#from __future__ import unicode_literals
# -*- coding: utf-8 -*-
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import regles
import AEtoile
import time, threading

class Action(object):
    """action effectuee par un combattant sur le plateau de jeu"""
    def __init__(self):
        self._num = None         #no du pion actif
        self._coordCible = None  #coord de la case ciblee par le curseur
        self._cible = None       #cible (case ou pion)
        self._sourceCurseur = ""
        self._nomBouton = ""     

    def typeAtt(self):
        return ""

    def activer(self, plateau, numPion):
        self.plateau = plateau
        self._num = numPion
        
        self.enfoncerBouton(True)
        self.activerCurseur()
        self.creerItemsGraphiques()

    def majCoordCible(self, coord):
        """met a jour les coordonnees de la cible,
            cad la case actuellement survolee par la souris"""
        if self.plateau.coordonneesValides(coord):
            self._coordCible = coord
            self.maj()

    def desactiver(self):
        self.afficherCibles(False)
        self.detruireItemsGraphiques()
        self.desactiverCurseur()
        self.enfoncerBouton(False)

    def valider(self):
        #envoyer signal
        self.envoiSignal()
        self.desactiver()

    def estValide(self):
        return True

    def maj(self):
        pass

    def acteur(self):
        return self.plateau.combattants[self._num]

    def coordActeur(self):
        return self.acteur().position

    def activerCurseur(self):
        if len(self._sourceCurseur) > 0:
            curseurPix = QPixmap(self._sourceCurseur)
            if not curseurPix.isNull():
                curseur = QCursor(curseurPix, 0, curseurPix.height())
                self.plateau.fenetre.ui.cbt_vue.setCursor(curseur)   

    def desactiverCurseur(self):
        self.plateau.fenetre.ui.cbt_vue.setCursor(QCursor(Qt.ArrowCursor))

    def enfoncerBouton(self, actif):
        for bouton in self.plateau.fenetre.ui.pi_actions.findChildren(QToolButton):
            if bouton.objectName() == self._nomBouton:
                bouton.setChecked(actif)

    #manipulation des items graphiques
    def creerItemsGraphiques(self):
        pass

    def majItemsGraphiques(self):
        pass    

    def detruireItemsGraphiques(self):
        pass

    #affichage des cibles
    def afficherCibles(self, actif):
        pass

    #envoi du signal en cas de validation
    def envoiSignal(self):
        pass

    def pivoter(self, modRotation):
        pass

class Deplacement(Action):
    ### a completer avec des icones de deplacement,
    #la prise en compte de la nage et de l'escalade
    #et le calcul du cout de deplacement
    def __init__(self):
        super(Deplacement, self).__init__()
        self._chemin = []  #liste des coord des cases a traverser
        self._chercheurChemin = None
        self._cout = 0     #cout en points de dep
        self.cible_aConfirmer = None
        self._sourceCurseur = ""
        self._nomBouton = "pi_deplacement" 


    def typeAtt(self):
        return "dep"
    
    def activer(self, plateau, numPion):
        super(Deplacement, self).activer(plateau, numPion)
        self.plateau.proj.creer(self.acteur())
        
    def desactiver(self):
        self.plateau.proj.desactiver()
        if self._chercheurChemin:
            self._chercheurChemin.arreter()
            self._chercheurChemin = None
        super(Deplacement, self).desactiver()

    def valider(self):
        if not self.cible_aConfirmer or self.cible_aConfirmer != self._coordCible:             
            self.cible_aConfirmer = self._coordCible
            self.creerChemin()
        else:
            if self.estValide() and self.plateau.proj.projectionValide():
                self.acteur().majPosition(self.plateau.proj.coord(), self.plateau.proj.nbRotations())
                super(Deplacement, self).valider()

    def estValide(self):
        return len(self._chemin)>0

    def majCoordCible(self, coord):
        if coord != self.coordActeur():
            super(Deplacement, self).majCoordCible(coord)

    def maj(self):
        self.plateau.proj.majCoord(self._coordCible)

    def pivoter(self, modRotation):
        self.plateau.proj.majRotation(modRotation)
            
    def creerChemin(self):
        self.afficherCibles(False)
        self._chemin = []
        self._cout = 0
        if self._chercheurChemin:
            self._chercheurChemin.arreter()
            self._chercheurChemin = None
        self._chercheurChemin = AEtoile.Chemin(self.plateau, self.coordActeur(), self._coordCible)
        self._chemin = self._chercheurChemin.liste()
        self.afficherCibles(True)        

    def afficherCibles(self, actif):
        for coord, cout in self._chemin:
            valide = True
            if actif:
                if cout > self.acteur().deplacement: valide = False
            else:
                cout = 0
            self.plateau.cases[coord].majAffichageDeplacement(cout, valide)

    def envoiSignal(self):
        cout = self._chemin[-1][1]  #cout de deplacement retenu pour la derniere case
        print "{} s'est deplacé et a utilisé {} points de mouvement".format(self.acteur().txtId(), cout)

class Attaque(Action):
    """attaque pre-parametree affectee a un pion, un personnage ou une creature"""
    def __init__(self):
        super(Attaque, self).__init__()
        self._nom = "Attaque"
        self._icone = ""
        self._portee = 1   #portee max en cases
        self._rayon = 0
        self._attributs = regles.listeAttributsAttaques()
        self._notes = ""

    def typeAtt(self):
        return "att"

    def nom(self):
        return self._nom

    def majNom(self, nom):
        if len(str(nom)) > 0:
            self._nom = nom

    def portee(self):
        return self._portee

    def majPortee(self, portee):
        try:
            ent = int(portee)
            if ent > 0:
                if ent >= 1000: ent = 999
                self._portee = ent
        except:
            pass

    def rayon(self):
        return self._rayon
    
    def majRayon(self, rayon):
        try:
            ent = int(rayon)
            if ent > 0:
                if ent >= 100: ent = 99
                self._rayon = ent
        except:
            pass

    def majAttribut(self, nom, nouvelleVal):
        if nom in self._attributs:
            if regles.attributAttaque(nom).controler(nouvelleVal):
                self._attributs[nom] = nouvelleVal

    def majAttributs(self, dicoAttributs):
        self._attributs = dicoAttributs
    
    def attributs(self):
        return self._attributs

    def notes(self):
        return self._notes

    def majNotes(self, notes):
        #on limite a 400 le nombre de caracteres
        notes = str(notes)
        self._notes = notes[0:400]

    def icone(self):
        return QIcon(self._icone)
 
class Cac(Attaque):
    """attaque au corps a corps"""
    def __init__(self):
        super(Cac, self).__init__()
        self._nom = "Attaque au corps-à-corps"
        self._pionCible = None
        self._sourceCurseur = ""
        self._nomBouton = "pi_attaqueCac"
        self._icone = "img\\curseurEpee.png"

    def typeAtt(self):
        return "cac"

    def desactiver(self):
        self.afficherCibles(False)
        super(Cac, self).desactiver()

    def valider(self):
        if self.estValide() and self._pionCible:
            super(Cac, self).valider()
      
    def maj(self):
        self.afficherCibles(False)
        pionCible = self.plateau.cases[self._coordCible].pionOccupant()
        if pionCible != None and pionCible != self.plateau.pionSelectionne():
            self._pionCible = pionCible
        else:
            self._pionCible = None
        self.afficherCibles(True)

    def estValide(self):
        return (self._coordCible in self.plateau.zone(self.plateau.pionSelectionne().position, self.portee, 0, False, True))

    def afficherCibles(self, actif):
        if self._pionCible:
            self._pionCible.estCibleAttaque(actif, self.estValide())

    def envoiSignal(self):
        print "{} a attaqué {} au corps-à-corps".format(self.acteur().txtId(), self._pionCible.txtId())

class Distance(Attaque):
    """attaque a distance"""
    def __init__(self):
        super(Distance, self).__init__()
        self._nom = "Attaque à distance"
        self._itemLigne = None
        self._pionCible = None
        self._sourceCurseur = ""
        self._nomBouton = "pi_attaqueDist"
        self._icone = "img\\curseurArc.png"

    def typeAtt(self):
        return "dist"

    def majCoordCible(self, coord):
        if self._pionCible:
            self._pionCible.estCibleAttaque(False, self.estValide())
        if self._coordCible in self.plateau.cases:    
            self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
        super(Distance, self).majCoordCible(coord)        

    def valider(self):
        if self.estValide() and self._pionCible != None:
            super(Distance, self).valider()

    def maj(self):
        """met a jour la ligne de mire representant l'attaque a distance"""
        self.afficherCibles(False)
        pionCible = self.plateau.cases[self._coordCible].pionOccupant()

        self.majItemsGraphiques()
        if pionCible != None and pionCible != self.plateau.pionSelectionne():
            self._pionCible = pionCible
        else:
            self._pionCible = None

        self.afficherCibles(True)

    def estValide(self):
        return self.plateau.estCibleAttaqueDistValide(self.plateau.pionSelectionne().position, self._coordCible, 0)

    def afficherCibles(self, actif):
        if self._pionCible:
            self._pionCible.estCibleAttaque(actif, self.estValide())
        else:
            #si pas de pion vise, on affiche la case cible comme visee
            self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, self.estValide())            

    def creerItemsGraphiques(self):
        self._itemLigne = QGraphicsLineItem()
        self._itemLigne.setZValue(100)
        pinceau = QPen()
        pinceau.setWidth(6)
        self._itemLigne.setPen(pinceau)
        self._itemLigne.prepareGeometryChange()
        self.plateau.addItem(self._itemLigne)

    def majItemsGraphiques(self):
        self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
                                       self.plateau.cases[self._coordCible].centreGraphique))

    def detruireItemsGraphiques(self):
        if self._itemLigne != None:
            self._itemLigne.prepareGeometryChange()
            self.plateau.removeItem(self._itemLigne)
            self._itemLigne = None

    def envoiSignal(self):
        print "{} a attaqué {} a distance".format(self.acteur().txtId(), self._pionCible.txtId())


class Zone(Attaque):
    """attaque de zone de base"""
    def __init__(self):
        super(Zone, self).__init__()    
        self._nom = "Attaque de zone"
        self._itemLigne = None
        self._itemCible = None
        self._casesCibles = []
        self._sourceCurseur = ""
        self._nomBouton = "pi_attaqueZone"
        self._icone = "img\\baguette.png"

    def typeAtt(self):
        return "zone"

    def valider(self):
        if self.estValide() and len(self._casesCibles) > 0:
            super(Zone, self).valider()

    def desactiver(self):
        self.afficherCibles(False)
        self.detruireItemsGraphiques()

    def maj(self):
        """maj la forme de l'attaque de zone et les items cibles"""
        self.afficherCibles(False)
        self.majItemsGraphiques()
        self.majCibles()
        self.afficherCibles(True)

    def majCibles(self):
        """met a jour la liste des cases cibles"""
        self._casesCibles = []
        if self.estValide():
            for coord in self.plateau.casesSousForme(self._itemCible, True, True):
                if coord!= None and coord != self.plateau.pionSelectionne().position:
                    self._casesCibles.append(coord)            

    def afficherCibles(self, actif):
        for coord in self._casesCibles:
            self.plateau.cases[coord].majEstCibleCurseur(actif)
        for numCombattant in self.plateau.pionsSurListeCase(self._casesCibles):
            self.plateau.combattants[numCombattant].estCibleAttaque(actif)    

    def creerItemsGraphiques(self):
        self._itemLigne = QGraphicsLineItem()
        self._itemLigne.setPen(QPen(QColor("black")))
        self._itemLigne.prepareGeometryChange()
        self.plateau.addItem(self._itemLigne)

        self._itemCible = QGraphicsEllipseItem()
        self._itemCible.setPen(QPen(QColor("black")))
        self._itemCible.prepareGeometryChange()
        self.plateau.addItem(self._itemCible)

    def detruireItemsGraphiques(self):
        if self._itemCible != None:
            self._itemCible.prepareGeometryChange()
            self.plateau.removeItem(self._itemCible)
            self._itemCible = None

        if self._itemLigne != None:
            self._itemLigne.prepareGeometryChange()
            self.plateau.removeItem(self._itemLigne)
            self._itemLigne = None

    def envoiSignal(self):
        touches = ""
        for num in self.plateau.pionsSurListeCase(self._casesCibles):
            touches += "{}, ".format(self.plateau.combattants[num].txtId())
        touches = touches[:-2]
        print "{} a lancé une attaque de zone. Les pions suivants sont touches: \n {}".format(self.acteur().txtId(), touches)


class Ligne(Zone):
    """attaque de zone de forme lineaire"""
    def __init__(self):
        super(Ligne, self).__init__()
        self._nom = "Attaque de zone: ligne"

    def typeAttZone(self):
        return "ligne"

    def majItemsGraphiques(self):
        self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
                                       self.plateau.cases[self._coordCible].centreGraphique))

    def majCibles(self):
        """met a jour la liste des cases cibles"""
        self._casesCibles = []
        if self.estValide():
            for coord in self.plateau.casesSousForme(self._itemLigne, True, True):
                if coord!= None and coord != self.plateau.pionSelectionne().position:
                    self._casesCibles.append(coord)  

    def estValide(self):
        retour = True
        for coord in self._casesCibles:
            if self.plateau.cases[coord].estObstacleVision():
                retour = False
                break
        return retour
            

class Disque(Zone):
    """attaque de zone de forme circulaire"""
    def __init__(self):
        super(Disque, self).__init__()
        self._nom = "Attaque de zone: disque"

    def typeAttZone(self):
        return "disque"

    def majCoordCible(self, coord):
        if self._coordCible in self.plateau.cases:    
            self.plateau.cases[self._coordCible].majEstCibleCurseur(False)
        super(Disque, self).majCoordCible(coord)    

    def majCibles(self):
        self._casesCibles = self.plateau.zone(self._coordCible, self.rayon, 0)

    def afficherCibles(self, actif):
        super(Disque, self).afficherCibles(actif)
        #si on affiche une attaque invalide
        if not self.estValide():
            self.plateau.cases[self._coordCible].majEstCibleCurseur(actif, False)

    def majItemsGraphiques(self):
        self._itemLigne.setLine(QLineF(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
                                       self.plateau.cases[self._coordCible].centreGraphique))
        if self.estValide():
            rect = self.rectEllipseCirculaire(self.plateau.cases[self._coordCible].centreGraphique, self.rayon)
            if rect != None:
                self._itemCible.setRect(rect)
            self._itemCible.setVisible(self.estValide() and rect != None)

    def estValide(self):
        return self.plateau.estCibleAttaqueDistValide(self.plateau.pionSelectionne().position, self._coordCible)

    def rectEllipseCirculaire(self, centre, rayon):
        """renvoie le QRectF definissant une ellipse ayant le QPointF pour centre et le rayon en cases entres en param
           attention: l'ellipse n'est pas tout a fait circulaire, elle couvre horizontalement et
           verticalement le nombre de cases demandees"""
        rect = None
        if rayon > 0:
            p1 = QPointF((centre.x() - (rayon*self.plateau.hCase)), (centre.y() - (rayon*self.plateau.hCase)))
            p2 = QPointF((centre.x() + (rayon*self.plateau.hCase)), (centre.y() + (rayon*self.plateau.hCase)))
            if p1 != p2:
                rect = QRectF()
                rect.setTopLeft(p1)
                rect.setBottomRight(p2)
        return rect


class Cone(Zone):
    """attaque de zone de forme conique"""
    def __init__(self):
        super(Cone, self).__init__()
        self._nom = "Attaque de zone: cône"

    def typeAttZone(self):
        return "cone"

    def creerItemsGraphiques(self):
        self._itemCible = QGraphicsPolygonItem()
        self._itemCible.setPen(QPen(QColor("black")))
        self._itemCible.prepareGeometryChange()
        self.plateau.addItem(self._itemCible)

    def majItemsGraphiques(self):        
        self._itemCible.setPolygon(self.polygoneCone(self.plateau.cases[self.plateau.pionSelectionne().position].centreGraphique, \
                                                     self.plateau.cases[self._coordCible].centreGraphique))


    def polygoneCone(self, point1, point2):
        """renvoie le polygone du cone defini par les deux points (origine, distance)"""
        ligne1 = QLineF(point1, point2)
        longueur = ligne1.length()
        ligne1.setAngle(ligne1.angle() + 22.5)
        ligne1.setLength(1.1547*longueur)
        ligne2 = QLineF(point1, point2)    
        ligne2.setAngle(ligne2.angle() - 22.5)
        ligne2.setLength(1.1547*longueur)
        polygone = QPolygonF()
        polygone.append(point1)
        polygone.append(ligne1.p2())
        polygone.append(ligne2.p2())
        return polygone












        

