# -*- coding: utf-8 -*-
###########################################################################
#
# Eole NG - 2009
# 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

 - parse_be1d_eleves : parsing des fichiers CSV issus de ONDE/BE1D

"""
from csv import DictReader, reader
from sqlalchemy import and_
from scribe.eoletools import replace_cars, convert_file, formate_date, \
formate_civilite, replace_more_cars
from scribe.importation import log
from scribe.importation.config import DEBUG_NUM
from scribe.storage import Eleve, Niveau, Classe, Responsable, Adresse, JointureResponsableEleve


##########################################
# Extraction Be1d Elèves
# Fichier :
# - ecole.csv
##########################################
def parse_be1d_eleves(store, csvfile):
    """
    parsing des élèves depuis ONDE/BE1D
    """
    num = 0
    log.infolog("Lecture des élèves...", title=True)
    # Ensure UTF-8 file
    convert_file(csvfile)

    source = 'onde'
    # champs obligatoires
    onde_fields = ['Nom élève', 'Prénom élève', 'Date naissance', 'Sexe', 'INE',
                   'Niveau', 'Libellé classe']
    # FIXME ONDE : Nom d'usage élève;Cp1;Commune1;Pays1;Adresse2;Cp2;Commune2;Pays2;
    #Cycle;Identifiant classe;Attestation fournie;Autorisation associations;
    #Autorisation photo;Décision de passage
    be1d_fields = ['Nom Elève', 'Prénom Elève', 'Date naissance', 'Sexe',
                   'Niveau','Classe']
    reader = DictReader(open(csvfile), delimiter=';')
    # validation en-tête
    #ATTENTION : ça commence direct par le 1er élève
    data = next(reader)
    for field in onde_fields:
        if field not in data:
            msg = "Le champ \"%s\" n'est pas présent dans l'en-tête du fichier !" % field
            log.errorlog(msg)
            log.infolog("Essai avec l'ancien format BE1D")
            be1d_fields = ['Nom Elève', 'Prénom Elève', 'Date naissance', 'Sexe',
                           'Niveau','Classe']
            reader = DictReader(open(csvfile), delimiter=';')
            data = next(reader)
            for field in be1d_fields:
                if field not in data:
                    msg = "Le champ \"%s\" n'est pas présent dans l'en-tête du fichier !" % field
                    log.errorlog(msg)
                    log.errorlog(msg)
                    raise Exception(msg)
            source = 'be1d'
            break

    while True:
        eleve = {}
        if source == 'onde':
            eleve['prenom'] = str(replace_more_cars(data['Prénom élève']))
            eleve['nom'] = str(replace_more_cars(data['Nom élève']))
            eleve['ine'] = str(replace_more_cars(data['INE']))
            if eleve['ine']:
                eleve['numero'] = eleve['ine']
            else:
                log.infolog("INE non renseigné pour l'élève : %s %s" % (
                            str(eleve['prenom']), str(eleve['nom'])))
                eleve['numero'] = str(formate_date(data['Date naissance'], ''))
        else:
            eleve['prenom'] = str(replace_more_cars(data['Prénom Elève']))
            eleve['nom'] = str(replace_more_cars(data['Nom Elève']))
            #FIXME : trouver mieux comme numéro élève ?
            eleve['numero'] = str(formate_date(data['Date naissance'], ''))
        eleve['date'] = str(formate_date(data['Date naissance']))
        # pas d'identifiant interne au logiciel
        eleve['int_id'] = ''
        if data['Sexe'] == 'F':
            eleve['civilite'] = '3' #Mlle
        else:
            eleve['civilite'] = '1' #M.
        try:
            my_eleve = Eleve(**eleve)
            niveau = str(replace_cars(data['Niveau']))
            if not niveau:
                raise TypeError("niveau invalide")
            if source == 'onde':
                classe = str(replace_cars(data['Libellé classe']))
            else:
                classe = str(replace_cars(data['Classe']))
            if not classe:
                raise TypeError("classe invalide")
            my_niveau = store.findOrCreate(Niveau, nom=niveau)
            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
            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" % (data['Nom Elève'],
                                                         msg))
        try:
            data = next(reader)
        except StopIteration:
            break
    log.infolog("TOTAL : %d élèves" % num)
    store.flush()


##########################################
# Extraction Be1d Responsables
# Fichier :
# - parents.csv
##########################################
def parse_be1d_responsables(store, csvfile):
    """
    parsing des responsables depuis ONDE/BE1D
    """
    num = 0
    log.infolog("Lecture des responsables...", title=True)
    # fichier en UTF-8 ?
    convert_file(csvfile)
    # champs obligatoires
    fields = ["Nom responsable", "Prénom responsable", "Civilité Responsable",
              "Adresse responsable", "CP responsable", "Commune responsable",
              "Pays", "Courriel", "Téléphone domicile", "Téléphone travail",
              "Téléphone portable"]
    multi_fields = ["Nom de famille enfant", "Prénom enfant", "Classes enfants"]
    # champs inutilisés
    #"Nom usage responsable", "Nom d'usage enfant", "Numéro de poste"

    # on a des champs qui ont le même nom -> on ne peut pas utiliser DictReader :(
    csvreader = reader(open(csvfile), delimiter=';')
    # validation en-tête
    indice = {}
    header = next(csvreader)
    for field in fields:
        if field not in header:
            msg = "Le champ \"%s\" n'est pas présent dans l'en-tête du fichier !" % field
            log.errorlog(msg)
            raise Exception(msg)
        indice[field] = header.index(field)
    # indice le plus élevé parmi les champs obligatoires
    top = max(indice.values())
    for field in multi_fields:
        if field not in header:
            msg = "Le champ \"%s\" n'est pas présent dans l'en-tête du fichier !" % field
            log.errorlog(msg)
            raise Exception(msg)
        indice[field] = []
        for ind in range(len(header)):
            if header[ind] == field:
                indice[field].append(ind)
    # nombre de champs élève prévus dans le CSV
    num_eleves = len(indice["Nom de famille enfant"])

    mapping = { 'Nom responsable':'nom',
                'Prénom responsable':'prenom',
                'Civilité Responsable':'civilite',
                "Courriel":'mail',
                "Téléphone domicile":'telephone',
                "Téléphone travail":'tel_pro',
                "Téléphone portable":'tel_portable',
    }
    mapping_adresse = { "Adresse responsable":'adresse',
                        "CP responsable":'code_postal',
                        "Commune responsable":'ville',
                        "Pays":'pays',
    }

    for data in csvreader:
        ## entrée responsable
        if len(data) <= top:
            # ligne invalide
            continue
        responsable = {'int_id':''}
        for attr in mapping:
            clean_text = replace_more_cars(data[indice[attr]])
            cle = mapping[attr]
            responsable[cle] = str(clean_text)
        if not responsable['nom']:
            continue
        responsable['civilite'] = str(formate_civilite(responsable['civilite']))
        try:
            resp = Responsable(**responsable)
            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 : %s" % (responsable['prenom'],
                                                      responsable['nom'], msg))
            continue

        ## liens responsable - élève
        for num_eleve in range(num_eleves):
            try:
                nom = str(replace_more_cars(data[indice["Nom de famille enfant"][num_eleve]]))
                if not nom:
                    continue
                prenom = str(replace_more_cars(data[indice["Prénom enfant"][num_eleve]]))
                classe = str(replace_cars(data[indice["Classes enfants"][num_eleve]]))
            except IndexError:
                # cf. http://dev-eole.ac-dijon.fr/issues/638
                continue
            # recherche de l'élève :
            my_eleve = None
            my_eleves = [qr[0] for qr in store.query(Eleve, and_(Eleve.nom == nom,
                                                     Eleve.prenom == prenom))
                         if qr[1]]
            if len(my_eleves) == 0:
                # élève non trouvé
                log.infolog("Elève %s %s non touvé !" % (str(prenom), str(nom)))
                continue
            elif len(my_eleves) == 1:
                my_eleve = my_eleves[0]
            else:
                # homonymes -> on vérifie la classe
                for eleve in my_eleves:
                    if eleve.classe.nom == classe:
                        my_eleve = eleve
                        break
            if my_eleve is not None:
                store.add(JointureResponsableEleve(eleve=my_eleve,
                                         responsable=resp))

        ## entrée adresse
        adresse = {'int_id':''}
        for attr in mapping_adresse:
            clean_text = replace_cars(data[indice[attr]])
            cle = mapping_adresse[attr]
            adresse[cle] = str(clean_text)
        try:
            addr = Adresse(**adresse)
            # affectation de l'adresse au responsable
            resp.adresse = addr
        except TypeError as msg:
            log.infolog("Erreur sur l'adresse de %s %s : %s" % (responsable['prenom'],
                                                      responsable['nom'], msg))
    log.infolog("TOTAL : %d responsables" % num)
    store.flush()
