#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from messages import Messages
from ascii_encoder import AsciiEncoder
import os

#Rapport: Ceci gère la le lien entre la connexion au serveur, le protocole
#         et le système de fichier local


class ClientManager:
    """
    Classe représentant le client
    """

    def __init__(self, connexion, protocole, file_system):
        self.quit_has_been_called = False

        self.connexion = connexion
        self.protocole = protocole
        self.file_system = file_system

    def greeting(self):
        message_to_send = self.protocole.get_connexion()
        server_answer = self.get_server_answer(message_to_send)

        return server_answer

    def get_server_name(self):
        tag_name = "nomServeur"

        message_to_send = self.protocole.get_server_name()
        server_answer = self.get_server_answer(message_to_send)
        interpreted_answer = self.protocole.interpret(server_answer, tag_name)

        return interpreted_answer

    def get_folder_list(self, folder_name):
        parent_tag_name = "listeDossiers"
        child_tag_name = "dossier"

        message_to_send = self.protocole.get_folder_list(folder_name)
        server_answer = self.get_server_answer(message_to_send)
        # si il y a erreur, on retourne la réponse du serveur au prompt qui va l'interpréter.
        # Sinon, le protocole génère la liste des dossiers.
        if "erreur" in server_answer:
            return server_answer
        else:
            return self.protocole.interpret(server_answer, parent_tag_name, child_tag_name)

    def verify_folder_exists(self, folder_name):
        message_to_send = self.protocole.get_folder_list(folder_name)
        server_answer = self.get_server_answer(message_to_send)
        if "listeDossiers" in server_answer:
            return True
        else:
            return False

    def create_folder(self, folder_name):
        message_to_send = self.protocole.create_folder(folder_name)
        server_answer = self.get_server_answer(message_to_send)

        return server_answer

    def upload_file(self, path):
        file_name = self.get_file_name(path)
        folder_name = self.get_folder_name(path)
        if self.file_system.folder_exists(path):
            signature = self.file_system.get_md5_signature(path)
            file_content = self.file_system.get_encoded_content(path)
            date = self.file_system.get_file_modification_date(path)

            message_to_send = self.protocole.upload_file(file_name, folder_name, signature, file_content, date)
            server_answer = self.get_server_answer(message_to_send)

            return server_answer
        else:
            return Messages.FILE_NOT_FOUND_CLIENT

    def download_file(self, path):
        file_name = self.get_file_name(path)
        folder_name = self.get_folder_name(path)

        message_to_send = self.protocole.download_file(file_name, folder_name)
        server_answer = self.get_server_answer(message_to_send)
        if "contenu" in server_answer:
            interpreted_answer = self.protocole.interpret(server_answer, "fichier", "contenu")
            content = interpreted_answer[0]  # interpreted_answer étant un tableau, on prend l'élément à l'intérieur
            decoded_content = AsciiEncoder.decode_ascii(content)
            self.file_system.create_file(path, decoded_content)

        return server_answer

    def delete_folder(self, folder_name):
        message_to_send = self.protocole.delete_folder(folder_name)
        server_answer = self.get_server_answer(message_to_send)

        return server_answer

    def delete_file(self, path):
        file_name = self.get_file_name(path)
        folder_name = self.get_folder_name(path)

        message_to_send = self.protocole.delete_file(file_name, folder_name)
        server_answer = self.get_server_answer(message_to_send)

        return server_answer

    def verify_file_exists(self, path):
        folder_name = self.get_folder_name(path)
        file_name = self.get_file_name(path)

        message_to_send = self.protocole.get_file_list(folder_name)
        server_answer = self.get_server_answer(message_to_send)
        if file_name in server_answer:
            return True
        else:
            return False

    def verify_file_is_identical(self, path):
        file_name = self.get_file_name(path)
        folder_name = self.get_folder_name(path)
        if self.file_system.folder_exists(path):
            signature = self.file_system.get_md5_signature(path)
            date = self.file_system.get_file_modification_date(path)

            message_to_send = self.protocole.verify_file_is_identical(file_name, folder_name, signature, date)
            server_answer = self.get_server_answer(message_to_send)
            return server_answer
        else:
            return Messages.FILE_NOT_FOUND_CLIENT

    def verify_file_is_more_recent(self, path):
        file_name = self.get_file_name(path)
        folder_name = self.get_folder_name(path)
        if self.file_system.folder_exists(path):
            date = self.file_system.get_file_modification_date(path)

            message_to_send = self.protocole.verify_file_is_more_recent(file_name, folder_name, date)
            server_answer = self.get_server_answer(message_to_send)

            return server_answer
        else:
            return Messages.FILE_NOT_FOUND_CLIENT

    def update(self, path):
        if self.file_system.folder_exists(path):
            client_file_list = self.file_system.get_file_list(path)
            server_file_list = self.get_server_file_list(path)

            self.update_client_to_server(client_file_list, server_file_list)
            self.update_server_to_client(client_file_list, server_file_list)

            server_answer = Messages.OK
        else:
            server_answer = Messages.FOLDER_NOT_FOUND_CLIENT

        return server_answer

    def get_server_file_list(self, path):
        file_list = []
        folder_file_list = self.get_server_file_list_in_folder(path)
        for file in folder_file_list:
            file_list.append(file)

        folder_list = self.get_folder_list(path)
        for folder in folder_list:
            new_path = path + '\\' + folder
            folder_file_list = self.get_server_file_list(new_path)
            if folder_file_list:
                for file in folder_file_list:
                    file_list.append(file)

        return file_list

    def get_server_file_list_in_folder(self, path):
        parent_tag_name = "listeFichiers"
        child_tag_name = "fichier"

        message_to_send = self.protocole.get_file_list(path)
        server_answer = self.get_server_answer(message_to_send)
        interpreted_answer = self.protocole.interpret(server_answer, parent_tag_name, child_tag_name)

        file_list = []

        for file in interpreted_answer:
            file_list.append(path + '\\' + file)

        return file_list

    def update_client_to_server(self, client_file_list, server_file_list):
        for file in client_file_list:
            if file not in server_file_list:
                folder_name = self.get_folder_name(file)

                if not self.verify_folder_exists(folder_name):
                    self.create_folder(folder_name)

                if not self.verify_file_exists(file):
                    self.upload_file(file)
            else:
                file_more_recent_server_answer = self.verify_file_is_more_recent(file)
                file_more_recent_on_client = "oui" in file_more_recent_server_answer
                if file_more_recent_on_client:
                    self.delete_file(file)
                    self.upload_file(file)

    def update_server_to_client(self, client_file_list, server_file_list):
        for file in server_file_list:
            if file not in client_file_list:
                folder_name = self.get_folder_name(file)

                if not self.file_system.folder_exists(folder_name):
                    self.file_system.create_folder(folder_name)

                if not self.file_system.file_exists(file):
                    self.download_file(file)

            else:
                file_more_recent_server_answer = self.verify_file_is_more_recent(file)
                file_more_recent_on_client = "oui" in file_more_recent_server_answer
                if not file_more_recent_on_client:
                    self.download_file(file)

    def quit(self):
        message_to_send = self.protocole.quit()
        server_answer = self.get_server_answer(message_to_send)
        self.connexion.close()

        return server_answer

    @staticmethod
    def get_folder_name(path):
        return os.path.dirname(path)

    @staticmethod
    def get_file_name(path):
        return os.path.basename(path)

    def get_server_answer(self, message_to_send):
        self.connexion.send(message_to_send)
        return self.connexion.receive()
