# -*- coding: utf-8 -*-
###########################################################################
# Eole NG - 2009
# Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon)
# Licence CeCill  cf /root/LicenceEole.txt
# eole@ac-dijon.fr
###########################################################################
"""
   écriture dans le ldap des données relationnelles
"""
from os.path import join
from creole.eosfunc import gen_random
from scribe.storage import Niveau, Classe, Eleve, Responsable, Enseignant, \
Administratif, EnsClasse, Matiere, Groupe, JointureClasseEnseignant, \
Service, Invite, JointureGroupeEleve, JointureGroupeEnseignant
from scribe.ldapconf import CIVILITES, EOLE_AD, MIN_PASSWORD_CLASS, GROUP_PATH, LDAP_MODE, FORCED_PASSWORD_MODIFICATION_ALLOWED
from scribe.eoletools import ok_groupe, gen_login, clean_date, \
gen_strong_password, lsc_sync
from scribe.errors import BadLogin
from scribe.eolegroup import Group
from scribe.eoleshare import Share
from scribe.eleves import Eleve as LdapEleve
from scribe.responsables import Responsable as LdapResponsable
from scribe.enseignants import Enseignant as LdapEnseignant
from scribe.administratifs import Administratif as LdapAdministratif
from scribe.autres import Autre as LdapAutre
from scribe.linker import _eleve_exists, _responsable_exists, _enseignant_exists, \
_administratif_exists, _invite_exists
from scribe.importation import preferences
from scribe.importation import log
from scribe.importation import config

# formattage du dico des civilité
CIV = {'':''}
for civ in CIVILITES:
    CIV[civ['code']] = civ['title']
ATTRIB = "(déjà attribué)"

def _gen_password(pref, date):
    """
        calcul du mot de passe en fonction des préférences
        @pref : alea/naiss
        @date : date de naissance
    """
    if (EOLE_AD or LDAP_MODE == 'ad') and MIN_PASSWORD_CLASS > 1:
        return gen_strong_password()
    date = clean_date(date)
    if pref == 'naiss' and date not in ['', '01010001']:
        return date
    else:
        return gen_random(8)

def _gen_mail(pref, mail):
    """
        calcul de l'adresse mail en fonction des prédérencess
        @pref : perso_restreint/perso_internet/perso_aucune/restreint/internet/aucune
        @mail : adresse fournie (ou vide)
    """
    if pref.startswith('perso') and '@' in mail:
        return mail
    elif 'internet' in pref:
        return 'internet'
    elif 'restreint' in pref:
        return 'restreint'
    else:
        return ''

def _gen_new_login(user, pref, prenom='', nom='', force_login=''):
    """
    génération d'un login unique
    @user : objet compatible LdapUser()
    @pref : standard/pnom/nomp/p.nnn/prenom.n
    @prenom : prénom de l'utilisateur
    @nom : nom de l'utilisateur
    @force_login : login forcé
    """
    if force_login != '':
        login = base_login = force_login
    else:
        login = base_login = gen_login(pref, prenom, nom)
    num = 1
    # vérification de la disponibilité de l'identifiant
    # si non disponible, il est suffixé d'un numéro
    while not user._is_available_name(login):
        login = "%s%d" % (base_login, num)
        num += 1
    if login == '' or login.isdigit():
        raise BadLogin("""Login "%s" invalide""" % login)
    return login

def _sync_passwords(user, new_passwords, change_pwd=False):
    """
    synchronisation des mots de passe
    @user : objet compatible LdapUser()
    @new_passwords : liste de couples user/password
    """
    log.infolog("Synchronisation des comptes utilisateurs AD...")
    lsc_sync()
    log.infolog("Synchronisation des mots de passe AD...")
    for login, passwd in new_passwords:
        log.log.debug("Initialisation du mot de passe pour : %s" % login)
        user.c_mod_password(login, passwd, must_change=change_pwd)

def _gen_shares(group, shares, _type):
    """
    génération des partages
    @group : objet EoleGroup()
    @shares : liste des partages à créer
    @_type : type de partage à créer (classe, option, matiere, service)
    """
    log.infolog("Génération des partages {}".format(_type))
    lsc_sync()
    group._init_share()
    for groupname in shares:
        log.log.debug("Création des partages pour %s" % groupname)
        filepath = join(GROUP_PATH, groupname)
        if _type in ('classe', 'option'):
            group.share._make_dirs(groupname, filepath, _type)
            # équipe pédago de la classe ou de l'option
            equipe = 'profs-{0}'.format(groupname)
            filepath = join(GROUP_PATH, equipe)
            group.share._make_dirs(equipe, filepath, 'rw')
        else:
            group.share._make_dirs(groupname, filepath, 'rw')

def _create_dirs(user, quota, new_passwords):
    """
    création des répertoires et des liens
    pour les nouveaux enseigants & administratifs
    @user : objet compatible LdapUser()
    @quota : quota disque à appliquer aux utilisateurs
    @new_passwords : liste de couples user/password
    """
    log.infolog("Mise à jour des répertoires...")
    for login, _ in new_passwords:
        user._add_perso(login, quota=quota)
        user._gen_ftpdir(login)
        user._gen_groupesdir(login)

def purge_equipes(connexion, etab=None):
    """
        Vidange des équipes pédagogiques
        (Classes et Options)
    """
    log.infolog("Nettoyage des équipes pédagogiques", title=True)
    # vidanges des équipes pédagogiques
    groupe = Group()
    groupe.ldap_admin = connexion
    for grp in groupe._get_groups('Equipe', etab):
        groupe._purge_groupe(grp)
    # suppression des responsables de classe
    ens = LdapEnseignant()
    ens.ldap_admin = connexion
    ens._purge_classes_admin(etab)

# -------------------- niveaux -------------------- #

def _write_niveau(groupe, grp_name, description, etab=None, etab_prefix=''):
    """
        gestion des cas pour un niveau
        (nouveau, mise à jour, renommage...
    """
    prefix_grp_name = etab_prefix + grp_name
    if groupe._is_available_name(prefix_grp_name):
        log.log.debug("création du niveau %s" % prefix_grp_name)
        # par défaut : pas de partage pour les niveaux
        groupe._add('Niveau', prefix_grp_name, domaine="restreint", partage="",
                    description=description, sync=False, etab=etab, mkdir=False)
    elif prefix_grp_name in groupe._get_groups(_type='Niveau'):
        log.log.debug("Niveau %s existant : OK" % prefix_grp_name)
        groupe._touch(prefix_grp_name)
    else:
        # renommage obligatoire
        grp_name = "n%s" % grp_name
        prefix_grp_name = _write_niveau(groupe, grp_name, description, etab=etab,
                etab_prefix=etab_prefix)
    return prefix_grp_name

def write_niveau(store, connexion, etab=None, etab_prefix=''):
    """
        insertion des niveaux
    """
    num = 0
    log.infolog("Intégration des niveaux...", title=True)
    groupe = Group()
    groupe.ldap_admin = connexion
    for niveau in store.query(Niveau):
        if niveau.get_eleves() != []:
            nom = str(niveau.nom)
            description = "Niveau %s" % nom
            grp_name = ok_groupe(nom, gtype='n')
            grp_name = _write_niveau(groupe, grp_name, description, etab,
                    etab_prefix)
            # enregistrement du nom retenu
            niveau.nom = str(grp_name)
            num += 1
        else:
            log.infolog("niveau %s sans élèves" % str(niveau.nom))
    log.infolog("TOTAL : %d niveaux traités" % num)


# -------------------- classes -------------------- #

def _write_classe(groupe, grp_name, niveau, description, etab_prefix='', new_cls=[]):
    """
        gestion des cas pour une classe
        (nouveau, mise à jour, renommage...
    """
    prefix_grp_name = etab_prefix + grp_name
    if groupe._is_available_name(prefix_grp_name):
        log.log.debug("création de la classe %s" % prefix_grp_name)
        groupe._add('Classe', prefix_grp_name, domaine="restreint", partage="",
                    niveau=niveau, sync=False, description=description, mkdir=False)
        new_cls.append(prefix_grp_name)
    elif prefix_grp_name in groupe._get_groups(_type='Classe'):
        log.log.debug("Classe %s existante : OK" % prefix_grp_name)
        groupe._touch(prefix_grp_name)
    else:
        # renommage obligatoire
        grp_name = "c%s" % grp_name
        prefix_grp_name = _write_classe(groupe, grp_name, niveau, description, etab_prefix, new_cls)
    return prefix_grp_name

def write_classe(store, connexion, etab_prefix=''):
    """
        insertion des classes
    """
    num = 0
    log.infolog("Intégration des classes...", title=True)
    groupe = Group()
    groupe.ldap_admin = connexion
    new_cls = []
    for classe in store.query(Classe):
        if classe.get_eleves() != []:
            nom = str(classe.nom)
            description = "Classe %s" % nom
            grp_name = ok_groupe(nom, gtype='c')
            niveau = str(classe.niveau.nom)
            grp_name = _write_classe(groupe, grp_name, niveau, description,
                    etab_prefix=etab_prefix, new_cls=new_cls)
            # enregistrement du nom retenu
            classe.nom = str(grp_name)
            num += 1
        else:
            log.infolog("classe %s sans élèves" % str(classe.nom))
    if new_cls:
        _gen_shares(groupe, new_cls, 'classe')
    log.infolog("TOTAL : %d classes traitées" % num)

def verify_classe(store, connexion, etab_prefix=''):
    """
        vérification des classes des enseignants
    """
    num = 0
    log.infolog("Vérification des classes...", title=True)
    groupe = Group()
    groupe.ldap_admin = connexion
    commit = False
    for classe in store.query(EnsClasse):
        nom = str(classe.nom)
        grp_name = etab_prefix+ok_groupe(nom, gtype='c')
        if grp_name in groupe._get_groups(_type='Classe'):
            log.log.debug("Classe %s existante : OK" % grp_name)
            classe.nom = str(grp_name)
            num += 1
        elif "c%s" % grp_name in groupe._get_groups(_type='Classe'):
            log.log.debug("Classe c%s existante : OK" % grp_name)
            classe.nom = str("c%s" % grp_name)
            num += 1
        else:
            log.infolog("Classe %s non trouvée" % grp_name)
            # suppression des références sur cette classe
            jointures = store.query(JointureClasseEnseignant).filter_by(classe=classe).delete()
    log.infolog("TOTAL : %d équipes pédagogiques traitées" % num)


# -------------------- matières -------------------- #

def _write_matiere(groupe, grp_name, description, etab=None, etab_prefix='', new_mats=[]):
    """
        gestion des cas pour une matiere
        (nouveau, mise à jour, renommage...)
    """
    prefix_grp_name = etab_prefix + grp_name
    if groupe._is_available_name(prefix_grp_name):
        log.log.debug("création de la matiere %s" % prefix_grp_name)
        groupe._add('Matiere', prefix_grp_name, domaine="restreint", partage="rw",
                    description=description, sync=False, etab=etab, mkdir=False)
        new_mats.append(prefix_grp_name)
    elif prefix_grp_name in groupe._get_groups(_type='Matiere'):
        log.log.debug("Matiere %s existante : OK" % prefix_grp_name)
        groupe._touch(prefix_grp_name)
    else:
        # renommage obligatoire
        grp_name = "m%s" % grp_name
        prefix_grp_name = _write_matiere(groupe, grp_name, description, etab=etab,
		etab_prefix=etab_prefix, new_mats=new_mats)
    return prefix_grp_name

def write_matiere(store, connexion, etab=None, etab_prefix=''):
    """
        insertion des matieres
    """
    num = 0
    log.infolog("Intégration des matières...", title=True)
    groupe = Group()
    groupe.ldap_admin = connexion
    new_mats = []
    for matiere in store.query(Matiere):
        nom = str(matiere.nom)
        description = str(matiere.description)
        if description == '':
            description = "Matiere %s" % nom
        grp_name = ok_groupe(nom, gtype='m')
        grp_name = _write_matiere(groupe, grp_name, description, etab,
                etab_prefix, new_mats=new_mats)
        # enregistrement du nom retenu
        matiere.nom = str(grp_name)
        num += 1
    if new_mats:
        _gen_shares(groupe, new_mats, 'matiere')
    log.infolog("TOTAL : %d matières traitées" % num)


# -------------------- options -------------------- #

def purge_eleves_options(connexion, etab=None):
    """
        Vidanges des groupes Options
    """
    log.infolog("Nettoyage des options", title=True)
    groupe = Group()
    groupe.ldap_admin = connexion
    for opt in groupe._get_groups('Option', etab=etab):
        groupe._purge_option(opt)

def _write_option(groupe, grp_name, description, etab=None, etab_prefix='', new_opts=[]):
    """
        gestion des cas pour une option
        (nouveau, mise à jour, renommage...)
    """
    prefix_grp_name = etab_prefix + grp_name
    if groupe._is_available_name(prefix_grp_name):
        log.log.debug("création de l'option %s" % prefix_grp_name)
        groupe._add('Option', prefix_grp_name, domaine="restreint",
                    description=description, sync=False, etab=etab,
                    mkdir=False)
        new_opts.append(prefix_grp_name)
    elif prefix_grp_name in groupe._get_groups(_type='Option'):
        log.log.debug("Option %s existante : OK" % prefix_grp_name)
        groupe._touch(prefix_grp_name)
    else:
        # renommage obligatoire
        grp_name = "o%s" % grp_name
        prefix_grp_name = _write_option(groupe, grp_name, description, etab=etab,
                etab_prefix=etab_prefix, new_opts=new_opts)
    return prefix_grp_name

def write_option(store, connexion, etab=None, etab_prefix=''):
    """
        insertion des options
    """
    num = 0
    log.infolog("Intégration des options...", title=True)
    groupe = Group()
    groupe.ldap_admin = connexion
    new_opts = []
    for option in store.query(Groupe):
        if option.count_members() != 0:
            nom = str(option.nom)
            description = str(option.description)
            if description == '':
                description = "Option %s" % nom
            grp_name = ok_groupe(nom, gtype='o')
            grp_name = _write_option(groupe, grp_name, description, etab=etab,
                    etab_prefix=etab_prefix, new_opts=new_opts)
            # enregistrement du nom retenu
            option.nom = str(grp_name)
            num += 1
        else:
            log.infolog("pas d'utilisateurs pour l'option %s" % str(option.nom))
    if new_opts:
        _gen_shares(groupe, new_opts, 'option')
    log.infolog("TOTAL : %d options traitées" % num)

def verify_option(store, connexion, etab_prefix=''):
    """
        vérification des options des enseignants
    """
    num = 0
    log.infolog("Vérification des Options...", title=True)
    groupe = Group()
    groupe.ldap_admin = connexion
    commit = False
    for option in store.query(Groupe):
        if option.count_members() != 0:
            nom = str(option.nom)
            grp_name = etab_prefix+ok_groupe(nom, gtype='o')
            if grp_name in groupe._get_groups(_type='Option'):
                log.log.debug("Option %s existante : OK" % grp_name)
                option.nom = str(grp_name)
                num += 1
            elif "o%s" % grp_name in groupe._get_groups(_type='Option'):
                log.log.debug("Option o%s existante : OK" % grp_name)
                option.nom = str("o%s" % grp_name)
                num += 1
            else:
                log.debuglog("Option %s non trouvée (sans élèves ?)" % grp_name)
                # suppression des références sur cette option
                commit = True
                jointures = store.query(JointureGroupeEnseignant).filter_by(groupe=option).delete()
                jointures = store.query(JointureGroupeEleve).filter_by(groupe=option).delete()
        else:
            log.infolog("pas d'enseignant pour l'option %s" % str(option.nom))
    log.infolog("TOTAL : %d options traitées" % num)

# -------------------- services -------------------- #

def _write_service(groupe, grp_name, description, etab=None, etab_prefix='', new_svs=[]):
    """
        gestion des cas pour un service administratif
        (nouveau, mise à jour, renommage...)
    """
    prefix_grp_name = etab_prefix + grp_name
    if groupe._is_available_name(prefix_grp_name):
        log.log.debug("création du service %s" % (prefix_grp_name))
        groupe._add('Service', prefix_grp_name, domaine="restreint",
                    partage="rw", description=description, sync=False,
                    etab=etab, mkdir=False)
        new_svs.append(prefix_grp_name)
    elif prefix_grp_name in groupe._get_groups(_type='Service'):
        log.log.debug("Service %s existant : OK" % prefix_grp_name)
        groupe._touch(prefix_grp_name)
    else:
        # renommage obligatoire
        grp_name = "s%s" % grp_name
        prefix_grp_name = _write_service(groupe, grp_name, description, etab_prefix=etab_prefix, new_svs=new_svs)
    return prefix_grp_name

def write_service(store, connexion, etab=None, etab_prefix=''):
    """
        insertion des matieres
    """
    num = 0
    log.infolog("Intégration des services administratifs...", title=True)
    groupe = Group()
    groupe.ldap_admin = connexion
    new_svs = []
    for grp in store.query(Service):
        nom = str(grp.nom)
        description = str(grp.description)
        if description == '':
            description = "Service %s" % nom
        grp_name = ok_groupe(nom, gtype='s')
        grp_name = _write_service(groupe, grp_name, description, etab,
                etab_prefix, new_svs=new_svs)
        # enregistrement du nom retenu
        grp.nom = str(grp_name)
        num += 1
    if new_svs:
        _gen_shares(groupe, new_svs, 'service')
    log.infolog("TOTAL : %d services traités" % num)


# -------------------- élèves -------------------- #

def _new_eleve(eleve, user, prefs, etab=None, new_passwords=[], new_perso=[]):
    """
        traitement d'un nouvel élève (création)
        eleve : store.Eleve()
        user  : eoleuser.Eleve()
    """
    if eleve.force_login:
        login = _gen_new_login(user, prefs.get_default('login'),
                               force_login=str(eleve.force_login))
    else:
        login = _gen_new_login(user, prefs.get_default('login'),
                               str(eleve.prenom),
                               str(eleve.nom))
    if eleve.force_password:
        password = str(eleve.force_password)
    else:
        password = _gen_password(prefs.get_default('gen_pwd'), str(eleve.date))
    log.log.debug("nouvel élève : %s" % login)
    my_eleve = {'login':login,
                'password':password,
                'nom':str(eleve.nom),
                'prenom':str(eleve.prenom),
                'date':str(eleve.date),
                'classe':str(eleve.classe.nom),
                # désormais calculé dans ajout_eleve
                #'niveau':str(eleve.niveau.nom),
                'civilite':str(eleve.civilite),
                'numero':str(eleve.numero),
                'ine':str(eleve.ine),
                'patronyme':str(eleve.nom_patronymique),
                'prenom2':str(eleve.prenom2),
                'int_id':str(eleve.int_id),
                'entlogin':False,
                'regime':str(eleve.regime),
                'rattachid':str(eleve.rattachid),
                'enseignements':eval(eleve.enseignements),
                'elevegroupes': list(set([str(g.nom) for g in eleve.get_groupes()])),
                'entpersonjointure':str(eleve.entpersonjointure),
                # préférences générales
                'domaine':prefs.get_default('domaine'),
                'quota':prefs.get_default('quota'),
                'profil':prefs.get_default('profil'),
                'shell':prefs.get_default('shell') == 'oui',
                'change_pwd':prefs.get_default('change_pwd') == 'oui' if FORCED_PASSWORD_MODIFICATION_ALLOWED else False,
                'etab': etab,
                'syncpassword': not EOLE_AD,
    }
    # création de l'élève
    user._add(**my_eleve)
    info = "%(classe)s;%(nom)s;%(prenom)s;%(login)s;%(password)s;%(numero)s;%(ine)s"
    log.write_info(info % my_eleve, config.ELE_INFO)
    if EOLE_AD:
        new_passwords.append((login, password))
        new_perso.append((login, str(eleve.classe.nom)))
    return login

def _maj_eleve(eleve, user, login, etab=None):
    """
        traitement d'un élève existant (mise à jour)
        eleve : store.Eleve()
        user  : eoleuser.Eleve()
        login : uid de l'utilisateur dans ldap
    """
    classe = str(eleve.classe.nom)
    niveau = user._get_niveau(classe)
    attrs = user._get_attrs(login, ['Divcod', 'Meflcf'])
    # gestion de la classe et du niveau
    if classe != attrs['Divcod'][0] or niveau != attrs['Meflcf'][0]:
        log.log.debug("changement de classe pour %s de %s vers %s" % (login, attrs['Divcod'][0], classe))
        user._change_classe(login, classe, etab, sync=False)
    else:
        log.log.debug("élève retrouvé %s" % login)
    # autres éléments à mettre à jour
    update_eleve = {'int_id':str(eleve.int_id),
                    'ine':str(eleve.ine),
                    'rattachid':str(eleve.rattachid),
                    'regime':str(eleve.regime),
                    'enseignements':eval(eleve.enseignements),
                    'elevegroupes': list(set([str(g.nom) for g in eleve.get_groupes()])),
                    # maj systématique des noms, prénoms et date (#1915)
                    'nom':str(eleve.nom),
                    'prenom':str(eleve.prenom),
                    'date':str(eleve.date),
                    'entpersonjointure':str(eleve.entpersonjointure),
                    'etab': etab
    }
    user._update(login, **update_eleve)
    info = "%s;%s;%s;%s;%s;%s;%s;" % (classe, str(eleve.nom),
                                str(eleve.prenom), login,
                                ATTRIB, str(eleve.numero),
                                str(eleve.ine))
    log.write_info(info, config.ELE_INFO)

def write_eleve(store, connexion, etab=None, current_ead_user=config.DEFAULT_USER):
    """
        insertion des élèves
    """
    num = 0
    log.infolog("Intégration des élèves...", title=True)
    log.write_header(config.ELE_HEADER, config.ELE_INFO)
    user = LdapEleve()
    user.ldap_admin = connexion
    prefs = preferences.get_eleves_prefs()
    quota = prefs.get_default('quota')
    if FORCED_PASSWORD_MODIFICATION_ALLOWED:
        change_pwd = prefs.get_default('change_pwd') == 'oui'
    else:
        change_pwd = False
    new_passwords = []
    new_perso = []
    userlist = []
    for eleve in store.query(Eleve):
        if eleve.classe is None:
            # pas de classe
            #print eleve.prenom, eleve.nom, "non affecté"
            continue
        if eleve.force_login:
            # login forcé
            if user._is_eleve(str(eleve.force_login)):
                login = str(eleve.force_login)
            else:
                login = ''
        else:
            login = _eleve_exists(eleve, user)
        if login != '':
            # élève existant
            _maj_eleve(eleve, user, login, etab)
        else:
            # nouvel élève
            if str(eleve.nom) == '' or str(eleve.prenom) == '':
                log.infolog("Eleve n°%s invalide" % str(eleve.int_id))
                continue
            try:
                login = _new_eleve(eleve, user, prefs, etab=etab, new_passwords=new_passwords, new_perso=new_perso)
            except BadLogin as message:
                log.infolog(str(message))
                continue
        if config.WRITE_OPTS == 'oui':
            options = eleve.get_groupes()
            if options != []:
                my_grps = user._get_user_groups(login)
                for option in options:
                    opt_name = str(option.nom)
                    if opt_name not in my_grps:
                        user._inscription(login, opt_name, etab=etab, sync=False)
        userlist.append(login)
        # enregistrement du login attribué
        eleve.login = str(login)
        num += 1
        if num % config.DEBUG_NUM == 0:
            log.debuglog("%d élèves traités..." % num)
    if EOLE_AD:
        _sync_passwords(user, new_passwords, change_pwd)
    log.infolog("Mise à jour des répertoires...")
    for login, classe in new_perso:
        # création des réprtoires "perso"
        user._add_perso(login, quota=quota, classe=classe)
    for login in userlist:
        # mise à jour des répertoires spéciaux
        user._gen_ftpdir(login)
        user._gen_groupesdir(login)
    log.infolog("TOTAL : %d élèves" % num)
    if num != 0:
        log.copy_info(config.ELE_INFO, user=current_ead_user)


# -------------------- responsables -------------------- #

def _new_responsable(responsable, user, eleves, ele_infos, prefs):
    """
        traitement d'un nouveau responsable (création)
        responsable : store.Responsable()
        user  : eoleuser.Responsable()
        eleves : login de ses élèves
        ele_infos : liste des élèves pour sortie CSV
        prefs : préférences responsable
    """
    login = _gen_new_login(user, prefs.get_default('login'),
            str(responsable.prenom), str(responsable.nom))
    password = _gen_password(prefs.get_default('gen_pwd'), str(responsable.date))
    log.log.debug("nouveau responsable : %s" % login)
    mail = str(responsable.mail)
    real_mail = _gen_mail(prefs.get_default('mail'), mail)
    my_responsable = {'login':login,
                'password':password,
                'nom':str(responsable.nom),
                'prenom':str(responsable.prenom),
                'date':str(responsable.date),
                'civilite':str(responsable.civilite),
                'mailperso':mail,
                'mail':real_mail,
                'telephone':str(responsable.telephone),
                'tel_portable':str(responsable.tel_portable),
                'tel_pro':str(responsable.tel_pro),
                'eleve':eleves,
                'int_id':str(responsable.int_id),
                'entlogin':False,
                'entpersonjointure':str(responsable.entpersonjointure),
    }
    info = "%s;" % CIV[str(responsable.civilite)]
    if responsable.adresse is not None:
        add = responsable.adresse
        my_responsable['adresse'] = str(add.adresse)
        my_responsable['code'] = str(add.code_postal)
        my_responsable['ville'] = str(add.ville)
        my_responsable['pays'] = str(add.pays)
        info += "%(nom)s;%(prenom)s;%(login)s;%(password)s;%(adresse)s;%(code)s;%(ville)s;%(pays)s;"
    else:
        info += "%(nom)s;%(prenom)s;%(login)s;%(password)s;;;;;"
    # création du responsable
    user._add(**my_responsable)
    info = info % my_responsable + ele_infos
    log.write_info(info.replace('\n', ''), config.RES_INFO)
    return login

def _maj_responsable(responsable, user, login, eleves, ele_infos):
    """
        traitement d'un responsable existant (mise à jour)
        responsable : store.Responsable()
        user  : eoleuser.Responsable()
        login : uid de l'utilisateur dans ldap
        eleves : login de ses élèves
        ele_infos : liste des élèves pour sortie CSV
    """
    log.log.debug("maj de %s" % login)
    update_responsable = {'telephone':str(responsable.telephone),
                          'tel_portable':str(responsable.tel_portable),
                          'tel_pro':str(responsable.tel_pro),
                          'mailperso':str(responsable.mail),
                          # maj systématique des noms et prénoms (#6468)
                          'nom':str(responsable.nom),
                          'prenom':str(responsable.prenom),
                          'entpersonjointure':str(responsable.entpersonjointure),
    }
    if responsable.adresse is not None:
        add = responsable.adresse
        update_responsable['adresse'] = str(add.adresse)
        update_responsable['code'] = str(add.code_postal)
        update_responsable['ville'] = str(add.ville)
        update_responsable['pays'] = str(add.pays)
        csv_adresse = "%(adresse)s;%(code)s;%(ville)s;%(pays)s" % update_responsable
    else:
        csv_adresse = ";;;"
    if responsable.int_id:
        update_responsable['int_id'] = str(responsable.int_id)
    user._update(login, eleves, **update_responsable)
    info = "%s;%s;%s;%s;%s;%s;%s" % (CIV[str(responsable.civilite)],
                                  str(responsable.nom),
                                  str(responsable.prenom),
                                  login, ATTRIB, csv_adresse, ele_infos)
    log.write_info(info.replace('\n', ''), config.RES_INFO)

def write_responsable(store, connexion, current_ead_user=config.DEFAULT_USER):
    """
        insertion des responsables
    """
    num = 0
    log.infolog("Intégration des responsables...", title=True)
    log.write_header(config.RES_HEADER, config.RES_INFO)
    user = LdapResponsable()
    user.ldap_admin = connexion
    prefs = preferences.get_responsables_prefs()
    for responsable in store.query(Responsable):
        eleves = responsable.get_eleves()
        if eleves == []:
            # pas d'élèves connus
            continue
        if str(responsable.nom) in ['', '-'] or str(responsable.prenom) in ['', '-']:
            log.debuglog("Responsable n°%s invalide" % str(responsable.int_id))
            continue
        my_eleves = []
        eleves_info = ''
        for eleve in eleves:
            if str(eleve.login) != '':
                my_eleves.append(str(eleve.login))
                eleves_info += "%s;%s;%s;" % (str(eleve.nom),
                        str(eleve.prenom), str(eleve.classe.nom))
        if my_eleves == []:
            # pas d'élève valide
            continue
        login = _responsable_exists(responsable, user)
        if login != '':
            # responsable existant
            _maj_responsable(responsable, user, login, my_eleves, eleves_info)
        else:
            # nouveau responsable
            try:
                login = _new_responsable(responsable, user, my_eleves,
                                         eleves_info, prefs)
            except BadLogin as message:
                log.infolog(str(message))
                continue
        # enregistrement du login attribué
        responsable.login = str(login)
        num += 1
        if num % config.DEBUG_NUM == 0:
            log.debuglog("%d responsables traités..." % num)
    log.infolog("TOTAL : %d responsables" % num)
    if num != 0:
        log.copy_info(config.RES_INFO, user=current_ead_user)


# -------------------- enseignants -------------------- #

def _new_enseignant(enseignant, user, prefs, etab=None, new_passwords=[]):
    """
        traitement d'un nouveau enseignant (création)
        enseignant : store.Enseignant()
        user  : eoleuser.Enseignant()
    """
    if enseignant.force_login:
        login = _gen_new_login(user, prefs.get_default('login'),
                               force_login=str(enseignant.force_login))
    else:
        login = _gen_new_login(user, prefs.get_default('login'),
                               str(enseignant.prenom),
                               str(enseignant.nom))
    if enseignant.force_password:
        password = str(enseignant.force_password)
    else:
        password = _gen_password(prefs.get_default('gen_pwd'), str(enseignant.date))
    log.log.debug("nouvel enseignant : %s" % login)
    classe = []
    groups = []
    for joint in enseignant.get_classes():
        groups.append('profs-%s' % str(joint.classe.nom))
        if joint.profprincipal:
            classe.append(str(joint.classe.nom))
    for matiere in enseignant.get_matieres():
        groups.append(str(matiere.nom))
    for option in enseignant.get_groupes():
        groups.append('profs-%s' % str(option.nom))
    mail = str(enseignant.mail)
    real_mail = _gen_mail(prefs.get_default('mail'), mail)
    my_enseignant = {'login':login,
                'password':password,
                'nom':str(enseignant.nom),
                'prenom':str(enseignant.prenom),
                'date':str(enseignant.date),
                'civilite':str(enseignant.civilite),
                'mail':real_mail,
                'mail_acad':mail,
                'int_id':str(enseignant.int_id),
                'classe':classe,
                'groups':groups,
                'entlogin':False,
                'disciplines':eval(enseignant.disciplines),
                'entpersonjointure':str(enseignant.entpersonjointure),
                # préférences générales
                'quota':prefs.get_default('quota'),
                'profil':prefs.get_default('profil'),
                'shell':prefs.get_default('shell') == 'oui',
                'change_pwd':prefs.get_default('change_pwd') == 'oui' if FORCED_PASSWORD_MODIFICATION_ALLOWED else False,
                'etab': etab,
                'syncpassword': not EOLE_AD,
    }
    # création de l'enseignant
    user._add(**my_enseignant)
    info = "%(nom)s;%(prenom)s;%(login)s;%(password)s"
    log.write_info(info % my_enseignant, config.ENS_INFO)
    if EOLE_AD:
        new_passwords.append((login, password))
    return login

def _maj_enseignant(enseignant, user, login, etab, administratif=False):
    """
        traitement d'un enseignant existant (mise à jour)
        enseignant : store.Enseignant()
        user  : eoleuser.Enseignant()
        login : uid de l'utilisateur dans ldap
        administratif : personnel administratif avec un compte enseignant
    """
    log.log.debug("maj de %s" % login)
    classe = []
    groups = []
    # attention : des administratifs peuvent avoir un compte enseignant
    if isinstance(enseignant, Enseignant):
        old_etab = user.get_etab(login)
        if old_etab != etab:
            user._change_etab(login, old_etab, etab)
        for joint in enseignant.get_classes():
            groups.append('profs-%s' % str(joint.classe.nom))
            if joint.profprincipal:
                classe.append(str(joint.classe.nom))
        for matiere in enseignant.get_matieres():
            groups.append(str(matiere.nom))
        for option in enseignant.get_groupes():
            groups.append('profs-%s' % str(option.nom))
        disciplines = eval(enseignant.disciplines)
    else:
        disciplines = []
    update_enseignant = {'mail_acad':str(enseignant.mail),
                         'int_id':str(enseignant.int_id),
                         'disciplines':disciplines,
                         'classe':classe,
                         'groups':groups,
                         # maj systématique des noms et prénoms (#6468)
                         'nom':str(enseignant.nom),
                         'prenom':str(enseignant.prenom),
                         'entpersonjointure':str(enseignant.entpersonjointure),
                         'etab': etab,
    }
    user._update(login, **update_enseignant)
    if administratif:
        info = "%s;%s;%s;%s" % (str(enseignant.nom), str(enseignant.prenom),
                                login, "(compte enseignant)")
        log.write_info(info, config.ADM_INFO)
    else:
        info = "%s;%s;%s;%s" % (str(enseignant.nom), str(enseignant.prenom),
                                login, ATTRIB)
        log.write_info(info, config.ENS_INFO)

def write_enseignant(store, connexion, etab=None, current_ead_user=config.DEFAULT_USER):
    """
        insertion des enseignants
    """
    num = 0
    log.infolog("Intégration des enseignants...", title=True)
    log.write_header(config.ENS_HEADER, config.ENS_INFO)
    user = LdapEnseignant()
    user.ldap_admin = connexion
    prefs = preferences.get_enseignants_prefs()
    quota = prefs.get_default('quota')
    if FORCED_PASSWORD_MODIFICATION_ALLOWED:
        change_pwd = prefs.get_default('change_pwd') == 'oui'
    else:
        change_pwd = False
    new_passwords = []
    for enseignant in store.query(Enseignant):
        if enseignant.force_login:
            # login forcé
            if user._is_enseignant(str(enseignant.force_login)):
                login = str(enseignant.force_login)
            else:
                login = ''
        else:
            login = _enseignant_exists(enseignant, user)
        if login != '':
            # enseignant existant
            _maj_enseignant(enseignant, user, login, etab)
        else:
            # nouvel enseignant
            if str(enseignant.nom) == '' or str(enseignant.prenom) == '':
                log.infolog("Enseignant n°%s invalide" % str(enseignant.int_id))
                continue
            try:
                login = _new_enseignant(enseignant, user, prefs, etab=etab, new_passwords=new_passwords)
            except BadLogin as message:
                log.infolog(str(message))
                continue
        # enregistrement du login attribué
        enseignant.login = str(login)
        num += 1
        if num % config.DEBUG_NUM == 0:
            log.debuglog("%d enseignants traités..." % num)
    if EOLE_AD:
        _sync_passwords(user, new_passwords, change_pwd=change_pwd)
        _create_dirs(user, quota, new_passwords)
    log.infolog("TOTAL : %d enseignants" % num)
    if num != 0:
        log.copy_info(config.ENS_INFO, user=current_ead_user)


# -------------------- administratifs -------------------- #

def _new_administratif(administratif, user, prefs, etab=None, new_passwords=[]):
    """
        traitement d'un nouvel administratif (création)
        administratif : store.Administratif()
        user  : eoleuser.Administratif()
    """
    if administratif.force_login:
        login = _gen_new_login(user, prefs.get_default('login'),
                               force_login=str(administratif.force_login))
    else:
        login = _gen_new_login(user, prefs.get_default('login'),
                               str(administratif.prenom),
                               str(administratif.nom))
    if administratif.force_password:
        password = str(administratif.force_password)
    else:
        password = _gen_password(prefs.get_default('gen_pwd'), str(administratif.date))
    mail = str(administratif.mail)
    real_mail = _gen_mail(prefs.get_default('mail'), mail)
    log.log.debug("nouvel administratif : %s" % login)
    my_administratif = {'login':login,
                'password':password,
                'nom':str(administratif.nom),
                'prenom':str(administratif.prenom),
                'date':str(administratif.date),
                'civilite':str(administratif.civilite),
                'mail':real_mail,
                'mail_acad':mail,
                'int_id':str(administratif.int_id),
                'entlogin':False,
                'entpersonjointure':str(administratif.entpersonjointure),
                 # préférences générales
                'quota':prefs.get_default('quota'),
                'profil':prefs.get_default('profil'),
                'shell':prefs.get_default('shell') == 'oui',
                'change_pwd':prefs.get_default('change_pwd') == 'oui' if FORCED_PASSWORD_MODIFICATION_ALLOWED else False,
                'etab': etab,
                'syncpassword': not EOLE_AD,
    }
    if administratif.groupe is not None:
        my_administratif['groupe'] = str(administratif.groupe.nom)
    # création de l'administratif
    user._add(**my_administratif)
    info = "%(nom)s;%(prenom)s;%(login)s;%(password)s"
    log.write_info(info % my_administratif, config.ADM_INFO)
    if EOLE_AD:
        new_passwords.append((login, password))
    return login

def _maj_administratif(administratif, user, login):
    """
        traitement d'un administratif existant (mise à jour)
        administratif : store.Administratif()
        user  : eoleuser.Administratif()
        login : uid de l'utilisateur dans ldap
    """
    log.log.debug("maj de %s" % login)
    update_administratif = {'mail_acad':str(administratif.mail),
                            'int_id':str(administratif.int_id),
                            # maj systématique des noms et prénoms (#6468)
                            'nom':str(administratif.nom),
                            'prenom':str(administratif.prenom),
                            'entpersonjointure':str(administratif.entpersonjointure),
    }
    user._update(login, **update_administratif)
    info = "%s;%s;%s;%s;" % (str(administratif.nom), str(administratif.prenom),
                             login, ATTRIB)
    log.write_info(info, config.ADM_INFO)

def write_administratif(store, connexion, etab=None, current_ead_user=config.DEFAULT_USER):
    """
        insertion des administratifs
    """
    num = 0
    log.infolog("Intégration des personnels administratifs...", title=True)
    log.write_header(config.ADM_HEADER, config.ADM_INFO)
    user = LdapAdministratif()
    user.ldap_admin = connexion
    prefs = preferences.get_administratifs_prefs()
    quota = prefs.get_default('quota')
    if FORCED_PASSWORD_MODIFICATION_ALLOWED:
        change_pwd = prefs.get_default('change_pwd') == 'oui'
    else:
        change_pwd = False
    new_passwords = []
    for administratif in store.query(Administratif):
        if administratif.force_login:
            # login forcé
            if user._is_administratif(str(administratif.force_login)):
                login = str(administratif.force_login)
            else:
                login = ''
        else:
            login = _administratif_exists(administratif, user)
        if login != '':
            # personnel existe
            _maj_administratif(administratif, user, login)
        else:
            login = _enseignant_exists(administratif, user)
            if login != '':
                # le personnel a été crée comme un professeur...
                log.infolog("(%s a un compte enseignant)" % login)
                ldap_ens = LdapEnseignant()
                ldap_ens.ldap_admin = connexion
                _maj_enseignant(administratif, ldap_ens, login, etab, administratif=True)
            else:
                # nouveau personnel
                if str(administratif.nom) == '' or str(administratif.prenom) == '':
                    log.infolog("Administratif n°%s invalide" % str(administratif.int_id))
                    continue
                try:
                    login = _new_administratif(administratif, user, prefs, etab=etab, new_passwords=new_passwords)
                except BadLogin as message:
                    log.infolog(str(message))
                    continue
        # enregistrement du login attribué
        administratif.login = str(login)
        num += 1
        if num % config.DEBUG_NUM == 0:
            log.debuglog("%d personnels administratif traités..." % num)
    if EOLE_AD:
        _sync_passwords(user, new_passwords, change_pwd=change_pwd)
        _create_dirs(user, quota, new_passwords)
    log.infolog("TOTAL : %d personnels administratif" % num)
    if num != 0:
        log.copy_info(config.ADM_INFO, user=current_ead_user)

def _new_invite(invite, user, prefs):
    """
        traitement d'un nouveau compte invité (création)
        invite : store.Invite()
        user  : eoleuser.Autre()
    """
    login = _gen_new_login(user, prefs.get_default('login'),
            str(invite.prenom), str(invite.nom))
    password = _gen_password(prefs.get_default('gen_pwd'), str(invite.date))
    log.log.debug("nouveau compte invité : %s" % login)
    # FIXME : vaut toujouts u'' pour l'instant
    mail = str(invite.mail)
    real_mail = _gen_mail(prefs.get_default('mail'), mail)
    my_invite = {'login':login,
                'password':password,
                'nom':str(invite.nom),
                'prenom':str(invite.prenom),
                'date':str(invite.date),
                'civilite':str(invite.civilite),
                'mail':real_mail,
                'entlogin':False,
    }
    ## création du compte
    user._add(**my_invite)
    info = "%(nom)s;%(prenom)s;%(login)s;%(password)s"
    log.write_info(info % my_invite, config.INV_INFO)
    return login

def _maj_invite(invite, user, login):
    """
        traitement d'un invité existant (mise à jour)
        invite : store.Invite()
        user  : eoleuser.Autre()
        login : uid de l'utilisateur dans ldap
    """
    log.log.debug("maj de %s" % login)
    # FIXME : attributs en Maj
    user._update(login)
    info = "%s;%s;%s;%s" % (str(invite.nom), str(invite.prenom),
                            login, ATTRIB)
    log.write_info(info, config.INV_INFO)

def write_invite(store, connexion, current_ead_user=config.DEFAULT_USER):
    """
        insertion des comptes invités
    """
    num = 0
    log.infolog("Intégration de comptes invités...", title=True)
    log.write_header(config.INV_HEADER, config.INV_INFO)
    user = LdapAutre()
    user.ldap_admin = connexion
    prefs = preferences.get_invites_prefs()
    for invite in store.query(Invite):
        login = _invite_exists(invite, user)
        if login != '':
            # compte invité existant
            _maj_invite(invite, user, login)
        else:
            # nouveau compte invité
            if str(invite.nom) == '' or str(invite.prenom) == '':
                log.infolog("Compte invité n°%s invalide" % str(invite.int_id))
                continue
            try:
                login = _new_invite(invite, user, prefs)
            except BadLogin as message:
                log.infolog(str(message))
                continue
        # enregistrement du login attribué
        invite.login = str(login)
        num += 1
        if num % config.DEBUG_NUM == 0:
            log.debuglog("%d comptes traités..." % num)
    log.infolog("TOTAL : %d comptes invités" % num)
    if num != 0:
        log.copy_info(config.INV_INFO, user=current_ead_user)

def write_samba(connexion):
    """
        Génération de la configuration Samba
    """
    log.infolog("Synchronisation des partages Samba...")
    share = Share()
    share.ldap_admin = connexion
    share._synchronize(False)

