# -*- coding: utf-8 -*-
###########################################################################
#
# Eole NG - 2011
# Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon)
# Licence CeCill  http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html
# eole@ac-dijon.fr
#
###########################################################################
"""
 librairie pour le parsing des fichiers de données AAF

 - parse_aaf_eleves : parsing des fichiers XML issus de AAF
 - parse_aaf_prof   : parsing des fichiers XML issus de AAF

"""
from scribe.eoletools import replace_cars, replace_more_cars, \
not_empty, is_empty, formate_civilite
from scribe.importation import log
from scribe.importation.config import DEBUG_NUM
from scribe.storage import Eleve, \
Responsable, Adresse, JointureResponsableEleve, \
Classe, Niveau, Enseignant, Administratif, \
EnsClasse, JointureClasseEnseignant, JointureGroupeEleve, JointureGroupeEnseignant, JointureMatiereEnseignant, \
Matiere, \
Groupe, Service
from scribe.parsing.tools import parse_xml
from scribe.parsing.nomenclature import MATIERES

##########################################
    # Extraction AAF Elèves & Responsables
# Fichiers :
# - ENT_$RNE_Complet_$DATE_Eleve_0000.xml
# - ENT_$RNE_Complet_$DATE_PersRelEleve_0000.xml
##########################################
def parse_aaf_eleves(store, eleve_file):
    """
    parsing des élèves depuis AAF
    """
    num = 0
    log.infolog("Lecture des élèves...", title=True)
    context, _ = parse_xml(eleve_file)
    # nb : la date de naissance est au format jj/mm/aaaa
    mapping = {'sn':'nom',
               'givenName':'prenom',
               'ENTPersonDateNaissance':'date',
               'personalTitle':'civilite',
               # FIXME elenoet
               'ENTEleveINE':'ine',
               'ENTPersonJointure':'numero',
               'ENTPersonAutresPrenoms':'prenom2',
               'ENTPersonNomPatro':'nom_patronymique',
               # nouveaux attributs
               'ENTEleveStructRattachId':'rattachid',
               'ENTEleveRegime':'regime',
    }
    groupe_mapping = {'ENTEleveMEF':'mef_id',
                      'ENTEleveLibelleMEF':'mef',
                      "ENTEleveNivFormation":'niveau',
                      "ENTEleveFiliere":'filiere',
                      "ENTEleveClasses":'classe',
    }
    for _, televe in context:
        _type = televe.find('operationalAttributes/attr/value').text
        if _type != 'Eleve':
            log.infolog("%s pas un élève :(" % _type)
            continue
        #Attention : identifier/id == ENTPersonJointure
        eleid = televe.find('identifier/id').text
        eleve = {'int_id':str(eleid)}
        groupe = {}
        responsables = []
        relations = []
        options = []
        for attr in televe.findall('attributes/attr'):
            balise = attr.attrib['name']
            if balise in mapping:
                # WARNING : que des mono-valuées ?
                clean_text = replace_more_cars(attr.find('value').text)
                cle = mapping[balise]
                eleve[cle] = str(clean_text)
            elif balise == 'ENTEleveAutoriteParentale':
                for resp in attr.findall('value'):
                    responsables.append(str(resp.text))
            elif balise == 'ENTElevePersRelEleve':
                # stockage des relations pour #24829
                relations = attr.findall('value')
            elif balise in groupe_mapping:
                clean_text = replace_cars(attr.find('value').text)
                cle = groupe_mapping[balise]
                groupe[cle] = str(clean_text)
            elif balise == 'ENTEleveGroupes':
                # options enseignées
                for tgrp in attr.findall('value'):
                    if tgrp.text is not None and '$' in tgrp.text:
                        options.append(str(replace_cars(tgrp.text.split('$')[1])))
            elif balise == 'ENTEleveEnseignements':
                # enseignements suivis (multi)
                enst = set()
                for ens in attr.findall('value'):
                    if ens.text is not None:
                        enst.add(replace_more_cars(ens.text))
                eleve['enseignements'] = str(list(enst))

        if len(responsables) == 0:
            # aucun responsable trouvé avec "ENTEleveAutoriteParentale" #24829
            for rel in relations:
                if rel.text is not None:
                    relation = rel.text.split('$')
                    # ENTElevePersRelEleve : 4ème valeur = code responsable légal
                    if relation[3] == '1':
                        responsables.append(str(relation[0]))

        # ENTPersonJointure #10027
        eleve['entpersonjointure'] = "AAF$%s" % eleve['int_id']
        #pré-traitement
        if not_empty(eleve, 'civilite'):
            eleve['civilite'] = str(formate_civilite(str(eleve['civilite'])))
        else:
            log.infolog("Attribution arbitraire d'une civilité à l'élève : %s %s" % (
                         str(eleve['prenom']), str(eleve['nom'])))
            eleve['civilite'] = '1'
        # création de l'élève
        try:
            my_eleve = Eleve(**eleve)
            # niveau (MEF)
            niveau = groupe['filiere']
            my_niveau = store.findOrCreate(Niveau, nom=niveau)
            # classe (format AAF : "numero$classe")
            classe = groupe['classe'].split('$')[1]
            my_classe = store.findOrCreate(Classe, nom=classe,
                                             niveau=my_niveau)
            # affectation de l'élève
            my_eleve.classe = my_classe
            my_eleve.niveau = my_niveau

            store.add(my_eleve)
            num += 1
            if num % DEBUG_NUM == 0:
                log.debuglog("%d élèves lus..." % num)
        except TypeError as msg:
            log.errorlog("Erreur sur l'élève %s : %s" % (eleid, msg))
            continue
        # jointure élèves-responsables
        for id_resp in responsables:
            try:
                my_resp = store.query(Responsable).filter_by(int_id=id_resp).first()
                if my_resp is not None:
                    # FIXME : attributs supplémentaires ?
                    store.add(JointureResponsableEleve(eleve=my_eleve, responsable=my_resp))
            except Exception as err:
                log.infolog("erreur jointure eleve-resp", err)
        # inscription aux options
        for option in options:
            my_option = store.findOrCreate(Groupe, nom=option)
            store.add(JointureGroupeEleve(groupe=my_option, eleve=my_eleve))

    log.infolog("TOTAL : %d élèves" % num)

def parse_aaf_responsables(store, responsables_file):
    """
    parsing des responsables depuis AAF
    """
    num = 0
    log.infolog("Lecture des responsables...", title=True)
    context, _ = parse_xml(responsables_file)
    mapping = {'sn':'nom',
               'givenName':'prenom',
               'ENTPersonDateNaissance':'date',
               'personalTitle':'civilite',
               #'ENTPersonNomPatro':'nom_patronymique', #FIXME : différent de sn ?
               'homePhone':'telephone',
               'telephoneNumber':'tel_pro',
               'mobile':'tel_portable',
               'mail':'mail',

    }
    mapping_adresse = {'ENTPersonAdresse':'adresse',
                       'ENTPersonCodePostal':'code_postal',
                       'ENTPersonVille':'ville',
                       'ENTPersonPays':'pays',
    }
    for _, tresp in context:
        _type = tresp.find('operationalAttributes/attr/value').text
        if _type != 'PersRelEleve':
            log.infolog("%s n'est pas un responsable :(" % _type)
            continue
        #Attention : identifier/id == ENTPersonJointure
        respid = tresp.find('identifier/id').text
        responsable = {'int_id':str(respid)}
        adresse = {'int_id':str(respid)}
        for attr in tresp.findall('attributes/attr'):
            balise = attr.attrib['name']
            if balise in mapping:
                clean_text = replace_more_cars(attr.find('value').text)
                cle = mapping[balise]
                responsable[cle] = str(clean_text)
            elif balise in mapping_adresse:
                clean_text = replace_cars(attr.find('value').text)
                cle = mapping_adresse[balise]
                adresse[cle] = str(clean_text)
                if balise == 'ENTPersonAdresse':
                    adresse[cle] = adresse[cle].replace('$', '\n').rstrip()
        # ENTPersonJointure #10027
        responsable['entpersonjointure'] = "AAF$%s" % responsable['int_id']
        if not_empty(responsable, 'civilite'):
            responsable['civilite'] = str(formate_civilite(str(responsable['civilite'])))
        try:
            resp = Responsable(**responsable)
            store.add(resp)
            num += 1
            if num % DEBUG_NUM == 0:
                log.debuglog("%d responsables lus..." % num)
        except TypeError as msg:
            log.infolog("Erreur sur le responsable %s : %s" % (respid, msg))
        try:
            addr = Adresse(**adresse)
            store.add(addr)
            # affectation de l'adresse au responsable
            resp.adresse = addr
        except TypeError as msg:
            log.infolog("Erreur sur l'adresse de %s : %s" % (respid, msg))
    log.infolog("TOTAL : %d responsables" % num)


##########################################
# Extraction AAF Professeurs + Administratifs ?
# Fichier :
# - ENT_$RNE_Complet_$DATE_PersEducNat_0000.xml
##########################################
def parse_aaf_profs(store, profs_file):
    """
    parsing des professeurs depuis AAF
    """
    num = 0
    log.infolog("Lecture des personnels...", title=True)
    context, _ = parse_xml(profs_file)
    mapping = {'sn':'nom',
               'givenName':'prenom',
               'ENTPersonDateNaissance':'date',
               'personalTitle':'civilite',
               'ENTPersonNomPatro':'nom_patronymique',
               'mail':'mail',
    }
    for _, tprof in context:
        _type = tprof.find('operationalAttributes/attr/value').text
        if _type != 'PersEducNat':
            log.infolog("%s n'est pas un personnel :(" % _type)
            continue
        #Attention : identifier/id == ENTPersonJointure
        administratif = False
        profid = tprof.find('identifier/id').text
        professeur = {'int_id':str(profid)}
        classes = []
        matieres = []
        options = []
        principal = []
        groupe = None
        for attr in tprof.findall('attributes/attr'):
            balise = attr.attrib['name']
            if balise in mapping:
                clean_text = replace_more_cars(attr.find('value').text)
                cle = mapping[balise]
                professeur[cle] = str(clean_text)
            elif balise in ['ENTAuxEnsClasses', 'ENTAuxEnsClassesMatieresDate']:
                # classes enseignées
                for tclasse in attr.findall('value'):
                    if tclasse.text is not None and '$' in tclasse.text:
                        nom = str(replace_cars(tclasse.text.split('$')[1]))
                        my_classe = store.findOrCreate(EnsClasse, nom=nom)
                        classes.append(my_classe)
            elif balise == 'ENTAuxEnsClassesPrincipal':
                # professeur principal
                for tclasse in attr.findall('value'):
                    if tclasse.text is not None and '$' in tclasse.text:
                        nom = str(replace_cars(tclasse.text.split('$')[1]))
                        my_classe = store.findOrCreate(EnsClasse, nom=nom)
                        principal.append(my_classe)
            elif balise == 'ENTAuxEnsMatiereEnseignEtab':
                # matieres enseignees
                for tmat in attr.findall('value'):
                    if tmat.text is not None and '$' in tmat.text:
                        desc = tmat.text.split('$')[1]
                        # mapping des matières selon la nomenclature Sconet
                        if desc in MATIERES:
                            mat = {'nom':str(replace_cars(MATIERES[desc])),
                                   'description':str(replace_cars(desc))}
                        else:
                            mat = {'nom':str(replace_cars(desc))}
                        my_matiere = store.findOrCreate(Matiere, **mat)
                        matieres.append(my_matiere)
            elif balise in ['ENTAuxEnsGroupes', 'ENTAuxEnsGroupesMatieresDate']:
                # options enseignées
                for tgrp in attr.findall('value'):
                    if tgrp.text is not None and '$' in tgrp.text:
                        nom = str(replace_cars(tgrp.text.split('$')[1]))
                        my_groupe = store.findOrCreate(Groupe, nom=nom)
                        options.append(my_groupe)
            elif balise == 'ENTAuxEnsCategoDiscipline':
                # Catégories de disciplines de poste (multi)
                enst = []
                for ens in attr.findall('value'):
                    if ens.text is not None and '$' in ens.text:
                        enst.append(replace_more_cars(ens.text))
                professeur['disciplines'] = str(enst)
            elif balise == 'ENTPersonFonctions':
                # groupes pour les administratifs
                for tgrp in attr.findall('value'):
                    if tgrp.text is not None and '$' in tgrp.text:
                        fonctions = tgrp.text.split('$')
                        # FIXME: "sans objet" #3926
                        if fonctions[1] not in ['-', 'ENS']:
                            administratif = True
                            nom = str(replace_cars(fonctions[1]))
                            desc = str(replace_cars(fonctions[2]))
                            groupe = store.findOrCreate(Service, nom=nom, description=desc)
            #elif balise == 'PersEducNatPresenceDevantEleves':
            #    if attr.find('value').text == 'N':
            #        administratif = True
        # ENTPersonJointure #10027
        professeur['entpersonjointure'] = "AAF$%s" % professeur['int_id']
        if not_empty(professeur, 'civilite'):
            professeur['civilite'] = str(formate_civilite(str(professeur['civilite'])))
        else:
            # civilité arbitraire #2599
            log.infolog("Attribution arbitraire d'une civilité au personnel : %s %s" % (
                         str(professeur['prenom']), str(professeur['nom'])))
            professeur['civilite'] = '1'
        if is_empty(professeur, 'date'):
            # date de naissance arbitraire #1730
            professeur['date'] = '01/01/0001'
        if not administratif:
            # c'est un enseignant
            try:
                prof = Enseignant(**professeur)
                store.add(prof)
                num += 1
            except Exception as msg:
                log.infolog("Erreur sur l'enseignant %s : %s" % (profid, msg))
            # inscription aux classes
            for classe in classes:
                if classe in principal:
                    is_principal = True
                else:
                    is_principal = False
                store.add(JointureClasseEnseignant(classe=classe,
                        enseignant=prof, profprincipal=is_principal))
            # inscription aux matieres
            for matiere in matieres:
                store.add(JointureMatiereEnseignant(matiere=matiere,
                        enseignant=prof))
            # inscription aux options
            for option in options:
                store.add(JointureGroupeEnseignant(groupe=option, enseignant=prof))

        else:
            # c'est un administratif
            if 'disciplines' in professeur:
                del professeur['disciplines']
            try:
                admin = Administratif(**professeur)
                if groupe is not None:
                    admin.groupe = groupe
                store.add(admin)
                num += 1
            except Exception as msg:
                log.infolog("Erreur sur le personnel %s : %s" % (profid, msg))
        if num % DEBUG_NUM == 0:
            log.debuglog("%d personnels lus..." % num)
    log.infolog("TOTAL : %d personnels" % num)

