'''
module: facette
description: gestion des facettes du rubikCube, de leur mouvement et de leur actualisation graphique
'''
from coords import Coords

class Facette:
    # représente une facette
    RELATIVE_COORDS = {
        "U":((-1,-1,1), (1,-1,1), (1,1,1)),
        "D":((-1,-1,-1), (-1, 1, -1), (1, 1, -1)),
        "F": ((1, -1, -1), (1, 1, -1), (1, 1, 1)),
        "B": ((-1, -1, -1), (-1, -1, 1), (-1, 1, 1)),
        "L": ((-1, -1, -1), (1, -1, -1), (1, -1, 1)),
        "R": ((1, 1, -1), (-1, 1, -1), (-1, 1, 1))
    }



    def __init__(self, color, face, parent, size, canvas):
        '''
        color: un code de couleur accepté par TkInter
        face: parmi UDFBLR, indique l'orientation de la face
        A, B, C: trois Coords représentant 3 sommets de la facette
        parent: Cube parent
        size: taille en pixels d'une facette
        canvas: zone de dessin
        '''
        assert face in self.RELATIVE_COORDS
        rcA, rcB, rcC = self.RELATIVE_COORDS[face]

        centre = Coords(parent.x, parent.y, parent.z) * size
        self.__A = centre + Coords(*rcA) * (size/2)
        self.__B = centre + Coords(*rcB) * (size/2)
        self.__C = centre + Coords(*rcC) * (size/2)
        # A, B, C sont les positions quand le cube à terminer un mouvement et qu'il est aligné
        # pour gérer l'animation en évitant les problèmes liés à des cumuls d'approximations,
        # on prévoit des coordonnées supplémentaires qui sont les coordonnées en cours de mouvement

        self.__rA = self.__A
        self.__rB = self.__B
        self.__rC = self.__C

        self.__color = color
        self.__canvas = canvas
        self.__polygon_id = None # polygon tkinter

        self.__x_offset = canvas.winfo_reqwidth()/2
        self.__y_offset = canvas.winfo_reqheight()/2

    @property
    def face(self):
        '''
        renvoie l'orientation courante de la face
        '''
        n = self.n
        if n.z >= 1:
            return 'U'
        if n.z <= -1:
            return 'D'
        if n.x >= 1:
            return 'F'
        if n.x <= -1:
            return 'B'
        if n.y >= 1:
            return 'R'
        if n.y <= -1:
            return 'L'
        return ''

    @property
    def color(self):
        # Accesseur attribut color
        return self.__color

    @property
    def n(self):
        '''
        renvoie un vecteur normal sortant de la face
        '''
        return (self.__rB - self.__rA) * (self.__rC - self.__rB)

    def update(self):
        '''
        actualisation graphique
        '''
        if self.__polygon_id != None:
            # effacer
            self.__canvas.delete(self.__polygon_id)
            self.__polygon_id = None
        if self.visible():
            # tracer nouveau polygone
            x0, y0, x1, y1, x2, y2, x3, y3 = self.screen_coords()
            self.__polygon_id = self.__canvas.create_polygon(x0, y0, x1, y1, x2, y2, x3, y3, fill=self.__color, width=2, outline='black')

    def rotate(self, n, deg_angle):
        '''
        mise à jour de la position des points définissant la position de la facette
        selon un vecteur de rotation et un angle en degrés, calculés par rapport
        à la dernière position alignée
        '''
        self.__rA = self.__A.rotate(n, deg_angle)
        self.__rB = self.__B.rotate(n, deg_angle)
        self.__rC = self.__C.rotate(n, deg_angle)

    def align(self):
        '''
        Quand le cube est déclaré aligné, les positions de références
        s'harmonisent avec la position courante de la facette
        '''
        self.__A = self.__rA
        self.__B = self.__rB
        self.__C = self.__rC

    @property
    def __D(self):
        '''
        calcule D pour que ABCD soit un parallélogramme
        '''
        return self.__C + self.__A - self.__B

    @property
    def __rD(self):
        '''
        calcule rD pour que ABCD soit un parallélogramme
        '''
        return self.__rC + self.__rA - self.__rB

    def visible(self):
        '''
        renvoie True si la facette est visible
        La facette est visible si le vecteur normal à ABC, dans ce sens
        scalaire (1,1,1) (vecteurs sortant de l'écran suivant la perspective) est > 0
        '''
        return self.n.scalaire_xyz(1, 1, 1) > 0

    def screen_coords(self):
        '''
        renvoie les coordonnées des 4 points pour une représentation écran,
        tenant compte d'un décalage (offset)
        '''
        x_offset = self.__x_offset
        y_offset = self.__y_offset
        xA, yA = self.__rA.iso
        xB, yB = self.__rB.iso
        xC, yC = self.__rC.iso
        xD, yD = self.__rD.iso
        return xA + x_offset, yA + y_offset, xB + x_offset, yB + y_offset, xC + x_offset, yC +y_offset, xD + x_offset, yD + y_offset

