from Outils.Moteur_de_jeu.Fenetre import *
from Outils.Moteur_de_jeu.Joueur import *
from random import randint

from time import *

import requests
import json




class Partie :   # Quentin 17/10/2016
    """
        Attributs :
            .joueurs : Joueur * Joueur
            .plateau : Plateau
            .tour : int
            .afficher : bool
            .cases_selectionnables : int * int liste
            .barrieres_selectionnables : Barriere liste
            .liste_coups_licites : Coup liste
            .etape : string
            .deroulement : Coup liste
            
        Méthodes :
            .joueur_actuel(self)
            .est_selectionnable(self, barriere)
            .executer_tour(self, coup)
            .tourner_jeu(self)
            .demarrer(self)
            .sauvegarder_deroulement(self, nom, gagnant)
    """

    DOSSIER_STANDARD = "PARTIES_A_TRAITER"    # Chemin privililégié pour enregistrer les fichiers
    
    def __init__(self, joueurA, joueurB, afficher, dossier_save = "", demander_nom = False) : # Quentin 13/10/2016
        """
            joueurA et joueurB : les deux participants
            afficher : booléen qui vaut true si une fenêtre doit s'afficher
            dossier_save : '' -> pas de sauvegarde
                           '*' -> sauvegarde sur jhub
                           chemin -> sauvegarde dans le dossier indiqué
        """
        # Pour se souvenir :
        self.joueurA = joueurA
        self.joueurB = joueurB
        
        # Attribut .joueurs
        if randint(0,1) == 1 : # Tirage au sort du joueur qui commence
            self.joueurs = (joueurA, joueurB)
            joueurA.num = 0
            joueurB.num = 1
        else :
            self.joueurs = (joueurB, joueurA)
            joueurB.num = 0
            joueurA.num = 1
        
        # Attribut .plateau ; correspond respectivement à x lignes, y colonnes et n barrières par joueur
        self.plateau = Plateau(9, 9, 10)
        

        # Attributs caractérisant l'affichage
        config = self.types_joueurs()
        self.afficher = afficher or config != "OO"      # L'affichage est nécessaire si un humain présent
        self.demander_nom = demander_nom and config != "OO"         # S'il n'y a pas d'humain, il ne faut pas demander les noms


        # Attribut caractérisant les items sélectionnables sur le plateau :
        if self.joueur_actuel().type == "H" :
                self.cases_selectionnables = self.plateau.cases_accessibles_joueur(0)
                self.barrieres_selectionnables = self.plateau.liste_barrieres_possibles()
        else :
            self.cases_selectionnables = []
            self.barrieres_selectionnables = []

        #Attribut permettant de controler à posteriori le choix de l'I.A.
        self.liste_coups_licites = self.plateau.liste_coups_possibles()

        # Attribut .etape
        self.etape = "J"
        """
            Quatre étapes possibles :
            - J : Pour l'humain : se déplacer sans gagner -> J
                                  se déplacer et atteindre la rangée opposée -> F
                                  choisir de poser une barrière -> B1
                  Pour l'ordinateur : attendre que l'utilisateur clique sur le bouton -> J

            - B1 : choisir le barycentre de la barrière -> B2 si on peut choisir l'orientation, J sinon
                   annuler -> J
            - B2 : choisir l'orientation de la barrière -> J
                   annuler -> B1
            - F : fin de la self
        """

        # Attributs d'enregistrement
        self.deroulement = []   # C'est une liste de Coups qu'il faut incrémenter à chaque action de joueur.
        self.dossier_save = dossier_save
        


    def joueur_actuel(self) :      # Quentin 09/2016
        """ Retourne le joueur dont c'est le tour. """
        return self.joueurs[self.plateau.tour]


    def types_joueurs(self) :
        """ Renvoie 'OH', 'OO', 'HO' ou 'HH' selon les types des joueurs """
        return self.joueurs[0].type + self.joueurs[1].type

            

    def est_selectionnable(self, barriere) :     # Quentin 04/10/2016
        """ Permet de savoir si une barrière est dans la liste des barrières sélectionnables """
        for b in self.barrieres_selectionnables :
            if b == barriere :
                return True
        return False



    def coup_IA(self) :      # Quentin 15/11/2016
        """ Retourne le coup calculé par l'I.A. """
        l = self.plateau.liste_coups_possibles()
        id_coup = ( Global.partie.joueur_actuel().calculer_coup(Global.partie.plateau.copie_complete(), l) ) % len(l)
        return l[id_coup]



    def executer_tour(self, coup) :     # Quentin 15/11/2016
        """
            Fonction utilisée lorsqu'il y a affichage.
            Applique un coup et fait la transition vers le tour suivant.
        """      
        
        self.plateau.executer_coup(coup)
        self.deroulement.append(coup)
        
        if self.plateau.gagnant() != -1 :    # Condition de victoire
            self.etape = "F"
            self.enregistrer_partie()
                
        else :
            self.etape = "J"
            if self.joueur_actuel().type == "H" :
                # Calcul des nouvelles cases et barrières :
                self.cases_selectionnables = self.plateau.cases_accessibles_joueur(self.plateau.tour)
                self.barrieres_selectionnables = self.plateau.liste_barrieres_possibles()
            else :
                if self.types_joueurs() == "OO" or self.affichage.var_bouton.get() == 1 :
                    self.cases_selectionnables = []
                    self.barrieres_selectionnables = []
                else :
                    # Exécution immédiate du tour de l'I.A.
                    self.affichage.rafraichissement(self)
                    self.executer_tour(self.coup_IA())




    def tourner_jeu(self) :     # Quentin 17/10/2016
        """
            Fonction utilisée lorsqu'il n'y a pas affichage.
            Applique les coups en boucle
            Retourne le gagnant
        """


        while self.plateau.gagnant() == -1 :  # Condition de victoire
            coup = self.coup_IA()
            self.plateau.executer_coup(coup)
            self.deroulement.append(coup)


        self.enregistrer_partie()
        return self.joueurs[1 - self.plateau.tour]

            



    def lancement(self) :  # Quentin 15/11/2016
        """ Lance la partie et retourne le gagnant dans le cadre d'un match d'I.A. """
        if self.afficher :
            self.affichage = Affichage(self.plateau, self.types_joueurs() in ("OH","HO"))
            
            if self.joueur_actuel().type == "O" and self.types_joueurs() in ("OH","HO") :
                self.executer_tour(self.coup_IA())

            self.affichage.rafraichissement(Global.partie)
            self.affichage.fenetre.mainloop()
        else :
            return self.tourner_jeu()



    def demarrer(self) :
        """ Demande de saisir les noms puis lance la partie """
        if self.demander_nom :
            saisie_noms(self)
        else :
            return self.lancement()



    def relancer(self) :        # Quentin 21/11/2016
        """
            Recrée une partie avec les mêmes joueurs et le même dossier de sauvegarde
        """
        return Partie(self.joueurs[0], self.joueurs[1], self.afficher, self.dossier_save, False)






    #############################
    # Sauvegarde de la partie : #
    #############################

    def obtenir_donnees(self) :
        """ Retourne un couple (nom, contenu). Nom n'est que le nom du fichier, le chemin est ajouté après """
        
        (year, month, day, hour, minute, second, weekday, yearday, daylight) = localtime(time())
        instant = "%02d-%02d-%04d %02dh%02dmin%02ds" % (day, month, year, hour, minute, second)
        nom = self.joueurs[0].nom + " VS " + self.joueurs[1].nom + " " + instant + ".txt"

        # En-tête :
        contenu = ["Joueur 1 : " + self.joueurs[0].nom + " /" + self.joueurs[0].type + "\nJoueur 2 : " + self.joueurs[1].nom + " /" + self.joueurs[1].type + "\n\n"]
        

        # Coups :
        for t in enumerate( self.deroulement ) :
            k, cp = t
            contenu.append( "Coup " + str(k + 1) + " : " + cp.get_code() + "\n" )

        # Gagnant :
        contenu.append("\nGagnant : joueur " + str(2 - self.plateau.tour))


        return (nom, contenu)



    def sauvegarde(self, nom, contenu) :
        """ Enregistre les données de la partie """
        
        nomEntier = self.dossier_save + "/" + nom
        try :
            flux = open(nomEntier, "w")
        except :
            print("Echec de l'enregistrement.")
            print(nomEntier)
            return

        for l in contenu :
            flux.write(l)

        flux.close()


    def enregistrer_partie(self) :
        if self.dossier_save != "" :
            (nom, contenu) = self.obtenir_donnees()
            self.sauvegarde(nom, contenu)