#pragma once

#include <iostream>
#include <initializer_list>

#include <glm/glm.hpp>

#include <uv.hpp>

namespace gb
{
class mesh_compute;

class Mesh
{
public:
    uv4 m_va, m_vb, m_vc;
    uv2 m_ta, m_tb, m_tc;
    uv4 m_na, m_nb, m_nc;

public:
    explicit Mesh(
            const uv4& va,
            const uv4& vb,
            const uv4& vc,
            const uv2& vta,
            const uv2& vtb,
            const uv2& vtc,
            const uv4& vna,
            const uv4& vnb,
            const uv4& vnc
            );

    mesh_compute apply(const glm::mat4& mat) const;

    // friend ::std::ostream& operator<<(::std::ostream& stream, const Mesh& mesh);
};

struct mesh_compute
{
private:
    // return value: 1 if z is greater than 0
    static inline int test_two_points(glm::vec4 e_start, glm::vec4 e_end, const glm::vec4& p)
    {
        glm::vec3 edge = e_start - e_end;
        edge.z = 0;
        glm::vec3 v = e_start - p;
        v.z = 0;
        return glm::cross(edge, v).z > 0;
    }

public:
    glm::vec4 m_va, m_vb, m_vc;
    glm::vec2 m_ta, m_tb, m_tc;
    glm::vec4 m_na, m_nb, m_nc;

    // return value: 1 if colored, 0 if empty
    inline int sample(const glm::vec4& p) const
    {
        int sign = test_two_points(m_va, m_vb, p);
        if (test_two_points(m_vb, m_vc, p) != sign) {
            return 0;
        }
        if (test_two_points(m_vc, m_va, p) != sign) {
            return 0;
        }
        return 1;
    }
};
}
