from __future__ import unicode_literals
# -*- coding: utf-8 -*-
"""client chat"""
import socket
import threading
import time
import os


#### initialisation des variables ####
port = 6660
taille_paquets = 1024
#idClient = "00"


class Reception(threading.Thread):
    """fil de reception"""
    def __init__(self, cnn):
        """initialisation du fil"""
        threading.Thread.__init__(self)
        self.cnn = cnn
        self.connecte = True
        self.idClient = "00"
        self.idFichier = "00"
        self.receptionFichier = {} #id du fichier: nom du fichier
        self.repReceptionFichiers = "C:\\"
        self.recuInfo = ()
        self.recuChat = ()
        self.autresCo = {}
        self.ipServeurVoc = ""

    def nouveauFichier(self, idFichier, nomFichier):
        """renomme un fichier a recevoir si un fichier portant ce nom existe deja et 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:     
              self.receptionFichier[idFichier] = open((self.repReceptionFichiers + tmp), "wb")
              retour = tmp
        except:
           print("Impossible de créer le fichier")
        return retour
        
              
        
    def info(self, nature, msg):
        """stocke une information recu en attendant qu'elle soit affichee"""
        self.recuInfo = (nature, msg)

    def chat(self, emetteur, msg):
        """stocke un message recu en attendant qu'il soit affiche"""
        self.recuChat = (emetteur, msg)
        
    def traitement(self, msg):
        """determine la destination du message 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 == "ci":
                #recoit l'identifiant du client fourni par le serveur
                self.idClient = dest
                print("mon id est: {}\n".format(self.idClient))
                
            elif nature == "cc":
                if contenu[0:2] != self.idClient:
                    self.autresCo[contenu[0:2]] = contenu[2:]
                    print("{} est connecte ({})".format(contenu[2:], contenu[0:2]))
                    self.info("cc", "{} est connecte ({})".format(contenu[2:], contenu[0:2]))

            elif nature == "cd":
                if contenu != self.idClient and len(contenu) == 2:
                    print("{} s'est deconnecte ({})".format(self.autresCo[contenu], contenu))
                    self.info("cd", "{} s'est deconnecte ({})".format(self.autresCo[contenu], contenu))
                    del self.autresCo[contenu]
                    
            elif categorie == "m":
                #afficher dans le chat
                print("chat: {} -> {}\n".format(emet, contenu))
                self.chat(emet, contenu)
                
            elif categorie == "i":
                #afficher dans la fenetre évènement
                self.info(nature, contenu)
                if nature == "id":
                    #jet de dés: afficher en rouge
                    print("jet de dé: {} -> {}\n".format(emet, contenu))
                if nature == "ic":
                    #nouveau client connecte: afficher en bleu
                    print("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.idFichier == "00":
                       if len(contenu) == 2:
                          self.idFichier = contenu
                       else:
                          print("erreur: id du fichier\n")
                    else:
                       print("Un fichier est en cours d'envoi\n")
                       
                elif nature == "fi":
                    #quelqu'un nous envoie un fichier
                    if len(contenu)>2:
                       #les 2 premiers car sont l'identifiant, le reste est le nom du fichier
                       essai = self.nouveauFichier(contenu[0:2], contenu[2:])
                       if len(essai) > 0:
                           self.info(nature, "Fichier {} en cours de reception".format(contenu[2:]))
                       else:
                           self.info(nature, "Impossible de créer le fichier à recevoir")
                    else:
                       print("erreur reception fichier: id ou nom du fichier incorrect\n") 
                    
                elif nature == "fd":
                    #on recoit les donnees a ecrire dans le fichier
                    if len(contenu) > 2:
                        #print("reception fichier {}".format(contenu[0:2]))
                        data = contenu[2:].replace("[diese]","#")
                        self.receptionFichier[contenu[0:2]].write(data)
                    elif len(contenu) == 2:
                        pass
                    else:
                        print("erreur de reception des donnees du fichier\n")
                    
                elif nature == "ff":
                    #fin de reception du fichier
                    self.info("ff", "Fichier {} recu\n".format(os.path.basename(self.receptionFichier[contenu[0:2]].name)))          
                    self.receptionFichier[contenu[0:2]].close()
                    self.receptionFichier[contenu[0:2]] = ""
                #print("fichier: {} -> {}\n".format(emet, contenu))

            elif categorie == "v":
                #infos liees au chat vocal
                if nature == "vs":
                    #un serveur vocal a ete cree
                    self.info("vs", "{} a cree un serveur vocal ({})".format(self.autresCo[emet], contenu))
                    self.ipServeurVoc = contenu
                    
                if nature == "vi":
                    #un client rejoint le chat vocal
                    self.info("vi", "{} a rejoint le chat vocal".format(self.autresCo[emet]))

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

                if nature == "vf":
                    #fermeture du serveur vocal
                    self.info("vf", "{} a ferme le serveur vocal".format(self.autresCo[emet]))
                    
            elif categorie == "p":
                if nature == "pi":
                    #nouveau plateau créé
                    print("nouveau plateau: {}\n".format(emet, contenu))
        else:
            print("Erreur: message illisible -> {}\n".format(msg))
            
    def run(self):
        """reception de chaines de caracteres"""
        while self.connecte:
           #try:
               recu = self.cnn.recv(1024).decode('utf-8')
               for msg in recu.split("#"):
                   if len(msg) > 0:
                       self.traitement(msg)
           #except:
           #   self.stop()

    def stop(self):
        """fin de la reception"""
        print("Reception TCP interrompue.")
        self.connecte = False     

            

class Client(threading.Thread):
    """client pour chat tcp"""
    def __init__(self):
        """initialisation du client"""
        threading.Thread.__init__(self)
        self.connecte = False
        self.idClient = "00"
        self.ipClient = socket.gethostbyname(socket.gethostname())
    
    def envoi(self, nature, dest, msg):
        """envoie un message au serveur TCP
           - nature du message (2 car)
           - exp: id de l'expediteur (2 car)
           - dest: id du destinataire (2 car)
           - msg: contenu du message  (1018 car max)"""
        exp = self.R.idClient
        if self.connecte:
            try:
               if len(msg) <= 1018:
                  txt = "{}{}{}{}#".format(nature, exp, dest, msg)
                  self.cnn.sendall(txt.encode('utf-8'))
                  retour = len(txt)
               else:
                  #on decoupe le message en portions de 1018 car max (a voir)
                  nb_paquet = int(len(msg)/1018)
                  i = 0
                  while i <= nb_paquet:
                      txt = "{}{}{}{}#".format(nature, exp, dest, msg[((i*1018)+1):((i+1)*1018)])
                      self.cnn.sendall(txt.encode('utf-8'))
                      i += 1
                      
                  #envoi du dernier paquet
                  txt = "{}{}{}{}#".format(nature, exp, dest, msg[((i*1018)+1):])
                  self.cnn.sendall(txt.encode('utf-8'))    
                  retour = len(msg)
                  
            except:
                retour = ""
                print("Envoi impossible")
        else:
            retour = ""
            print("Le client n'est pas connecte au serveur")
     
        return retour

    def creer(self, pseudo, hote):
        """cree le client"""
        self.pseudo = pseudo
        self.hote = hote
        print("En attente du serveur")
        while self.connecte==False:
        #en attente de la connexion    
            try:
               self.cnn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
               self.cnn.connect((self.hote, port))
               self.connecte = True
               retour = "Connexion etablie avec le serveur sur le port {}\n".format(port)
            except KeyboardInterrupt:
               break
            except:
               pass

        if self.connecte:
            #demarre le fil de reception
            self.R = Reception(self.cnn)
            self.R.start()
            #prévient le serveur et envoie le pseudo
            self.envoi("ci", "sa", pseudo)
            self.start()
            
        return retour  

    def envoiFichier(self, chemin, dest = "ac"):
        """intialise le thread d'envoi du fichier"""
        threading.Thread(None, self.fil_envoiFichier, None, (chemin, dest), {}).start()

    def fil_envoiFichier(self, chemin, dest):
        """thread d'envoi de fichier(s)"""
        # on verifie si le fichier existe:
        existe = True
        try:
            fichier = open(chemin, "rb") 
        except:
            print("Le fichier '{}' est introuvable.".format(fichier))
            existe = False        
         
        if existe:
            taille = os.path.getsize(chemin)
            nomFichier = os.path.basename(chemin)
            #on demande un identifiant au serveur
            if len(nomFichier) > 0:
               self.envoi("f0","sa","")
               while self.R.idFichier == "00":
                   time.sleep(0.1)
               idFichier = self.R.idFichier
               self.R.idFichier = "00"
               print("{} a pour id {}\n".format(nomFichier, idFichier))
               if len(idFichier) == 2:
                  #on previent les destinataires, et on leur transmet l'identifiant et le nom du fichier
                  self.envoi("fi", dest, "{}{}".format(idFichier, nomFichier))
                  #on attend confirmation
                  
                  #on envoie les donnees
                  data = fichier.read(512)
                  while len(data) > 0:
                     data2 = data.replace("#","[diese]") 
                     self.envoi("fd", dest, "{}{}".format(idFichier, data2))
                     time.sleep(0.01)
                     data = fichier.read(512)
                     
                  #on signale que l'envoi est termine
                  self.envoi("ff", dest, "{}".format(idFichier))
                  self.envoi("f1","sa","{}".format(idFichier))

                  self.R.info("ff","- Fichier envoye -")
                  print("\n- Fichier envoye -")
               else:
                  print("Erreur envoi fichier: identifiant incorrect -> {}".format(idFichier))           
   
  
    def run(self):
        """boucle de fonctionnement"""
        while self.connecte:
           time.sleep(0.1)
        
    def stop(self):
        """fermeture du client"""
        try:
           self.envoi("cd", "sa", "") 
        except:
           pass
        self.connecte = False
        self.R.stop()        
        self.cnn.close()
        time.sleep(0.2)
        return "Client ferme"
              

#### fil principal ####  
if __name__ == "__main__":
    # si lancement direct:
    c = Client()
    pseudo = raw_input("pseudo: ")
    print(c.creer(pseudo, "localhost")) 
    while True:
        print(c.R.autresCo)
        saisie = raw_input("\n > ")
        if saisie == "quit":
            break
        else:
            c.envoi("m ","ac",saisie)
        
    #os.system("pause")
    c.stop()


   
