# -*- coding: utf-8 -*-
###########################################################################
#
# Eole NG - 2010
# 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_csv_eleves : parsing des fichiers CSV/Scribe élèves
 - parse_csv_profs  : parsing des fichiers CSV/Scribe enseignants
 - parse_csv_administratifs : parsing des fichiers CSV/Scribe personnels
 - parse_csv_invites : parsing des fichiers CSV/Scribe comptes invités
"""
import io
from csv import DictReader
from scribe.eoletools import convert_file, replace_cars, replace_more_cars, \
    valid_password
from scribe.importation import log
from scribe.importation.config import DEBUG_NUM, NO_USERNAME_IN_PASSWORD
from scribe.storage import Eleve, Niveau, Classe, Enseignant, Administratif, \
    Invite, EnsClasse, Groupe, JointureGroupeEleve, JointureGroupeEnseignant, JointureClasseEnseignant
from fichier import passwd

def read_csv(csvfile, fields):
    """
    ouverture et test du fichier CSV
    """
    msg_format = "{0}<br/>Le fichier CSV doit être au format UTF8 sans BOM avec \";\" comme séparateur."
    try:
        # fichier en UTF-8 ?
        encoding_found = convert_file(csvfile)
        # In Python 2, the open() function takes no encoding argument
        reader = DictReader(io.open(csvfile, 'r', encoding=encoding_found), delimiter=';')
    except Exception as err:
        log.errorlog(str(err))
        raise Exception(msg_format.format(str(err)))
    # validation en-tête
    # ATTENTION : ça commence direct par le 1er enregistrement
    try:
        data = next(reader)
    except Exception as err:
        log.errorlog(str(err))
        raise Exception(msg_format.format(str(err)))
    for field in 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)
            raise Exception(msg_format.format(msg))
    return reader, data


def check_date(date):
    """
    Vérifie le format de date envoyé
    """
    ma_date = date.replace('/', '')
    if len(ma_date) != 8:
        raise Exception("format de date incorrect : {0}".format(date))
    try:
        int(ma_date)
    except ValueError:
        raise Exception("format de date incorrect : {0}".format(date))
    return date


def process_force_login(user, data):
    """
    traitement spécifique pour les identifiants et mots de passe forcés
    """
    if 'login' in data and data['login']:
        user['force_login'] = str(replace_more_cars(data['login']))
        if 'password' in data and data['password']:
            password = data['password']
            if valid_password(password):
                # If we need to look for the username in password
                if NO_USERNAME_IN_PASSWORD == "non":
                    user['force_password'] = str(password)
                else:
                    if passwd.password_is_valid(data['login'], password, 0, 0):
                        # Force the password when it doesn't contain the login
                        user['force_password'] = str(password)
                    else:
                        # Send error message and don't force the password.
                        msg = "Le mot de passe ne peut pas contenir le nom d'utilisateur ({0})".format(data['login'])
                        log.errorlog(msg)

            else:
                msg = "Mot de passe proposé trop faible pour l'utilisateur : {}"
                log.errorlog(msg.format(user['force_login']))


##########################################
# Extraction CSV Elèves (version 2)
# Fichier :
# - eleves.csv
##########################################
def parse_csv_eleves(store, csvfile):
    """
    parsing des élèves
    """
    num = 0
    log.infolog("Lecture des élèves...", title=True)
    # champs obligatoires
    fields = ['numero', 'nom', 'prenom', 'sexe', 'date',
              'classe', 'niveau']
    # champs optionnels : ['login', 'password', 'options']
    reader, data = read_csv(csvfile, fields)
    while True:
        eleve = {}
        eleve['numero'] = str(data['numero'])
        eleve['int_id'] = ''
        eleve['nom'] = str(replace_more_cars(data['nom']))
        eleve['prenom'] = str(replace_more_cars(data['prenom']))
        if data['sexe'] == 'F':
            eleve['civilite'] = '3' #Mlle
        else:
            eleve['civilite'] = '1' #M.
        eleve['date'] = check_date(str(data['date']))
        # champs facultatifs
        options = data.get('options', '').split('|')

        # login/mot de passe forcés
        process_force_login(eleve, data)

        try:
            niveau = str(replace_cars(data['niveau']))
            if not niveau:
                raise TypeError("niveau invalide")
            classe = str(replace_cars(data['classe']))
            if not classe:
                raise TypeError("classe invalide")
            my_eleve = Eleve(**eleve)
            store.add(my_eleve)
            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
            # association élève-options
            for option in options:
                if option != '':
                    nom = str(replace_cars(option))
                    groupe = store.findOrCreate(Groupe, nom=nom)
                    store.add(JointureGroupeEleve(groupe=groupe, eleve=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" % (data['numero'], msg))
        try:
            data = next(reader)
        except StopIteration:
            break
    log.infolog("TOTAL : %d élèves" % num)
    store.flush()


##########################################
# Extraction CSV Enseignants (version 2)
# Fichier :
# - enseignants.csv
##########################################
def parse_csv_profs(store, csvfile):
    """
    parsing des enseignants
    """
    num = 0
    log.infolog("Lecture des enseignants...", title=True)
    # champs obligatoires
    fields = ['numero', 'nom', 'prenom', 'sexe', 'date']
    # champs optionnels : ['login', 'password', 'classes', 'options']
    reader, data = read_csv(csvfile, fields)
    while True:
        professeur = {}
        professeur['int_id'] = str(data['numero'])
        professeur['nom'] = str(replace_more_cars(data['nom']))
        professeur['prenom'] = str(replace_more_cars(data['prenom']))
        if data['sexe'] == 'F':
            professeur['civilite'] = '2' #Mme
        else:
            professeur['civilite'] = '1' #M.
        professeur['date'] = check_date(str(data['date']))
        # champs facultatifs
        classes = data.get('classes', '').split('|')
        options = data.get('options', '').split('|')

        # login/mot de passe forcés
        process_force_login(professeur, data)

        try:
            prof = Enseignant(**professeur)
            store.add(prof)
            num += 1
        except Exception as msg:
            log.infolog("Erreur sur l'enseigant %s : %s" % (data['numero'], msg))
        else:
            # association enseignant-classes
            for classe in classes:
                if classe != '':
                    nom = str(replace_cars(classe))
                    my_classe = store.findOrCreate(EnsClasse, nom=nom)
                    store.add(JointureClasseEnseignant(classe=my_classe,
                            enseignant=prof, profprincipal=False))
            # association enseignant-options
            for option in options:
                if option != '':
                    nom = str(replace_cars(option))
                    groupe = store.findOrCreate(Groupe, nom=nom)
                    store.add(JointureGroupeEnseignant(groupe=groupe, enseignant=prof))
        if num % DEBUG_NUM == 0:
            log.debuglog("%d enseignants lus..." % num)
        try:
            data = next(reader)
        except StopIteration:
            break
    log.infolog("TOTAL : %d enseignants" % num)
    store.flush()


##########################################
# Extraction CSV Personnels administratifs
# Fichier :
# - personnels.csv
##########################################
def parse_csv_administratifs(store, csvfile):
    """
    parsing des personnels
    """
    num = 0
    log.infolog("Lecture des personnels...", title=True)
    # champs obligatoires
    fields = ['numero', 'nom', 'prenom', 'sexe', 'date']
    # champs optionnels : ['login', 'password']
    reader, data = read_csv(csvfile, fields)
    while True:
        professeur = {}
        professeur['int_id'] = str(data['numero'])
        professeur['nom'] = str(replace_more_cars(data['nom']))
        professeur['prenom'] = str(replace_more_cars(data['prenom']))
        if data['sexe'] == 'F':
            professeur['civilite'] = '2' #Mme
        else:
            professeur['civilite'] = '1' #M.
        professeur['date'] = check_date(str(data['date']))

        # login/mot de passe forcés
        process_force_login(professeur, data)

        try:
            store.add(Administratif(**professeur))
            num += 1
        except Exception as msg:
            log.infolog("Erreur sur le personnel %s : %s" % (data['numero'], msg))
        if num % DEBUG_NUM == 0:
            log.debuglog("%d personnels lus..." % num)
        try:
            data = next(reader)
        except StopIteration:
            break
    log.infolog("TOTAL : %d personnels" % num)
    store.flush()


##########################################
# Extraction CSV Comptes invités
# Fichier :
# - invites.csv
##########################################
def parse_csv_invites(store, csvfile):
    """
    parsing des comptes invités
    """
    num = 0
    log.infolog("Lecture des comptes invités...", title=True)
    # champs obligatoires
    fields = ['nom', 'prenom', 'sexe', 'date']
    # champs optionnels : ['login', 'password']
    reader, data = read_csv(csvfile, fields)
    while True:
        professeur = {}
        # FIXME
        #professeur['int_id'] = u''
        professeur['nom'] = str(replace_more_cars(data['nom']))
        professeur['prenom'] = str(replace_more_cars(data['prenom']))
        if data['sexe'] == 'F':
            professeur['civilite'] = '2' #Mme
        else:
            professeur['civilite'] = '1' #M.
        professeur['date'] = check_date(str(data['date']))

        # login/mot de passe forcés
        process_force_login(professeur, data)

        try:
            store.add(Invite(**professeur))
            num += 1
        except Exception as msg:
            log.infolog("Erreur sur le compte %s %s : %s" % (data['prenom'], data['nom'], msg))
        if num % DEBUG_NUM == 0:
            log.debuglog("%d comptes lus..." % num)
        try:
            data = next(reader)
        except StopIteration:
            break
    log.infolog("TOTAL : %d comptes invités" % num)
    store.flush()
