# -*- coding: UTF-8 -*-
###########################################################################
# Eole NG - 2007
# Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon)
# Licence CeCill  cf /root/LicenceEole.txt
# eole@ac-dijon.fr
#
# aaf_rpc.py
#
# fonctions xmlrpc pour la gestion des fichiers d'import AAF
#
###########################################################################
"""module de gestion des identifiants ent
"""
import os
import shutil
import traceback
from zephir.backend.db_utils import db_connect
from zephir.backend.aaf import AAF
from zephir.backend.config import u, AAF_DIR
from zephir.backend.xmlrpceole import XMLRPCEole as XMLRPC
from zephir.backend.uucp_utils import uucp_pool, UUCPError
from zephir.utils.convert import to_bytes

class AAFRPC(XMLRPC):
    """serveur XMLRPC zephir pour la gestion des fichiers d'import AAF
    """

    def __init__(self, parent):
        self.dbpool = db_connect()
        self.dbpool.noisy = 0
        self.parent = parent
        self.aaf = AAF()
        XMLRPC.__init__(self)

    def xmlrpc_add_file(self, cred_user, serveur, filename):
        """associe un fichier AAF à un serveur
        """
        try:
            id_serveur = int(serveur)
            self.parent.s_pool.get(cred_user, id_serveur)
        except (KeyError, ValueError):
            return 0, """serveur %s non retrouvé""" % str(serveur)
        try:
            self.aaf.add_file(filename, id_serveur)
        except:
            traceback.print_exc()
            return 0, u("Erreur lors de l'attribution du fichier \
au serveur %s" % str(id_serveur))
        return 1, "OK"

    def xmlrpc_del_file(self, cred_user, filename):
        """supprime l'association d'un fichier AAF à un serveur
        """
        # vérification des droits sur le serveur
        try:
            id_serveur = self.aaf.get_serveur(filename)
            self.parent.s_pool.get(cred_user, id_serveur)
        except (KeyError, ValueError):
            return 0, """serveur associé à %s non retrouvé""" % str(filename)
        try:
            self.aaf.del_file(filename)
        except:
            traceback.print_exc()
            return 0, "Impossible de supprimer l'entrée"
        return 1, "OK"

    def xmlrpc_get_list(self, cred_user, serveur):
        """renvoie la liste des fichiers associés à un serveur"""
        try:
            id_serveur = int(serveur)
            self.parent.s_pool.get(cred_user, id_serveur)
        except (KeyError, ValueError):
            return 0, """serveur %s non retrouvé""" % str(serveur)
        try:
            files = self.aaf.list_files(id_serveur)
        except:
            traceback.print_exc()
            return 0, "Erreur de recherche des fichiers associés au serveur"
        return 1, u(files)

    def xmlrpc_notify_upload(self, cred_user, filename):
        """préviens Zéphir qu'un fichier a été mis à jour
        Envoie le fichier au serveur associé si besoin
        """
        if not os.path.isfile(os.path.join(AAF_DIR, filename)):
            return 0, u("Fichier non retrouvé sur Zéphir : %s" % filename)
        # recherche du serveur associé
        try:
            id_serveur = self.aaf.get_serveur(filename)
            serv = self.parent.s_pool[int(id_serveur)]
        except (KeyError, ValueError):
            return 0, """serveur associé à %s non retrouvé""" % str(filename)
        # si serveur trouvé, on regarde si le contenu du fichier a changé
        def_hash = self.aaf.check_hash(filename)
        return def_hash.addBoth(self.check_aaf_callb, filename, serv)

    def xmlrpc_notify_upload_annuel(self, cred_user, filename):
        """
        idem que xmlrpc_notify_upload mais avec demande d'importation
        en mode "annuel"
        """
        if not os.path.isfile(os.path.join(AAF_DIR, filename)):
            return 0, u("Fichier non retrouvé sur Zéphir : %s" % filename)
        # recherche du serveur associé
        try:
            id_serveur = self.aaf.get_serveur(filename)
            serv = self.parent.s_pool[int(id_serveur)]
        except (KeyError, ValueError):
            return 0, """serveur associé à %s non retrouvé""" % str(filename)
        # si serveur trouvé, on regarde si le contenu du fichier a changé
        def_hash = self.aaf.check_hash(filename)
        return def_hash.addBoth(self.check_aaf_callb, filename, serv, mode='annuel')

    def check_aaf_callb(self, result, filename, serv, mode='maj'):
        if result == True:
            # envoi nécessaire
            archive = 'import_%s' % filename
            serveur_dir = serv.get_confdir()
            # copie dans le répertoire du serveur
            if os.path.isfile(os.path.join(serveur_dir, archive)):
                os.unlink(os.path.join(serveur_dir, archive))
            shutil.copy(os.path.join(AAF_DIR, filename),
                        os.path.join(serveur_dir, archive))
            # calcul et stockage d'un hash de l'archive
            cmd_checksum = """cd %s;/usr/bin/sha256sum -b %s > %s.sha""" \
% (serveur_dir, archive, archive)
            os.system(cmd_checksum)
            # ajout de l'archive à la file d'attente uucp
            try:
                id_uucp = "%s-%s" % (str(serv.get_rne()), str(serv.id_s))
                uucp_pool.add_file(id_uucp, os.path.join(serveur_dir, archive))
                # on met en attente la commande de traitement du fichier sur le
                # serveur client (si plusieurs appels, elle remplace l'ancienne)
                uucp_pool.add_cmd(id_uucp, "zephir_client import_aaf {}".format(mode))
            except UUCPError as err:
                return 0, u("Erreur d'envoi du fichier par uucp: %s" % str(err))
        return 1, "OK"

    def xmlrpc_confirm_transfer(self, cred_user, id_serveur, dict_hash):
        """vérifie que les fichiers transférés sont bien pris en compte
        et met à jour leur hash dans la base de données
        """
        try:
            serv = self.parent.s_pool[int(id_serveur)]
        except:
            return 0, u("Serveur invalide : %s" % str(id_serveur))
        errors = []
        for fic_aaf, hash_res in list(dict_hash.items()):
            # comparaison au fichier hash stocké
            fic_hash = os.path.join(serv.get_confdir(), "%s.sha" % fic_aaf)
            if not os.path.isfile(fic_hash):
                errors.append(fic_aaf)
            else:
                hash_data = open(fic_hash).read().split('\n')
                # vérification de la correspondance
                if not to_bytes(hash_res).strip() in to_bytes(hash_data):
                    errors.append(fic_aaf)
                    # demander une relance de la copie au prochain appel ?
                else:
                    # vérification ok, on met à jour le checksum dans
                    # la base de données. Le fichier ne sera plus envoyé
                    fic_ori = fic_aaf.lstrip('import_')
                    self.aaf.update_hash(fic_ori, to_bytes(hash_res).decode().split()[0])
                    # suppression des fichiers inutiles
                    os.unlink(os.path.join(serv.get_confdir(), "%s.sha" % fic_aaf))
                    os.unlink(os.path.join(serv.get_confdir(), fic_aaf))
        if errors != []:
            return 0, u(errors)
        return 1, "OK"
