# -*- 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
#
# connecteur.py
#
# fonctions de connexion au backend Zephir pour création de rapports
# les fonctions convert et backend sont les mêmes que pour le frontend
#
###########################################################################
import xmlrpc.client
from zephir.config import charset

# encodage et conversions en encodage local
BACKEND_EXCEPTIONS = ['libpq.OperationalError','libpq.IntegrityError']

class BackendError(Exception):
    """Gère les erreurs provenant du backend xml-rpc
    """
    def __init__(self, msg=None):
        """Définition du message d'erreur
        """
        txt = """<p>Erreur provenant du backend XML-RPC<br/>
        <a href="javascript:history.back()">retour</a><br/></p>"""
        if msg :
            txt2 = """<p><b>Détail</b> : %s </p>""" % msg
            self.msg = txt + txt2
        else :
            self.msg = txt

    def __str__(self):
        return self.msg

class DatabaseError(Exception):
    """Différencie une erreur backend simple
    d'un pb d'intégrité référentielle
    """
    def __init__(self, msg=None):
        txt = """Interdiction due à un problème d'intégrité référentielle dans la base de données
        """
        if msg:
            txt2 = """, dans la table : <b>""" + msg + "</b>"
            self.msg = txt + txt2
        else :
            self.msg = "<p>" + txt + "</p>"

    def __str__(self):
        return self.msg

def convert(objet):
    """Transforme les objets unicode contenus dans un objet en chaines
    """
    if type(objet) == list:
        l = []
        for item in objet:
            l.append(convert(item))
        return l
    if type(objet) == dict:
        dico={}
        for cle in list(objet.keys()):
            dico[cle] = convert(objet[cle])
        return dico
    return objet

def backend(liste_backend):
    """Récupère les codes et les messages d'erreur système
    """
    # premier terme de la liste
    return_code = liste_backend[0]
    # le contenu à récupérer... si tout va bien
    # sinon, c'est une exception ou un message d'erreur
    retour = liste_backend[1]
    try:
        assert liste_backend[2]
        database_msg = liste_backend[2]
    except:
        database_msg = ""

    if not return_code :
        # quelque chose close
        if retour in BACKEND_EXCEPTIONS :
            # extrait la table concernée du message d'erreur
            database_msg = database_msg.split("from")[1]
            raise DatabaseError(database_msg)
        else:
            # tout va mal
            raise BackendError()
    else :
        # tout va bien
        retour = convert(retour)
        return retour

def tri_etab(x,y):
    if x[1].upper() > y[1].upper():
        return 1
    elif x[1].upper() == y[1].upper():
        return 0
    else:
        return -1

class Nomenclature:
    """utilitaires de récupérations de dictionnaires clef-libellé (nomenclatures)
    """

    def __init__(self, server, rne_rapport=None):
        self.server = server
        try:
            # récupération des données
            self.variante = backend(self.server.modules.get_variante())
            self.module_list = backend(self.server.modules.get_module())
            if rne_rapport != None:
                self.etab_list = backend(self.server.etabs.get_etab(rne_rapport))
            else:
                self.etab_list = backend(self.server.etabs.get_etab())
            self.types = backend(self.server.etabs.get_types())[0]
        except BackendError:
            raise BackendError("erreur lors de la récupération des données")

    def get_variante(self):
        """Dictionnaire clefs,libelle pour les variantes
        """
        libelle = {}
        for v in self.variante :
            libelle[v['id']] = xmlrpc.client.escape(v['libelle'])
        return libelle

    def get_variante_module(self,id_module):
        """Dictionnaire clefs, libelle pour les variantes d'un module considéré
        """
        libelle = {}
        for v in self.variante :
            if int(v['module']) == int(id_module) :
                libelle[v['id']] = xmlrpc.client.escape(v['libelle'])
        return libelle

    def get_module(self):
        """Dictionnaire clef,libelle pour les modules
        """
        # construction du dico des libellés
        dico_libelle = {}
        for module in self.module_list :
            dico_libelle[module['id']] = xmlrpc.client.escape(module['libelle'])
        return dico_libelle

    def get_etab(self):
        """Dictionnaire clef,libelle pour les établissements
        """
        # construction du dico des libellés
        dico_libelle = {}
        for etab in self.etab_list :
            dico_libelle[etab['rne']] = xmlrpc.client.escape(etab['libelle'])
        return dico_libelle

    def get_types(self):
        """Types d'établissement
        """
        return self.types

class Connecteur:
    """Gère les appels au backend
    """
    def __init__(self,server,rne_rapport=None):
        self.server = server #xmlrpclib.Server(ZEPHIR)
        self.nomenc=Nomenclature(self.server, rne_rapport)
        self.rne_rapport = rne_rapport
        try:
            if rne_rapport is not None:
                self.liste_serveurs = backend(self.server.serveurs.groupe_serveur({'rne':rne_rapport}))
            else:
                self.liste_serveurs = backend(self.server.serveurs.get_serveur())
            self.serv_etabs = {}
            self.etat_serv = {}
            for serveur in self.liste_serveurs:
                # stockage de l'id du serveur dans l'etablissement correspondant
                if serveur["rne"] in self.serv_etabs:
                    self.serv_etabs[serveur["rne"]].append(serveur['id'])
                else:
                    self.serv_etabs[serveur["rne"]] = [serveur['id']]
                # on récupère l'état du serveur
                liste_etat = []
                try:
                    try:
                        # le dictionnaire d'état est stocké sous forme de chaîne dans le champs params
                        etat2 = eval(serveur['params'])
                    except:
                        etat2 = backend(self.server.serveurs.get_status(serveur['id']))
                    if etat2['cle_ok'] == 1:
                        # serveur enregistré, on vérifie son état
                        for cle in list(etat2.keys()):
                            etat = etat2[cle]
                            if type(etat) == list:
                                if len(etat) == 3:
                                    if etat[0] == 0:
                                        liste_etat.append("erreur rapportée par zephir (cf. page d'état)")
                        try:
                            etat1 = int(serveur["etat"])
                            if etat1 == 2:
                                liste_etat.append("contact perdu avec le serveur")
                            if etat1 in [3,4]:
                                liste_etat.append("file d'attente bloquée (problème uucp ou ssh)")
                            if etat1 in [0,4]:
                                liste_etat.append("erreur reportée par le serveur (cf. page de surveillance)")
                        except:
                            liste_etat.append("pas de statistiques reçues")
                    else:
                        liste_etat.append("pas de serveur enregistré")
                except:
                    pass

                self.etat_serv[serveur['id']] = liste_etat

        except BackendError:
            raise BackendError("erreur lors de la récupération des données")

    def module(self, id_module=None):
        """Module ou liste de modules
        """
        if id_module:
            for module in self.nomenc.modules_list:
                if int(module['id']) == int(id_module):
                    return module
        return self.nomenc.module_list

    def dict_module(self):
        """Dictionnaire clef-libelle pour les modules
        """
        return self.nomenc.get_module()

    def nom_module(self, id_module):
        """Libellé d'un module
        """
        dico_module = self.dict_module()
        return xmlrpc.client.escape(dico_module[id_module])
        # return self.module(id_module)['libelle']

    def get_variante(self,id_variante=None):
        """Variante d'un module
        """
        if id_variante:
            for variante in self.nomenc.variante:
                if int(variante['id']) == int(id_variante):
                    return [variante]
        return self.nomenc.variante

    def _dict_variante(self, id_module):
        """dictionnaire des variantes d'un module
        """
        return self.nomenc.get_variante_module(id_module)

    def id_variante(self, id_module):
        """Liste des id des variantes d'un module
        """
        return list(self._dict_variante().keys())

    def nom_variante(self, id_variante):
        """Libellé d'une variante
        """
        variante = self.nomenc.get_variante()
        return variante[id_variante]

    def get_serveur(self, id_serveur=None):
        """Description d'un serveur
        """
        res={}
        if id_serveur:
            for serveur in self.liste_serveurs:
                if int(serveur['id']) == int(id_serveur):
                    for cle in list(serveur.keys()):
                        if cle != "libelle":
                            res[cle]=xmlrpc.client.escape(serveur[cle])
                    return serveur

    def nom_serveur(self, id_serveur):
        """Libellé d'un serveur
        """
        for serveur in self.liste_serveurs:
            if int(serveur['id']) == int(id_serveur):
                return xmlrpc.client.escape(serveur['libelle'])

    def libelle_serveur_etab(self, rne):
        """Liste des libellés des serveurs d'un établissement
        """
        list = []
        for id in self.id_serveur_etab(rne):
            string = self.nom_serveur(id) + " (%s)" % id
            if self.etat_serv[id] != []:
                string += xmlrpc.client.escape(" : %s" % ", ".join(self.etat_serv[id]))
            list.append(string)
        else:
            etat = ""

        return list

    def id_serveur_etab(self, rne):
        """Liste des id des serveurs d'un établissement
        """
        if rne in self.serv_etabs:
            return self.serv_etabs[rne]
        else:
            return []

    def get_etab(self,rne):
        """Détail d'un établissement
        """
        for etab in self.nomenc.etab_list:
            if etab['rne'].upper() == rne.upper():
                # remplace le type d'etab par son libellé
                etab['type'] = xmlrpc.client.escape(self.nom_type(str(etab['type'])))
                return etab
        return {}

    def _dict_etab(self):
        """Nomenclature etab
        """
        return self.nomenc.get_etab()

    def id_etab(self):
        """Liste des rne des etablissements
        """
        dico=list(self._dict_etab().items())
        dico.sort(key=tri_etab)
        liste=[]
        for rne in dico:
            liste.append(rne[0])
        return liste

    def noms_etab(self):
        """liste des noms des etablissements
        """
        dico=list(self._dict_etab().items())
        dico.sort(key=tri_etab)
        liste=[]
        for rne in dico:
            liste.append(xmlrpc.client.escape("%s (%s)" % (rne[1],rne[0])))
        return liste
        #return self._dict_etab().values()

    def nom_etab(self, rne):
        """libellé d'un établissement
        """
        return xmlrpc.client.escape(self._dict_etab()[rne])

    def _dict_type(self):
        """Nomenclature des types d'etab
        """
        return self.nomenc.get_types()

    def nom_type(self, type):
        """libelle d'un type d'etab
        """
        return xmlrpc.client.escape(self._dict_type()[type])

# FIXME ce qu'il faut récupérer concernant les services :
# la liste des services pour chaque module

    def get_service(self, id_module):
        """Liste des services d'un module
        """
        return backend(self.server.services.get_service_module(id))

if __name__ == "__main__" :
    # print Connecteur().get_serveur(178)
    print(Connecteur().module())
    # print Connecteur().services(39)
    # print Connecteur().service_module(13)
    # print Connecteur().get_variante_module(13)
    # print Connecteur().get_etab("qsd")
    # print Connecteur().nom_etab()
    # print Connecteur().nom_types()
    # print Connecteur().dict_module()
    # print Connecteur().nom_module(3)
    pass
