from ..Mesh import Mesh

from glass.utils import checktype
from glass import Vertex

import glm


class Box(Mesh):

    @checktype
    def __init__(
        self,
        Lx: float = 1,
        Ly: float = None,
        Lz: float = None,
        color: (glm.vec3, glm.vec4) = glm.vec4(0.396, 0.74151, 0.69102, 1),
        back_color: (glm.vec3, glm.vec4) = None,
        normalize_tex_coord=True,
        name: str = "",
    ):
        Mesh.__init__(self, color=color, back_color=back_color, name=name, block=True)
        if Ly is None:
            Ly = Lx

        if Lz is None:
            Lz = Lx

        self.__Lx = Lx
        self.__Ly = Ly
        self.__Lz = Lz
        self.__normalize_tex_coord = normalize_tex_coord
        self.start_building()

    def build(self):
        self.is_closed = True
        self.self_calculated_normal = True

        vertices = self.vertices
        indices = self.indices

        Lx = self.__Lx
        Ly = self.__Ly
        Lz = self.__Lz
        normalize_tex_coord = self.__normalize_tex_coord

        # 左面
        position = glm.vec3(-Lx / 2, Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(0)
            if normalize_tex_coord
            else glm.vec3(0.5 - position.y, 0.5 + position.z, 0)
        )
        vertices[0] = Vertex(
            position=position, normal=glm.vec3(-1, 0, 0), tex_coord=tex_coord
        )

        position = glm.vec3(-Lx / 2, -Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(1, 0, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 - position.y, 0.5 + position.z, 0)
        )
        vertices[1] = Vertex(
            position=position, normal=glm.vec3(-1, 0, 0), tex_coord=tex_coord
        )

        position = glm.vec3(-Lx / 2, -Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(1, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 - position.y, 0.5 + position.z, 0)
        )
        vertices[2] = Vertex(
            position=position, normal=glm.vec3(-1, 0, 0), tex_coord=tex_coord
        )

        position = glm.vec3(-Lx / 2, Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(0, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 - position.y, 0.5 + position.z, 0)
        )
        vertices[3] = Vertex(
            position=position, normal=glm.vec3(-1, 0, 0), tex_coord=tex_coord
        )

        # 右面
        position = glm.vec3(Lx / 2, -Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.y, 0.5 + position.z, 0)
        )
        vertices[4] = Vertex(
            position=position, normal=glm.vec3(1, 0, 0), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(1, 0, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.y, 0.5 + position.z, 0)
        )
        vertices[5] = Vertex(
            position=position, normal=glm.vec3(1, 0, 0), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(1, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.y, 0.5 + position.z, 0)
        )
        vertices[6] = Vertex(
            position=position, normal=glm.vec3(1, 0, 0), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, -Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(0, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.y, 0.5 + position.z, 0)
        )
        vertices[7] = Vertex(
            position=position, normal=glm.vec3(1, 0, 0), tex_coord=tex_coord
        )

        # 后面
        position = glm.vec3(-Lx / 2, -Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 + position.z, 0)
        )
        vertices[8] = Vertex(
            position=position, normal=glm.vec3(0, -1, 0), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, -Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(1, 0, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 + position.z, 0)
        )
        vertices[9] = Vertex(
            position=position, normal=glm.vec3(0, -1, 0), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, -Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(1, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 + position.z, 0)
        )
        vertices[10] = Vertex(
            position=position, normal=glm.vec3(0, -1, 0), tex_coord=tex_coord
        )

        position = glm.vec3(-Lx / 2, -Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(0, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 + position.z, 0)
        )
        vertices[11] = Vertex(
            position=position, normal=glm.vec3(0, -1, 0), tex_coord=tex_coord
        )

        # 前面
        position = glm.vec3(Lx / 2, Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(0)
            if normalize_tex_coord
            else glm.vec3(0.5 - position.x, 0.5 + position.z, 0)
        )
        vertices[12] = Vertex(
            position=position, normal=glm.vec3(0, 1, 0), tex_coord=tex_coord
        )

        position = glm.vec3(-Lx / 2, Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(1, 0, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 - position.x, 0.5 + position.z, 0)
        )
        vertices[13] = Vertex(
            position=position, normal=glm.vec3(0, 1, 0), tex_coord=tex_coord
        )

        position = glm.vec3(-Lx / 2, Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(1, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 - position.x, 0.5 + position.z)
        )
        vertices[14] = Vertex(
            position=position, normal=glm.vec3(0, 1, 0), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(0, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 - position.x, 0.5 + position.z)
        )
        vertices[15] = Vertex(
            position=position, normal=glm.vec3(0, 1, 0), tex_coord=tex_coord
        )

        # 下面
        position = glm.vec3(-Lx / 2, Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 - position.y)
        )
        vertices[16] = Vertex(
            position=position, normal=glm.vec3(0, 0, -1), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(1, 0, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 - position.y)
        )
        vertices[17] = Vertex(
            position=position, normal=glm.vec3(0, 0, -1), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, -Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(1, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 - position.y)
        )
        vertices[18] = Vertex(
            position=position, normal=glm.vec3(0, 0, -1), tex_coord=tex_coord
        )

        position = glm.vec3(-Lx / 2, -Ly / 2, -Lz / 2)
        tex_coord = (
            glm.vec3(0, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 - position.y)
        )
        vertices[19] = Vertex(
            position=position, normal=glm.vec3(0, 0, -1), tex_coord=tex_coord
        )

        # 上面
        position = glm.vec3(-Lx / 2, -Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 + position.y)
        )
        vertices[20] = Vertex(
            position=position, normal=glm.vec3(0, 0, 1), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, -Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(1, 0, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 + position.y, 0)
        )
        vertices[21] = Vertex(
            position=position, normal=glm.vec3(0, 0, 1), tex_coord=tex_coord
        )

        position = glm.vec3(Lx / 2, Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(1, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 + position.y, 0)
        )
        vertices[22] = Vertex(
            position=position, normal=glm.vec3(0, 0, 1), tex_coord=tex_coord
        )

        position = glm.vec3(-Lx / 2, Ly / 2, Lz / 2)
        tex_coord = (
            glm.vec3(0, 1, 0)
            if normalize_tex_coord
            else glm.vec3(0.5 + position.x, 0.5 + position.y, 0)
        )
        vertices[23] = Vertex(
            position=position, normal=glm.vec3(0, 0, 1), tex_coord=tex_coord
        )

        # 左面
        indices[0] = glm.uvec3(0, 1, 2)
        indices[1] = glm.uvec3(0, 2, 3)

        # 右面
        indices[2] = 4 + glm.uvec3(0, 1, 2)
        indices[3] = 4 + glm.uvec3(0, 2, 3)

        # 后面
        indices[4] = 8 + glm.uvec3(0, 1, 2)
        indices[5] = 8 + glm.uvec3(0, 2, 3)

        # 前面
        indices[6] = 12 + glm.uvec3(0, 1, 2)
        indices[7] = 12 + glm.uvec3(0, 2, 3)

        # 下面
        indices[8] = 16 + glm.uvec3(0, 1, 2)
        indices[9] = 16 + glm.uvec3(0, 2, 3)

        # 上面
        indices[10] = 20 + glm.uvec3(0, 1, 2)
        indices[11] = 20 + glm.uvec3(0, 2, 3)

        del vertices[24:]
        del indices[12:]

        for index in indices:
            self.generate_temp_TBN(
                vertices[index[0]], vertices[index[1]], vertices[index[2]]
            )

    @property
    def Lx(self):
        return self.__Lx

    @Lx.setter
    @Mesh.param_setter
    def Lx(self, Lx: int):
        self.__Lx = Lx

    @property
    def Ly(self):
        return self.__Ly

    @Ly.setter
    @Mesh.param_setter
    def Ly(self, Ly: int):
        self.__Ly = Ly

    @property
    def Lz(self):
        return self.__Lz

    @Lz.setter
    @Mesh.param_setter
    def Lz(self, Lz: int):
        self.__Lz = Lz

    @property
    def normalize_tex_coord(self):
        return self.__normalize_tex_coord

    @normalize_tex_coord.setter
    @Mesh.param_setter
    def normalize_tex_coord(self, flag: bool):
        self.__normalize_tex_coord = flag
