from __future__ import unicode_literals
# -*- coding: utf-8 -*-
import os
from sys import exit, argv
from time import time, sleep
from threading import Thread
from socket import socket, AF_INET, SOCK_STREAM
from subprocess import Popen, PIPE
import logging
import cPickle as pickle

#modules importes
from psutil import process_iter

#import de QT et des interfaces
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import QtOpenGL
#from PyQt4 import QtCore, QtGui
from ecran_connexion import Ui_ecranConnexion
from ecran_principal import Ui_principal
from ecran_chatPrive import Ui_chatPrive
from visionneuse import Ui_visionneuse

#modules persos
from serveur import Serveur, ServeurVoc
from lancer import jet
from clientvoc import ClientVoc

#fonctions potentiellement utiles:
  #print(psutil.connections())
  #print(psutil.net_io_counters(pernic=True))

#gestion des erreurs et log
logging.basicConfig(level=logging.DEBUG)
logProg = logging.getLogger(__name__)
handlerProg = logging.FileHandler('prog.log')
handlerProg.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s- %(message)s'))  #'%(name)s' nom du thread
logProg.addHandler(handlerProg)
logProg.debug("    ----------------------    \n")



def ipValide(addr):
    """controle la validite d'une adresse ip"""
    #if addr == "localhost":
    #    retour = addr
    #else:    
    #   try:
    #      socket.inet_aton(addr)
    #      retour = True
       #except socket.error:
    #   except:   
    #      retour = False
    retour = True
    return retour  


class EcranConnexion(QGroupBox):
    """fenetre de connexion a l'application et module d'envoi/reception"""
    def __init__(self, parent=None):
        """initialisation de la connexion et creation de la fenetre"""
        super (EcranConnexion, self).__init__(parent)        
        self.client_connecte = False
        self.serveur_connecte = False
        self.idServeur = ""
        self.idClient = "00"
        self.ip = ""
        self.pseudo = ""
        self.autresCo = {}

        #liste des chat prives ouverts avec les autres clients
        self.chatPrive = {}
        
        #echanges fichiers
        self.eFichier = {"id": "00", "chemin": "", "fichier": None, "dest": "", "envoi" : False, "annule" : False, "invisible": False}
                           #fichier en cours d'envoi : id fichier, chemin du fichier, fichier (objet), dest, envoi autorise, envoi annule
        self.destFichier = {}   #liste des clients dont on attend confirmation pour l'envoi de fichier
        self.rFichier = {} #liste des fichiers recus ou en cours de reception
                           #(id fichier: dictionnaire des infos du fichier [nom, taille (en o), recu (en o), ligne du tableau d'affichage])
        self.repReceptionFichiers = os.getcwd()+"\\FichiersRecus\\"
        
        #chat voc
        self.ipServeurVoc = ""
        self.port = 6660

        #recup des param et affichage:
        try:
            logProg.info(self.recupParamCo())
        except:
            logProg.info("pas de parametres a recuperer")
        self.createWidgets()

    def createWidgets(self):
        """creation de l'interface de connexion"""
        self.ui = Ui_ecranConnexion()
        self.ui.setupUi(self)
        if len(self.ip) > 0:
            self.ui.in_ip.setText(QString.fromUtf8(self.ip))
        if self.port > 0:
            self.ui.in_port.setText(QString.fromUtf8(str(self.port)))
        if len(self.pseudo) > 0:
            self.ui.in_pseudo.setText(QString.fromUtf8(self.pseudo))
            
        self.connect(self.ui.fermer, SIGNAL("clicked()"), self.fermer)
        self.connect(self.ui.creerServeur, SIGNAL("clicked()"), self.creerServeur)
        self.connect(self.ui.seConnecter, SIGNAL("clicked()"), self.seConnecter)

    def msg(self, txt):
        """affichage d'un message informatif sous forme de label"""
        self.ui.txt_msg.setText(QString.fromUtf8(txt))
        QApplication.processEvents()

    def creerServeur(self):
        """instancie un serveur local"""
        self.pseudo = self.ui.in_pseudo.text()
        self.port = self.ui.in_port.text()        
        if len(self.pseudo) == 0 or len(self.port) == 0:
            self.msg("Parametres incorrects")
        else:    
            self.ui.in_ip.setText(QString.fromUtf8("localhost"))
            self.s = Serveur(int(self.ui.in_port.text()))
            self.serveur_connecte, txt = self.s.creer()
            self.msg(txt)
            if self.serveur_connecte:
               self.seConnecter()

    def seConnecter(self):
        """se connecte au serveur correspondant a l'ip et au port saisis"""
        self.pseudo = self.ui.in_pseudo.text()
        self.port = self.ui.in_port.text()
        self.ip = self.ui.in_ip.text()
        essais = 0
        if len(self.pseudo) == 0 or not ipValide(self.ip) or len(self.port) == 0:
            self.msg("Parametres incorrects")
        else:    
            self.msg("En attente du serveur...")    
            while self.client_connecte == False:
            #en attente de la connexion    
                try:
                   self.cnn = socket(AF_INET, SOCK_STREAM)
                   self.cnn.connect((self.ip, int(self.port)))
                   self.client_connecte = True
                   txt = "Connexion etablie avec le serveur sur le port {}\n".format(self.port)
                   logProg.info(txt)
                except KeyboardInterrupt:
                   break
                except:
                   essais += 1
                   if essais > 3:
                       txt = "Delai depasse"
                       self.msg(txt)
                       logProg.warning(txt)
                       break
                   txt = "Connexion : essai {}".format(essais) 
                   self.msg(txt)
                   logProg.info(txt)

        if self.client_connecte:
            #demarre le fil de reception
            Thread(None, self.filReception, None, (), {}).start()
            #previent le serveur et envoie le pseudo
            self.envoi("ci", "sa", self.pseudo)
            self.msg(txt)
            sleep(0.01)
            self.close()
        else:
            txt = "Erreur: impossible de se connecter"
            self.msg(txt)
            logProg.error(txt)
    
    def filReception(self):
        """thread de reception des donnees du serveur, reste actif tant que l'application est active"""
        while self.client_connecte:
           recu = self.cnn.recv(1024)
           if len(recu) > 0:
               self.traitement(recu)
        
    def traitement(self, msg):
        """determine le traitement a apporter a un message recu, selon sa nature"""
        if len(msg) >= 6:        
            emet = msg[2:4]
            dest = msg[4:6]
            categorie = msg[:1]
            nature = msg[:2]
            try:
               contenu = msg[6:]
            except:
               contenu = "" 

            if nature != "fd" and nature != "ff":
                #on decode le message, sauf s'il contient des donnees binaires issues d'un fichier
                contenu = contenu.decode('utf-8')
            
            if nature == "ci":
                #recoit l'identifiant du client fourni par le serveur
                self.idClient = dest
                logProg.info("mon id est: {}\n".format(self.idClient))
                
            elif nature == "cc":
                #un autre client se connecte
                if contenu[0:2] != self.idClient:
                    self.autresCo[str(contenu[0:2])] = str(contenu[2:])
                    #on lui envoie notre id+x+pseudo (x=c si on est client simple, s si on est serveur)
                    sleep(0.02)
                    if self.serveur_connecte:
                        code = "s"
                    else:
                        code = "c"
                    self.envoi("cp", contenu[0:2], "{}{}{}".format(self.idClient, code, self.pseudo))
                    logProg.info("{} s'est connecte ({})".format(contenu[2:], contenu[0:2]))
                    self.recuInfo("cc", "{} s'est connecte ({})".format(contenu[2:], contenu[0:2]))
                    self.emit(SIGNAL("majAffichageLstClient()"))

            elif nature == "cp":
                #ce client est deja present
                idClient = str(contenu[0:2])
                self.autresCo[idClient] = str(contenu[3:])
                if str(contenu[2:3]) == "s":
                    self.idServeur = idClient
                sleep(0.001)
                logProg.info("{} est deja present [{}]".format(str(contenu[3:]), idClient))
                self.emit(SIGNAL("majAffichageLstClient()"))

            elif nature == "cd":
                #un client se deconnecte
                if contenu != self.idClient and len(contenu) == 2:
                    logProg.info("{} s'est deconnecte ({})".format(self.autresCo[contenu], contenu))
                    self.recuInfo("cd", "{} s'est deconnecte ({})".format(self.autresCo[contenu], contenu))
                    if contenu in self.chatPrive:
                         self.chatPrive[contenu].close()
                         del self.chatPrive[contenu]

                    del self.autresCo[contenu]
                    sleep(0.001)
                    self.emit(SIGNAL("majAffichageLstClient()"))
                    
            elif categorie == "m":
                if nature == "m ":
                    #afficher dans le chat publique
                    logProg.info("chat: {} -> {}\n".format(emet, contenu))
                    self.recuMsg(emet, contenu)
                    
                elif nature == "mp":
                    #message pour le chat prive
                    self.emit(SIGNAL("chatPrive(QString, QString,QString)"), QString.fromUtf8(emet), QString.fromUtf8(contenu), QString.fromUtf8(""))

                elif nature == "md":
                    #jet de des pour le chat prive
                    self.emit(SIGNAL("chatPrive(QString, QString,QString)"), QString.fromUtf8(emet), QString.fromUtf8(contenu), QString.fromUtf8("red"))
   
            elif categorie == "i":
                #afficher dans la fenetre évènement
                self.recuInfo(nature, contenu)
                if nature == "id":
                    #jet de dés: afficher en rouge
                    logProg.info("jet de dé: {} -> {}\n".format(emet, contenu))
                elif nature == "ic":
                    #nouveau client connecte: afficher en bleu
                    logProg.info("info connexion: {} -> {}\n".format(emet, contenu))
                    
            elif categorie == "f":
                #envoi ou reception de fichier
                if nature == "f0":
                    #le serveur nous renvoie l'identifiant du fichier que l'on veut envoyer
                    if self.eFichier["id"] == "00":
                       self.eFichier["id"] = contenu
                    else:
                       logProg.warning("Un fichier est deja en cours d'envoi\n")
                       
                elif nature == "fp":
                    #un clients est pret a recevoir le fichier
                    self.pretEnvoiFichier(emet)

                elif nature == "fi":
                    #quelqu'un nous envoie un fichier
                    try:
                       if len(contenu)>2:
                          #les 2 premiers car sont l'identifiant, puis le nom/taille du fichier (taille.nom)
                          try:
                             taille = int(contenu[2:].split(".",1)[0]) #on coupe seulement suivant le premier point 
                             nom_recu = contenu[2:].split(".",1)[1]
                          except:
                             logProg.error("impossible de lire la taille du nouveau fichier: {}".format(contenu[2:]))
                             taille = 0
                             nom_recu = contenu[2:]
                          
                          #on determine le nom qu'aura le fichier recu (au cas ou un fichier portant ce nom existe deja)   
                          essai = self.nouveauFichier(contenu[0:2], nom_recu, taille)
                          logProg.info("Creation d'un nouveau fichier: {}".format(essai))
                          if len(essai) > 0:
                              if dest == self.idClient:
                                  #si le fichier n'est destine qu'a nous, on affiche aussi le msg dans la fenetre de chat prive
                                  txt = "{} vous envoie {} ({} ko)".format(emet, nom_recu, int(taille/1000))
                                  self.emit(SIGNAL("chatPrive(QString, QString, QString)"), QString.fromUtf8(emet), QString.fromUtf8(txt), QString.fromUtf8("blue"))
                              self.recuInfo(nature, "Fichier {} en cours de reception ({} ko)".format(nom_recu, int(taille/1000)))
                              #on envoie confirmation de la reception:
                              sleep(0.001)
                              self.envoi("fp", emet, contenu[0:2])
                              self.emit(SIGNAL("majAffichageRecFichier(QString)"), QString.fromUtf8(contenu[0:2]))
                          else:
                              self.recuInfo(nature, "Impossible de créer le fichier à recevoir")
                              logProg.error("Impossible de créer le fichier à recevoir")
                       else:
                          logProg.error("erreur reception fichier: id ou nom du fichier incorrect\n") 
                    except:
                        #erreur de reception
                        logProg.error("erreur de reception des donnees du fichier\n")
                        self.envoi("fe", emet, contenu[0:2])
                        
                elif nature == "fd":
                    #on recoit les donnees a ecrire dans le fichier
                    try:
                       if len(contenu) > 2:
                           if not self.rFichier[contenu[0:2]]["annule"]:
                              self.rFichier[contenu[0:2]]["fichier"].write(contenu[2:])
                              self.rFichier[contenu[0:2]]["recu"] += len(contenu[2:])
                              try:
                                 taux = int(100*self.rFichier[contenu[0:2]]["recu"] / self.rFichier[contenu[0:2]]["taille"])
                              except:
                                 taux = "." 
                              self.emit(SIGNAL("majAffichageRecFichier(QString)"), QString.fromUtf8(contenu[0:2]))
                        
                              #le client renvoie la longueur de la donnee recue a l'emetteur pour confirmation
                              sleep(0.001)
                              self.envoi("fp", emet, contenu[0:2])
                       elif len(contenu) == 2:
                           #l'emetteur redemande confirmation, on lui envoie
                           if not self.rFichier[contenu[0:2]]["annule"]:
                              self.envoi("fp", emet, contenu[0:2])
                       else:
                           #erreur de reception, on annule la reception et on le signale
                           logProg.error("erreur de reception des donnees du fichier\n")
                           self.rFichier[contenu[0:2]]["annule"] = True
                           self.envoi("fe", emet, contenu[0:2])
                    except:
                        #erreur de reception, on annule la reception et on le signale
                        logProg.error("erreur de reception des donnees du fichier\n")
                        self.rFichier[contenu[0:2]]["annule"] = True
                        self.envoi("fe", emet, contenu[0:2])
                        
                        
                elif nature == "ff":
                    #fin de reception du fichier
                    try:
                       self.rFichier[contenu[0:2]]["fichier"].write(contenu[2:])
                       sleep(0.001)
                       self.envoi("fp", emet, contenu[0:2])                    
                       sleep(0.01)
                       self.rFichier[contenu[0:2]]["fichier"].close()
                       self.rFichier[contenu[0:2]]["termine"] = True
                    except:
                        #erreur de reception, on annule la reception et on le signale
                        logProg.error("erreur de reception des donnees du fichier\n")
                        self.rFichier[contenu[0:2]]["annule"] = True
                        self.envoi("fe", emet, contenu[0:2])
                        
                    if self.rFichier[contenu[0:2]]["termine"]:    
                        self.emit(SIGNAL("majAffichageRecFichier(QString)"), QString.fromUtf8(contenu[0:2]))
                        self.emit(SIGNAL("imageRecue(QString)"), QString.fromUtf8(contenu[0:2]))
                        self.recuInfo("ff", "Fichier {} recu\n".format(self.rFichier[contenu[0:2]]["nomOriginal"]))
                        if dest == self.idClient:
                             #si le fichier n'est destine qu'a nous, on affiche aussi le msg dans la fenetre de chat prive
                             txt = "Fichier {} bien recu".format(self.rFichier[contenu[0:2]]["nomOriginal"])
                             self.emit(SIGNAL("chatPrive(QString, QString, QString)"), QString.fromUtf8(emet), QString.fromUtf8(txt), QString.fromUtf8("blue"))
                        logProg.info("Fichier recu")
                    
                elif nature == "fa":
                    #envoi annule
                    logProg.info("Annulation de la reception du fichier")
                    if self.rFichier[contenu[0:2]]:
                       self.rFichier[contenu[0:2]]["annule"] = True 
                       self.recuInfo("ff", "Reception {} annule \n".format(self.rFichier[contenu[0:2]]["nom"]))
                       if dest == self.idClient:
                           #si le fichier n'est destine qu'a nous, on affiche aussi le msg dans la fenetre de chat prive
                           txt = "Transfert du fichier {} annule".format(self.rFichier[contenu[0:2]]["nomOriginal"])
                           self.emit(SIGNAL("chatPrive(QString, QString, QString)"), QString.fromUtf8(emet), QString.fromUtf8(txt), QString.fromUtf8("blue")) 
                       self.emit(SIGNAL("majAffichageRecFichier(QString)"), QString.fromUtf8(contenu[0:2]))
                       sleep(0.01)
                       self.rFichier[contenu[0:2]]["fichier"].close()                                 
                       #on supprime le fichier incomplet:
                       essais = 0
                       while essais < 100:
                           try:
                              os.remove(self.rFichier[contenu[0:2]]["fichier"].name)
                              break
                           except:
                              essais += 1
                       if essais ==  100:
                           logProg.error("Possible erreur de suppression du fichier temporaire")
                       del self.rFichier[contenu[0:2]]
                       
                elif nature == "fe":
                    #le destinataire du fichier signale une erreur de reception
                    self.recuInfo("fe", "{}: erreur de reception du fichier, l'envoi est annule \n".format(emet))
                    self.annuleEnvoiFichier()

                    
            elif categorie == "s":
                #infos sur le fonctionnement du serveur principal
                if nature == "sd":
                    #le serveur a ete ferme
                    self.serveurDeco()
                    
            elif categorie == "v":
                #infos liees au chat vocal
                if nature == "vs":
                    #un serveur vocal a ete cree
                    self.recuInfo("vs", "{} a cree un serveur vocal ({})".format(self.autresCo[emet], contenu))
                    self.ipServeurVoc = contenu
                    
                if nature == "vi":
                    #un client rejoint le chat vocal
                    self.recuInfo("vi", "{} a rejoint le chat vocal".format(self.autresCo[emet]))

                if nature == "vq":
                    #un client quitte le chat vocal
                    self.recuInfo("vq", "{} a quitte le chat vocal".format(self.autresCo[emet]))

                if nature == "vf":
                    #fermeture du serveur vocal
                    self.recuInfo("vf", "{} a ferme le serveur vocal".format(self.autresCo[emet]))
                    
            elif categorie == "p":
                if nature == "pi":
                    #nouveau plateau créé
                    logProg.info("nouveau plateau: {}\n".format(emet, contenu))
        else:
            logProg.warning("Erreur: message illisible -> {}\n".format(msg))


    def recuInfo(self, nature, contenu):
        """signale une nouvelle information"""
        self.emit(SIGNAL("nouvelleInfo(QString, QString)"), QString.fromUtf8(nature), QString.fromUtf8(contenu))

    def recuMsg(self, emetteur, contenu):
        """signale un nouveau message texte pour le chat ecrit"""
        self.emit(SIGNAL("msgChat(QString, QString)"), QString.fromUtf8(emetteur), QString.fromUtf8(contenu))
        
    def envoi(self, nature, dest, msg, idFichier = ""):
        """envoie un message au serveur TCP
           - longueur du message (3 car)
           - nature du message (2 car)
           - exp: id de l'expediteur (2 car)
           - dest: id du destinataire (2 car)
           - msg: contenu du message  (999 car max)
           - un identifiant pour le fichier le cas echeant"""
        
        exp = self.idClient
        if self.client_connecte:
            try:
               if len(msg) <= 999:
                  if len(idFichier) == 0:
                     msg = unicode(msg)   
                     lg = "%003.f"%len(msg.encode('utf-8')) #la longueur apres encodage peut changer
                     txt = "{}{}{}{}{}".format(lg, nature, exp, dest, msg)
                     txt = txt.encode('utf-8')
                  else:
                     lg = "%003.f"%(len(msg)+2)
                     txt = "{}{}{}{}{}".format(lg, nature, exp, dest, idFichier)
                     txt = txt.encode('utf-8') + msg
                  
                  retour = len(txt)
                  self.cnn.sendall(txt)
   
               else:
                  self.recuInfo("  ","999 caracteres au max.")
                  retour = 0
                  
            except:
                retour = 0
                logProg.warning("Envoi impossible")
        else:
            retour = ""
            logProg.warning("Le client n'est pas connecte au serveur")
            self.recuInfo("  ","Vous n'etes pas connecte a un serveur")
     
        return retour

    def envoiFichier(self, chemin, dest = "ac"):
        """intialise l'envoi d'un fichier"""
        if self.eFichier["id"] == "00":
           # on verifie si le fichier existe:
           fichier = None
           
           try:
               fichier = open(chemin, "rb")
           except:
               logProg.error("Le fichier '{}' est introuvable.".format(fichier))

           if not os.path.getsize(chemin) > 0:
               logProg.error("Envoi impossible - fichier vide")
               fichier.close()
               fichier = None
              
           if fichier:
               #on demande un identifiant au serveur
               self.eFichier["fichier"] = fichier
               self.eFichier["chemin"] = chemin
               self.eFichier["dest"] = dest
               self.eFichier["annule"] = False
               self.emit(SIGNAL("initEnvFichier(QString, QString)"), QString.fromUtf8(os.path.basename(chemin)), QString.fromUtf8("0"))
               logProg.debug(self.eFichier)
               if dest == "ac":
                   for idC in self.autresCo:
                       self.destFichier[idC] = False
               else:
                   self.destFichier[dest] = False
               #on demande un identifiant au serveur    
               self.envoi("f0","sa","")
               Thread(None, self.envoiFichier_fil, None, (), {}).start()               
                 
        else:
           self.recuInfo("fi", "Impossible d'envoyer le fichier, un fichier est peut-etre deja en cours d'envoi")
          

    def envoiFichier_fil(self):
        """le fichier est pret a etre envoye, on attend confirmation des destinataires"""
        #on attend que l'id du fichier soit mis a jour
        essais = 0
        while self.eFichier["id"]=="00" and essais < 3000:
           sleep(0.001)
           essais += 1
           
        if len(self.eFichier["id"]) == 2 and self.eFichier["id"] != "00": 
           idFichier = self.eFichier["id"]
           dest = self.eFichier["dest"]
           nomFichier = os.path.basename(self.eFichier["chemin"])
           taille = os.path.getsize(self.eFichier["chemin"])
           logProg.debug("{} a pour id {}\n".format(nomFichier, idFichier))

           #on previent les destinataires, et on leur transmet l'identifiant et taille.nom du fichier (taille au format numerique, en octets)
           logProg.info("En attente des destinataires...")
           self.recuInfo("fi", "{} - En attente des destinataires...".format(nomFichier))
           self.envoi("fi", dest, "{}{}.{}".format(idFichier, taille, nomFichier))

           essais = 0
           while not self.eFichier["envoi"] and not self.eFichier["annule"]:
              sleep(0.001)
              essais += 1
              if essais >= 3000:
                  logProg.error("Pas de reponse des destinataires - envoi avorte")
                  self.eFichier["annule"] = True

              
           if not self.eFichier["annule"]:
              #on a recu confirmation de la part des destinataires 
              envoye = 0
              essais = 0
            
              #on lit un premier paquet de donnees
              data = self.eFichier["fichier"].read(512)
              
              while len(data) == 512 and not self.eFichier["annule"]:           
                  #on reinitialise le controle de reception pour le prochain paquet:
                  self.eFichier["envoi"] = False
                  if dest == "ac":
                     for idC in self.autresCo:
                         self.destFichier[idC] = False
                  else:
                     self.destFichier[dest] = False

                  #on envoie le paquet precedent, que les destinataires ont confirme pouvoir recevoir
                  self.envoi("fd", dest, data, idFichier)
                  envoye += len(data)
                  taux = str((100*envoye)/taille)
                  self.emit(SIGNAL("initEnvFichier(QString, QString)"), QString.fromUtf8(""), QString.fromUtf8(taux))
                  
                  #logProg.info("{} / {}".format(int(envoye/1000), int(taille/1000))) #attention: ralentit enormement l'envoi

                  #on attend que les clients confirment reception pour envoyer le prochain
                  essais = 0
                  while not self.eFichier["envoi"]:
                      if self.eFichier["annule"]:
                          break
                      sleep(0.001)
                      essais += 1
                      if essais >= 500:
                          #on renvoie un message toutes les demi-secondes pour redemander confirmation 
                          self.envoi("fd", dest, b'', idFichier)
                          essais = 0
   
                  #on lit le paquet suivant             
                  data = self.eFichier["fichier"].read(512)

              #FIN DE LA BOUCLE, on a envoye tous les paquets de 512o, il reste donc un dernier paquet a envoyer    

              #pour dernier paquet on ajoute au drapeau: "%003.f"%len(paquet)   
              #on signale que c'est le dernier paquet et on ajoute 3 caracteres pour en specifier la taille:
                  
              #ENVOI DU DERNIER PAQUET: 
              if not self.eFichier["annule"]:
                  
                  #on reinitialise le controle de reception pour le prochain paquet:
                  self.eFichier["envoi"] = False
                  if dest == "ac":
                     for idC in self.autresCo:
                         self.destFichier[idC] = False
                  else:
                     self.destFichier[dest] = False
                     
                  #on envoie le paquet precedent, que les destinataires ont confirme pouvoir recevoir   
                  self.envoi("ff", dest, data, idFichier)
                  envoye += len(data)
                  taux = str((100*envoye)/taille)
                  self.emit(SIGNAL("initEnvFichier(QString, QString)"), QString.fromUtf8(""), QString.fromUtf8(taux))                  

                  #on attend que les clients confirment reception pour envoyer le signal de fin
                  essais = 0
                  while not self.eFichier["envoi"]:
                      if self.eFichier["annule"]:
                          break
                      sleep(0.001)
                      essais += 1
                      if essais >= 500:
                          #on renvoie un message pour redemander confirmation
                          logProg.warning("envoi fichier - on redemande confirmation")
                          self.envoi("fd", dest, b'', idFichier)
                          essais = 0
                  #on signale au serveur qu'il peut liberer l'id du fichier 
                  self.envoi("f1", "sa", "{}".format(idFichier))
                  self.recuInfo("ff", "- {} a bien ete envoye -".format(nomFichier))
                  logProg.info("\n- Fichier envoye -")
 
           else:
              logProg.error("Erreur envoi fichier: signal serveur non-recu -> {}".format(self.eFichier["id"]))
              
        else:
           logProg.error("Erreur envoi fichier: identifiant incorrect -> {}".format(idFichier))

        self.eFichier["fichier"].close()
        self.eFichier = {"id": "00", "chemin": "", "fichier": None, "dest": "", "envoi" : False, "annule": False}

            
    def pretEnvoiFichier(self, idClient):
        """signale un destinataire comme etant pret a recevoir le fichier ou le paquet de donnees,
           et renvoie Vrai si tous les destinataires sont prets"""
        pretEnvoi = False
        if self.eFichier["dest"] == "ac":
            self.destFichier[idClient] = True
            pretEnvoi = True
            for idC in self.destFichier:
                if self.destFichier[idC] == False:
                    pretEnvoi = False
        else:
            if idClient == self.eFichier["dest"]:
                pretEnvoi = True
        #print("{} -> {}".format(idClient, pretEnvoi))        
        self.eFichier["envoi"] = pretEnvoi
               

    def annuleEnvoiFichier(self):
        """annule l'envoi d'un fichier"""
        logProg.warning("Annulation de l'envoi")
        self.envoi("fa", self.eFichier["dest"], "{}".format(self.eFichier["id"]))
        self.eFichier["annule"] = True
        essais = 0
        while not self.eFichier["id"] == "00":
            sleep(0.01)
            essais += 1
            if essais > 500:
                logProg.error("Erreur: impossible d'annuler l'envoi")
                
        if self.eFichier["id"] == "00":
           logProg.info("-> Envoi annulé")
           self.recuInfo("fa", "- Envoi du fichier annule -")
           self.emit(SIGNAL("initEnvFichier(QString, QString)"), QString.fromUtf8(""), QString.fromUtf8("x"))


    def nouveauFichier(self, idFichier, nomFichier, taille):
        """cree le fichier a recevoir - le renomme si un fichier portant ce nom existe deja - retourne le chemin complet"""
        k = 1
        tmp = nomFichier
        retour = ""
        try:
           while os.path.isfile(self.repReceptionFichiers+tmp):     
              k += 1
              tmp = nomFichier.split(".")[0]+str(k)+"."+nomFichier.split(".")[1]
              if k == 100:
                  tmp = ""
                  break
           if len(tmp) > 0:
              fichier = open((self.repReceptionFichiers + tmp), "wb") 
              self.rFichier[idFichier] = {"fichier": fichier, "nom": tmp, "nomOriginal": nomFichier, "taille": taille, "recu": 0, "ligneAffichage": None, "termine": False, "annule": False}
              retour = tmp
        except:
           logProg.error("Impossible de creer le fichier")
        return retour

    def serveurDeco(self):
        """le serveur a ferme - on affiche a nouveau l'ecran de connexion"""
        #on annule les envois de fichier en cours
        if self.eFichier["fichier"] != None:
            self.eFichier["annule"] = True
            self.emit(SIGNAL("initEnvFichier(QString, QString)"), QString.fromUtf8(""), QString.fromUtf8("x"))
        #on annule les receptions de fichiers en cours
        for idFichier in self.rFichier:
            if not self.rFichier[idFichier]["termine"]:
               logProg.warning("{} - reception annulee".format(self.rFichier[idFichier]["nom"]))
               self.rFichier[idFichier]["fichier"].close()
               os.remove(self.rFichier[idFichier]["fichier"].name)
               self.emit(SIGNAL("majAffichageRecFichier(QString)"), QString.fromUtf8(idFichier))
        self.rFichier = {}  
        
        self.recuInfo("sd", "(!) Le serveur a mis la clef sous la porte (!)")
        self.idServeur = ""
        logProg.warning("Serveur deconnecte")
        self.cnn.close()
        self.client_connecte = False
        self.serveur_lance = False
        sleep(0.01)
        self.emit(SIGNAL("majAffichage()"))
        #on affiche l'ecran de connexion
        self.show()
        self.raise_()
        self.activateWindow()
        self.msg("Le serveur a ete deconnecte")

    def recupParamCo(self):
        """recupere les derniers parametres de connexion enregistres s'il existent"""
        try:
            with open("parametresCo", 'rb') as input:
                dico = pickle.load(input)
                self.pseudo = dico["pseudo"]
                self.port = dico["port"]
                self.ip = dico["ip"]
                if os.path.isdir(dico["repReceptionFichiers"]):
                    self.repReceptionFichiers = dico["repReceptionFichiers"] 
            retour = dico
            input.close()
        except IOError:
            retour = ("Erreur: parametresCo introuvable")

        return retour        

    def sauverParamCo(self):
        """sauvegarde les parametres de connexion pour une prochaine utilisation"""
        with open("parametresCo", 'wb') as output:
             dico = {"pseudo": str(self.pseudo), "port" : int(self.port), "ip": str(self.ip), "repReceptionFichiers" : str(self.repReceptionFichiers)}
             pickle.dump(dico, output, -1)
        output.close()
        chaine = "parametres sauvegarde."

        return chaine

    def fermer(self):
        """fermeture de la connexion, et du serveur le cas echeant"""      
        if self.client_connecte:
           try:
              self.envoi("cd", "sa", "") 
           except:
              logProg.warning("impossible de prévenir le serveur de la deco")
           for fenetre in self.chatPrive:
               self.chatPrive[fenetre].close()
           self.chatPrive = {}
           self.client_connecte = False
           self.cnn.close()
           if self.eFichier["fichier"] != None:
               self.eFichier["annule"] = True
           sleep(0.001)
           logging.info(self.sauverParamCo())
     
        if self.serveur_connecte:
           self.s.stop()
           self.serveur_connecte = False   
           sleep(0.001)
           
        self.close()
        
    def closeEvent(self, event):
        """sur fermeture de la fenetre"""
        if self.client_connecte:
            self.emit(SIGNAL("majAffichage()"))
        else:    
            self.fermer()
 


class AfficherImage(QGroupBox):
    """fenetre pop-up permettant l'affichage d'une image"""
    def __init__(self, chemin, parent=None):
        super (AfficherImage, self).__init__(parent)
        self.ui = Ui_visionneuse()
        self.ui.setupUi(self)
        self.setWindowTitle(QString.fromUtf8(chemin))
        myPixmap = QPixmap(chemin)
        myScaledPixmap = myPixmap.scaled(self.ui.label.size(), Qt.KeepAspectRatio)
        self.ui.label.setPixmap(myScaledPixmap)
        self.resize(myScaledPixmap.width(),myScaledPixmap.height())
        


class ChatPrive(QMainWindow):
    """interface de chat prive entre 2 joueurs"""
    def __init__(self, connexion, interloc, parent=None):
        """initialisation de la fenetre"""
        super (ChatPrive, self).__init__(parent)
        self.co = connexion
        self.idInterloc = interloc
        self.createWidgets()

    def createWidgets(self):
        """construction de l'interface"""
        #construction de l'interface
        self.ui = Ui_chatPrive()
        self.ui.setupUi(self)
        self.ui.lblInterlocChatPrive.setText(QString.fromUtf8("Chat prive avec {}".format(self.co.autresCo[self.idInterloc])))
        self.connect(self.ui.inSaisieChatPrive, SIGNAL("returnPressed()"), self.envoiMsgPrive)
        self.connect(self.ui.envoiFichierChatPrive, SIGNAL("clicked()"), self.envoyerfichierPrive) 
        self.connect(self.ui.inDesChatPrive, SIGNAL("returnPressed()"), self.jetDesPrive)

    def envoiMsgPrive(self):
        """ajout d'une ligne au chat prive"""
        msg = self.ui.inSaisieChatPrive.text()
        self.afficherMsgPrive(self.co.idClient, msg)
        self.co.envoi("mp", "{}".format(self.idInterloc), msg)
        self.ui.inSaisieChatPrive.clear()
        QApplication.processEvents()

    def envoyerfichierPrive(self):
        """envoi d'un fichier a l'interlocuteur actuel"""
        if self.co.eFichier["id"] == "00":
           fichier = QFileDialog.getOpenFileName(
                       self, 
                       "Selectionnez un fichier a envoyer", 
                       "c:\\", 
                       "")
           if len(str(fichier)) > 0:
              self.co.envoiFichier(str(fichier), self.idInterloc)
        else:
           self.co.annuleEnvoiFichier()
    
    def jetDesPrive(self):
        """ajout d'une ligne de jet de des au chat prive"""
        expr = str(self.ui.inDesChatPrive.text())
        self.ui.inDesChatPrive.clear()
        res, detail = jet(expr)
        if res > 0:
            txt = "{}   ({})  [{}]".format(res, detail, expr)
            self.afficherMsgPrive(self.co.idClient, txt, "red")
            self.co.envoi("md", self.idInterloc, txt)
        else:
            self.afficherMsgPrive(self.co.idClient, "mmmhh, pas bon le jet", "red")
        return res

    def afficherMsgPrive(self, emetteur, msg, couleur="black"):
        """ajoute un message au chat prive"""
        emetteur = str(emetteur)
        if len(couleur)>0 and couleur != "black":
            if emetteur != self.co.idClient:
                pseudo = self.co.autresCo["{}".format(emetteur)]
            else:
                pseudo = self.co.pseudo
            txt = "<font color=\"{}\">{} - {}</font>".format(couleur, pseudo, msg)
        else:    
            if emetteur == self.co.idClient:
                txt = "<font color=\"blue\">{} : </font> {}".format(self.co.pseudo, msg)
            elif emetteur in self.co.autresCo:
                pseudo = self.co.autresCo["{}".format(emetteur)]
                txt = "<font color=\"green\">{} : </font> {}".format(pseudo, msg)
            else:
                txt = str(msg)

        txt = QString.fromUtf8(txt)
        item = QListWidgetItem(self.ui.lstChatPrive)
        self.ui.lstChatPrive.addItem(item)
        label = QLabel()
        label.setWordWrap(True)
        label.setText(txt)
        item.setSizeHint(QSize(1, label.heightForWidth (self.ui.lstChatPrive.width()) + 5))
        self.ui.lstChatPrive.setItemWidget(item, label)
        self.ui.lstChatPrive.scrollToItem(item)
        self.show()
        self.raise_()
        self.activateWindow()
        QApplication.processEvents()

class EcranPrincipal(QMainWindow):
    """interface comprenant: chat ecrit, fenetre d'infos, lancer de des, echange de fichiers, lancement du chat vocal"""
    def __init__(self, connexion, parent=None):
        """initialisation de la fenetre"""
        super (EcranPrincipal, self).__init__(parent)
        self.co = connexion
        self.connecte = True
        self.estServeurVoc = False
        self.estClientVoc = False
        self.cases = {}
        self.createWidgets()

    def createWidgets(self):
        """construction de l'interface"""
        #construction de l'interface
        self.ui = Ui_principal()
        self.ui.setupUi(self)

        #connexion des commandes
        self.connect(self.ui.inChat, SIGNAL("returnPressed()"), self.envoiMsg)
        self.connect(self.ui.d20, SIGNAL("clicked()"), self.d20)
        self.connect(self.ui.d100, SIGNAL("clicked()"), self.d100)
        self.connect(self.ui.inJetDes, SIGNAL("returnPressed()"), self.autreJet)
        self.connect(self.ui.envoiFichier, SIGNAL("clicked()"), self.envoyerfichier) 
        self.connect(self.ui.repReceptionFichiers, SIGNAL("clicked()"), self.repReception)
        self.connect(self.ui.listFichiers, SIGNAL("itemDoubleClicked(QTreeWidgetItem*, int)"), self.ouvrirFichier)
        self.connect(self.ui.lstStatutJoueurs, SIGNAL("itemDoubleClicked (QListWidgetItem *)"), self.ouvrirChatPrive)
        self.connect(self.ui.chatVoc, SIGNAL("clicked()"), self.chatVoc)

        #reception des signaux self.emit(SIGNAL("majAffichage()"))
        self.connect(self, SIGNAL("msgChat(QString, QString)"), self.ajoutChat)
        self.connect(self.co, SIGNAL("msgChat(QString, QString)"), self.ajoutChat)
        self.connect(self, SIGNAL("nouvelleInfo(QString, QString)"), self.ajoutInfo)
        self.connect(self.co, SIGNAL("nouvelleInfo(QString, QString)"), self.ajoutInfo)
        self.connect(self, SIGNAL("majAffichageRecFichier(QString)"), self.afficheReception)
        self.connect(self.co, SIGNAL("majAffichageRecFichier(QString)"), self.afficheReception)
        self.connect(self, SIGNAL("imageRecue(QString)"), self.imageRecue)
        self.connect(self.co, SIGNAL("imageRecue(QString)"), self.imageRecue)
        self.connect(self, SIGNAL("initEnvFichier(QString, QString)"), self.afficheEnvoi)
        self.connect(self.co, SIGNAL("initEnvFichier(QString, QString)"), self.afficheEnvoi)
        self.connect(self, SIGNAL("majAffichage()"), self.majStatut)
        self.connect(self.co, SIGNAL("majAffichage()"), self.majStatut)
        self.connect(self, SIGNAL("majAffichageLstClient()"), self.majStatutLstClients)
        self.connect(self.co, SIGNAL("majAffichageLstClient()"), self.majStatutLstClients)
        self.connect(self, SIGNAL("chatPrive(QString, QString, QString)"), self.chatPrive)
        self.connect(self.co, SIGNAL("chatPrive(QString, QString, QString)"), self.chatPrive)

        #plateau de jeu
        self.creerPlateau(20,20)
        self.nouveauPion()
        
        #mise a jour de l'affichage
        self.majStatut()
        self.majStatutLstClients()

    """def msg(self, txt):
        
        self.ui.txt_msg.setText(QString.fromUtf8(txt))
        QApplication.processEvents()"""

    def ajoutChat(self, emetteur, msg):
        """ajoute une nouvelle ligne au chat ecrit"""
        emetteur = str(emetteur)
        if emetteur == self.co.idClient:
            txt = "<font color=\"blue\">{} : </font> {}".format(self.co.pseudo, msg)
        else:
            pseudo = self.co.autresCo["{}".format(emetteur)]
            txt = "<font color=\"green\">{} : </font> {}".format(pseudo, msg)
            
        txt = QString.fromUtf8(txt)
        item = QListWidgetItem(self.ui.listAffichage)
        self.ui.listAffichage.addItem(item)
        label = QLabel()
        label.setWordWrap(True)
        label.setText(txt)
        item.setSizeHint(QSize(1, label.heightForWidth (self.ui.listAffichage.width()) + 5))
        self.ui.listAffichage.setItemWidget(item, label)
        self.ui.listAffichage.scrollToItem(item)
        QApplication.processEvents()

    def ajoutInfo(self, nature, msg):
        """ajoute une nouvelle ligne a la liste des evenements"""
        #couleur selon nature de l'info:
        if nature[:1] == "c":
            txt = "<font color=\"green\">{}</font>".format(msg)
        elif nature == "id":
            txt = "<font color=\"red\">{}</font>".format(msg)
        elif nature[:1] == "f":
            txt = "<font color=\"blue\">{}</font>".format(msg)    
        elif nature[:1] == "v":
            txt = "<font color=\"orange\">{}</font>".format(msg)    
        else:
            txt = msg

        txt = QString.fromUtf8(txt)         
        item = QListWidgetItem(self.ui.listEvenement)
        self.ui.listEvenement.addItem(item)
        
        label = QLabel()
        label.setWordWrap(True)
        label.setText(txt)
        item.setSizeHint(QSize(110, label.heightForWidth (self.ui.listEvenement.width()) + 6))
        self.ui.listEvenement.setItemWidget(item, label)
        self.ui.listEvenement.scrollToItem(item)
        QApplication.processEvents()

             
    def envoiMsg(self):
        """envoie un message pour le chat ecrit"""
        msg = self.ui.inChat.text()
        self.co.envoi("m ", "tc", msg)
        self.ui.inChat.clear()
        QApplication.processEvents()

    def lancerD(self, expr):
        """fonction de lancer de des"""
        res, detail = jet(expr)
        if res > 0:
            txt = "{}: {}   ({})  [{}]".format(self.co.pseudo, res, detail, expr)
            self.co.envoi("id", "tc", txt)
        else:
            self.ajoutInfo("id", "mmmhh, pas bon le jet")
        return res
             
    def d20(self):
        """lance un D20"""
        self.lancerD("1d20")
        
    def d100(self):
        """lance un D100"""
        self.lancerD("1d100")

    def autreJet(self):
        """lance un jet personnalise"""
        expr = str(self.ui.inJetDes.text())
        retour = self.lancerD(expr)
        self.ui.inJetDes.clear()

    def envoyerfichier(self):
        """selectionne et envoie un fichier ou annule l'envoi en cours s'il existe"""
        if self.co.eFichier["id"] == "00":
           fichier = QFileDialog.getOpenFileName(
                       self, 
                       "Selectionnez un fichier a envoyer", 
                       "c:\\", 
                       "")
           if len(str(fichier)) > 0:
              self.co.envoiFichier(str(fichier))
        else:
           self.co.annuleEnvoiFichier()
           
    def ouvrirFichier(self):
        """ouvre un fichier depuis la liste des fichiers recus/envoyes"""
        item = self.ui.listFichiers.currentItem()
        eR = item.text(0)
        taux = item.text(1)
        nom = item.text(2)
        if eR == "R":
            if taux == "ok":
                try:
                    chemin = "{}\\{}".format(self.co.repReceptionFichiers, nom)
                    Popen(chemin, shell=True, stdout=PIPE) #from subprocess
                except:
                    print("impossible d'ouvrir le fichier")




    def repReception(self):
        """permet de choisir son repertoire de reception des fichiers"""
        dossier = QFileDialog.getExistingDirectory(self)
        if len(dossier) > 0:
            if dossier[len(dossier)-1:] != "\\":
                dossier += "\\"
            self.co.repReceptionFichiers = str(dossier)
            self.majStatut()

    def afficheReception(self, idFichier):
           """ajoute/maj une ligne dans la liste des fichiers en cours de reception"""
           idFichier = str(idFichier)
        #try:                                              
           if self.co.rFichier[idFichier]["ligneAffichage"] == None:
              self.co.rFichier[idFichier]["ligneAffichage"] = QTreeWidgetItem(self.ui.listFichiers, ["R", "0", self.co.rFichier[idFichier]["nom"]])
              self.ui.listFichiers.scrollToItem(self.co.rFichier[idFichier]["ligneAffichage"])
           else:
              if self.co.rFichier[idFichier]["termine"]:
                 taux = "ok"
              elif self.co.rFichier[idFichier]["annule"]:
                 taux = "x"
              else:    
                 taux = str(int(100*self.co.rFichier[idFichier]["recu"]/self.co.rFichier[idFichier]["taille"]))
              self.co.rFichier[idFichier]["ligneAffichage"].setText(1, taux)                                                          
        #except:
        #    logProg.error("erreur d'affichage de la progression: " + idFichier)

    def imageRecue(self, idFichier):
        """verifie si le fichier recu est une image, et l'ouvre le cas echeant"""
        idFichier = str(idFichier)
        if self.co.rFichier[idFichier]["termine"]:
           try: 
              typeFichier = self.co.rFichier[idFichier]["nom"].split(".")[len(self.co.rFichier[idFichier]["nom"].split("."))-1]
           except:
              typeFichier = "" 

        if typeFichier.lower() in ["png", "jpeg", "jpg"]:
             #si c'est une image, on l'ouvre dans une nouvelle fenetre
             logProg.debug("ouverture d'une image : " + self.co.rFichier[idFichier]["nom"])
             chemin = self.co.repReceptionFichiers + self.co.rFichier[idFichier]["nom"]
             #print(chemin)
             self.affiche = AfficherImage("{}".format(chemin))
             self.affiche.show()
             self.affiche.raise_()
             QApplication.processEvents()

    def afficheEnvoi(self, fichier, taux):
        """ajoute/maj une ligne a la liste des fichiers en cours d'envoi"""
        fichier = str(fichier)
        taux = str(taux)
        if len(fichier) > 0:
            self.ligneEFichier = QTreeWidgetItem(self.ui.listFichiers, ["E", taux, fichier])
            self.ui.listFichiers.scrollToItem(self.ligneEFichier)
        elif len(taux) > 0:
            if taux != self.ligneEFichier.text(1): 
                self.ligneEFichier.setText(1, taux)
            
    def majStatut(self):
        """met a jour l'onglet de statut de connexion"""
        self.ui.txtStatutCoPseudo.setText(QString.fromUtf8("Pseudo : {}".format(self.co.pseudo)))
        if self.co.serveur_connecte:
            self.ui.txtStatutCoServeur.setText(QString.fromUtf8("Serveur : {} [{}]".format(self.co.pseudo, self.co.ip)))
        elif len(self.co.idServeur) > 0 and self.co.idServeur in self.co.autresCo:
            self.ui.txtStatutCoServeur.setText(QString.fromUtf8("Serveur : {} [{}]".format(self.co.autresCo[self.co.idServeur], self.co.ip)))
        else:
            self.ui.txtStatutCoServeur.setText(QString.fromUtf8("Serveur : Pas de serveur"))
            
        if self.estServeurVoc:
            self.ui.txtStatutCoServeur.setText(QString.fromUtf8("Serveur vocal : {} [{}]".format(self.co.pseudo, self.co.ip)))
        QApplication.processEvents()
        
    def majStatutLstClients(self):
        """met a jour la liste des joueurs"""
        self.ui.lstStatutJoueurs.clear()
        txt = "{} - {}".format(self.co.idClient, self.co.pseudo)
        self.ui.lstStatutJoueurs.addItem(QString.fromUtf8(txt))
        for idClient in self.co.autresCo:
            txt = "{} - {}".format(idClient, self.co.autresCo[idClient])
            self.ui.lstStatutJoueurs.addItem(QString.fromUtf8(txt))
        self.majStatut()    
        QApplication.processEvents()
        
    def ouvrirChatPrive(self):
        """ouvre un chat prive avec le joueur sur lequel on a clique"""
        item = self.ui.lstStatutJoueurs.currentItem()
        idInterloc = str(item.text())[0:2]
        if idInterloc != self.co.idClient:
           self.chatPrive(idInterloc)
           

    def chatPrive(self, idInterloc, txt="", couleur=""):
        """ouvre la fenetre de chat prive si elle ne l'est pas deja, puis affiche le message"""
        idInterloc = str(idInterloc)
        if not idInterloc in self.co.chatPrive:
           self.co.chatPrive[idInterloc] = ChatPrive(self.co, idInterloc)
        self.co.chatPrive[idInterloc].show()
        if len(txt)>0:
            if len(couleur)>0:
                self.co.chatPrive[idInterloc].afficherMsgPrive(idInterloc, txt, couleur)
            else:
                self.co.chatPrive[idInterloc].afficherMsgPrive(idInterloc, txt)
                              
    def creerServeurVoc(self):
        """cree un serveur vocal"""
        if not self.estServeurVoc:
            self.sVoc = ServeurVoc(6660)
              #on ouvre une boite de dialogue pour demander l'ip distante
                #de celui qui veut ouvrir le serveur voc
            ipS, ok = QInputDialog.getText(self, 'Creation du serveur vocal', 
            'Saisissez votre adresse IP distante :')
            if ok:
               if ipValide(ipS):
                  #self.co.ipServeurVoc = self.ui.ipServeurVoc.text()
                  self.co.ipServeurVoc = ipS
                  txt = self.sVoc.creer()
                  self.ajoutInfo("vs", txt)
                  if self.sVoc.serveur_lance:
                     self.co.envoi("vs","ac","{}".format(self.co.ipServeurVoc))
                     self.estServeurVoc = True
                     self.majStatut()
                  else:
                     self.ajoutInfo("vs", "Erreur - Creation du serveur vocal annulee") 
               else:
                  self.ajoutInfo("vs", "Veuillez entrer une adresse ip valide")
        else:
            self.fermerServeurVoc()
            

    def fermerServeurVoc(self):
        """ferme le serveur vocal"""
        txt = self.sVoc.stop()
        self.ajoutInfo("vs", txt)
        if not self.sVoc.serveur_lance:
            self.co.envoi("vf","ac","")
            self.estServeurVoc = False
            self.majStatut()
        
    def chatVoc(self):
        """connexion au chat vocal"""
        if not self.estClientVoc:
             if len(self.co.ipServeurVoc) == 0:
                if QMessageBox.question(self.parent(), "Chat Vocal", "Aucun serveur vocal ne semble avoir ete cree, /nVoulez-vous en creer un?",
                                        QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
                    self.creerServeurVoc()
                    sleep(0.01)
                    
             if len(self.co.ipServeurVoc) > 0:
                  self.cVoc = ClientVoc(self.co.idClient, self.co.ipServeurVoc, 6660)
                  txt = self.cVoc.creer()
                  if self.cVoc.connecte:
                      self.ajoutInfo("vi", txt)
                      self.co.envoi("vi","ac","")
                      self.estClientVoc = True
                      self.majStatut()
                  
        else:
            self.quitterChatVoc()

    def quitterChatVoc(self):
        """deconnexion du chat vocal"""
        if self.estClientVoc:
            txt = self.cVoc.stop()
            self.ajoutInfo("vq", txt)
            self.co.envoi("vq","ac","")
            self.estClientVoc = False
            self.majStatut()
        if self.sVoc.serveur_lance:
            self.fermerServeurVoc()
        

    def creerPlateau(self, x, y):
        """Creation du Plateau de combat"""
        if x > 0 and y > 0 and x == int(x) and y == int(y):
            self.plateau = QGraphicsScene(self)
            self.cCase = 30
            self.plateau.setSceneRect(0, 0, self.cCase*x, self.cCase*y)

            pinceau = QPen()
            pinceau.setColor(QColor(85, 85, 85, 85))
            pinceau.setWidth(1)
            i = 0
            j = 0
            for i in range(x):
                for j in range(y):
                    if 1 == (i % 2):
                        j += 0.5
                    polygon = QPolygonF()
                    polygon << QPointF(i*self.cCase,(j+0.5)*self.cCase) << QPointF((i+0.34)*self.cCase,j*self.cCase)<< QPointF((i+1)*self.cCase,(j)*self.cCase) << QPointF((i+1.34)*self.cCase,(j+0.5)*self.cCase) << QPointF((i+1)*self.cCase,(j+1)*self.cCase) << QPointF((i+0.34)*self.cCase,(j+1)*self.cCase)
                    self.plateau.addPolygon(polygon)
                 
            self.ui.vuePlateau.setScene(self.plateau)


    def nouveauPion(self):
        """essai de creation graphique: ajout d'un pion sur le plateau de jeu"""
        #creation d'un pion
        pinceau = QPen()
        pinceau.setColor(QColor(0, 0, 0, 120))
        pinceau.setWidth(2)
        self.pion = QGraphicsEllipseItem(0, 0, self.cCase, self.cCase)
        self.pion.setPen(pinceau)
        self.pion.setFlag(QGraphicsItem.ItemIsMovable)
        self.pion.setFlag(QGraphicsItem.ItemIsFocusable)
        self.pion.setBrush(QColor(255, 0, 0, 150))

        #ombre
        self.shadow = QGraphicsDropShadowEffect() 
        self.shadow.setColor(QColor(50, 50, 50, 200)) 
        self.shadow.setXOffset(1) 
        self.shadow.setYOffset(1) 
        self.shadow.setBlurRadius(3) 
        self.pion.setGraphicsEffect(self.shadow)
        self.shadow.setEnabled(True)

        self.plateau.addItem(self.pion)

    def closeEvent(self, event):
        """sur fermeture de la fenetre"""
        if self.estClientVoc:
            self.cVoc.stop()
        if self.estServeurVoc:
            self.sVoc.stop()
        self.co.fermer()
        sleep(0.01)
        self.connecte = False    
        self.close()             
        
if __name__ == "__main__":
    demarrageOk = True
    #repertoire de travail et creation des dossiers necessaires:
    try:
       repCourant = os.getcwd()
    except:
       repCourant = ""
       
    if not len(repCourant) > 0:
        logProg.error("Impossible de determiner le repertoire courant")
        demarrageOk = False
    else:
        try:
            #repertoire media (musiques+images)
            if not os.path.exists(repCourant+"\\media"):
               os.mkdir(repCourant+"\\media")
            #repertoire utilisateur (sauvegardes)
            if not os.path.exists(repCourant+"\\svg"):
               os.mkdir(repCourant+"\\svg")
            #repertoire reception des fichiers persos
            if not os.path.exists(repCourant+"\\FichiersRecus"):
               os.mkdir(repCourant+"\\FichiersRecus")
        except:
            logProg.error("Erreur de creation des repertoires de l'application")
            demarrageOk = False         
                 
    #verif si l'appli est deja lancee:    
    nomAppli = "DMonde.exe"
    compte = 0
    for proc in process_iter():    #from psutil
        try:
            nomProc = proc.name()
            if nomProc == nomAppli:
                compte += 1
            if compte > 1:
                demarrageOk = False
                logProg.error("Une instance de l'application est deja en cours d'execution")
                break
        except:
            pass
        
    if demarrageOk: 
    #lancement de l'appli    
        app = QApplication(argv)  #'argv' vient de 'sys'
        connexion = EcranConnexion()    
        connexion.show()
        r = app.exec_()
        if r == 0 and connexion.client_connecte:
            #si pas d'erreur et client connecte, on ouvre l'interface principale
            ecranPrincipal = EcranPrincipal(connexion)
            ecranPrincipal.show()
            r = app.exec_()
            exit(r)   #'exit' vient de 'sys'
        

    


    
    
    
