# -*- 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
###########################################################################
"""
   recherche les liens entre les utilisateurs importes
   et l'annuaire ldap
"""
from scribe.ldapconf import ELEVE_FILTER, PROF_FILTER, ADMINISTRATIF_FILTER, \
RESPONSABLE_FILTER, USER_FILTER, AUTRE_FILTER, LDAP_MODE
from scribe.eoletools import deformate_date, strip_adresse
from scribe.eoleldap import Ldap

def _eleve_exists(eleve, user):
    """
        recherche si un élève existe déjà dans l'annuaire
        eleve : storage.Eleve()
        user  : eoleuser.Eleve()
    """
    filtres = []
    date = deformate_date(str(eleve.date))
    # /!\ avec BE1D (#924) /!\ #
    is_be1d = False
    try:
        if date == deformate_date(eleve.numero):
            is_be1d = True
    except:
        pass

    # date + cn (cf. demande n°855)
    if LDAP_MODE == 'ad':
        filtre = "(&%s(dateNaissance=%s)(givenName=%s)(sn=%s))"
    else:
        filtre = "(&%s(dateNaissance=%s)(cn=%s %s))"
    filtres.append(filtre % (ELEVE_FILTER,
                        date, str(eleve.prenom), str(eleve.nom) ))
    if eleve.int_id:
    # id interne + date
        filtres.append("(&%s(intid=%s)(dateNaissance=%s))" % (ELEVE_FILTER,
                            str(eleve.int_id), date))
    # id interne + numéro interne
        filtres.append("(&%s(intid=%s)(employeeNumber=%s))" % (ELEVE_FILTER,
                            str(eleve.int_id), str(eleve.numero) ))
    elif not is_be1d:
        # numéro interne + date
        filtres.append("(&%s(employeeNumber=%s)(dateNaissance=%s))" % (ELEVE_FILTER,
                            str(eleve.numero), date))

    for filtre in filtres:
        res = user.ldap_admin._search_one(filtre, 'uid')
        if res != {}:
            return res['uid'][0]
    return ''

def _responsable_exists(responsable, user):
    """
        recherche si un responsable existe déjà dans l'annuaire
        responsable : storage.Responsable()
        user  : eoleuser.Responsable()
    """
    filtres = []
    if responsable.date:
        date = deformate_date(str(responsable.date))
        if responsable.int_id:
    # date + id interne
            filtres.append("(&%s(dateNaissance=%s)(intid=%s))" % (RESPONSABLE_FILTER,
                                date, str(responsable.int_id) ))
    # date + nom
        filtres.append("(&%s(dateNaissance=%s)(sn=%s))" % (RESPONSABLE_FILTER,
                            date, str(responsable.nom) ))
    if responsable.int_id:
    # nom + id interne
        filtres.append("(&%s(sn=%s)(intid=%s))" % (RESPONSABLE_FILTER,
                            str(responsable.nom), str(responsable.int_id) ))
        if responsable.mail:
            # mail + id interne
            filtres.append("(&%s(mailPerso=%s)(intid=%s))" % (RESPONSABLE_FILTER,
                                str(responsable.mail), str(responsable.int_id) ))
    # lancement des tests hors homonymie
    for filtre in filtres:
        res = user.ldap_admin._search_one(filtre, 'uid')
        if res != {}:
            return res['uid'][0]

    filtre_homonyme = "(&%s(sn=%s)(givenName=%s))" % (RESPONSABLE_FILTER,
                 str(responsable.nom), str(responsable.prenom))
    for entry in user.ldap_admin._search(filtre_homonyme):
        # homonymes détectés
        res = entry[1]
        if not (responsable.date or responsable.int_id or responsable.mail):
            # accepté uniquement si aucune autre information (BE1D)
            return res['uid'][0]
        if responsable.mail and res.get('mailPerso', [''])[0] == str(responsable.mail):
            # mail + nom + prenom (#6061) mais mail + nom => mauvaise idée (#4191)
            return res['uid'][0]
        if responsable.adresse.adresse and \
           strip_adresse(res.get('ENTPersonAdresse', [''])[0]) == \
           strip_adresse(str(responsable.adresse.adresse)):
            # adresse + nom + prenom (#6934)
            return res['uid'][0]
    return ''

def _enseignant_exists(enseignant, user):
    """
        recherche si un enseignant existe déjà dans l'annuaire
        enseignant : storage.Enseignant()
        user  : eoleuser.Enseignant()
    """
    filtres = []
    if enseignant.date and enseignant.date != '01/01/0001':
        date = deformate_date(str(enseignant.date))
        if enseignant.int_id:
    # date + id interne
            filtres.append("(&%s(dateNaissance=%s)(intid=%s))" % (PROF_FILTER,
                                date, str(enseignant.int_id) ))
    # date + cn (cf. demande n°943)
        filtres.append("(&%s(dateNaissance=%s)(cn=%s %s))" % (PROF_FILTER,
                            date, str(enseignant.prenom), str(enseignant.nom) ))
    if enseignant.mail:
    # mail + nom
        filtres.append("(&%s(mail=%s)(sn=%s))" % (PROF_FILTER,
                    str(enseignant.mail), str(enseignant.nom) ))
    # mail (federation) + nom
        filtres.append("(&%s(FederationKey=%s)(sn=%s))" % (PROF_FILTER,
                            str(enseignant.mail), str(enseignant.nom) ))
    if enseignant.int_id:
    # nom + id interne
        filtres.append("(&%s(sn=%s)(intid=%s))" % (PROF_FILTER,
                            str(enseignant.nom), str(enseignant.int_id) ))
    # beurk (homonymes) -> à améliorer
    #filtres.append("(&%s(cn=%s %s)(objectClass=enseignant))" % (USER_FILTER,
    #                str(enseignant.prenom), str(enseignant.nom)))
    for filtre in filtres:
        res = user.ldap_admin._search_one(filtre, 'uid')
        if res != {}:
            return res['uid'][0]
    return ''

def _administratif_exists(administratif, user):
    """
        recherche si un administratif existe déjà dans l'annuaire
        administratif : storage.Administratif()
        user  : eoleuser.Administratif()
    """
    filtres = []
    if administratif.date and administratif.date != '01/01/0001':
        date = deformate_date(str(administratif.date))
        if administratif.int_id:
    # date + id interne
            filtres.append("(&%s(dateNaissance=%s)(intid=%s))" % (ADMINISTRATIF_FILTER,
                                date, str(administratif.int_id) ))
    # date + nom
        filtres.append("(&%s(dateNaissance=%s)(sn=%s))" % (ADMINISTRATIF_FILTER,
                            date, str(administratif.nom)))
    if administratif.mail:
    # mail + nom
        filtres.append("(&%s(mail=%s)(sn=%s))" % (ADMINISTRATIF_FILTER,
                            str(administratif.mail), str(administratif.nom)))
    # mail (federation) + nom
        filtres.append("(&%s(FederationKey=%s)(sn=%s))" % (ADMINISTRATIF_FILTER,
                            str(administratif.mail), str(administratif.nom) ))
    if administratif.int_id:
    # nom + id interne
        filtres.append("(&%s(sn=%s)(intid=%s))" % (ADMINISTRATIF_FILTER,
                            str(administratif.nom), str(administratif.int_id) ))

    for filtre in filtres:
        res = user.ldap_admin._search_one(filtre, 'uid')
        if res != {}:
            return res['uid'][0]
    return ''

def _invite_exists(invite, user):
    """
        recherche si un invité existe déjà dans l'annuaire
        invite : storage.Invite()
        user  : eoleuser.Autre()
    """
    filtres = []
    if invite.date:
        date = deformate_date(str(invite.date))
    # FIXME pas de int_id pour les invités ?
    #    if invite.int_id:
    ## date + id interne
    #        filtres.append("(&%s(dateNaissance=%s)(intid=%s))" % (AUTRE_FILTER,
    #                            date, str(invite.int_id) ))
    # date + nom
        filtres.append("(&%s(dateNaissance=%s)(sn=%s))" % (AUTRE_FILTER,
                            date, str(invite.nom) ))
    ## FIXME/TODO pas de mail pour les invités ?
    #if invite.mail:
    ## mail + nom ## FIXME si mail == local ?
    #    filtres.append("(&%s(mail=%s)(sn=%s))" % (AUTRE_FILTER,
    #                        str(invite.mail), str(invite.nom) ))
    # FIXME pas de int_id pour les invités ?
    #if invite.int_id:
    ## nom + id interne
    #    filtres.append("(&%s(sn=%s)(intid=%s))" % (AUTRE_FILTER,
    #                        str(invite.nom), str(invite.int_id) ))
    # beurk (homonymes) -> à améliorer
    filtres.append("(&%s(cn=%s %s))" % (AUTRE_FILTER,
                    str(invite.prenom), str(invite.nom) ))
    for filtre in filtres:
        res = user.ldap_admin._search_one(filtre, 'uid')
        if res != {}:
            return res['uid'][0]
    return ''

def user_factory(login):
    """
    Renvoie le bon objet User() en fonction du login
    """
    conn = Ldap()
    conn.connect()
    filtre = "(&%s(uid=%s))" % (USER_FILTER, login)
    res = conn._search_one(filtre, 'objectClass')
    conn.close()
    if 'objectClass' in res:
        userclass_name = get_userclass_name(res['objectClass'])
        if userclass_name:
            ldapuser = get_userclass_instance(userclass_name)
            return ldapuser
    raise Exception("utilisateur %s inconnu" % login)

def _user_factory(login, connexion=None):
    """
    Renvoie le bon objet User() en fonction du login avec la connexion ldap
    """
    conn = Ldap()
    if connexion:
        conn.connexion = connexion
    else:
        conn.connect()
    filtre = "(&%s(uid=%s))" % (USER_FILTER, login)
    res = conn._search_one(filtre, 'objectClass')
    if 'objectClass' in res:
        userclass_name = get_userclass_name(res['objectClass'])
        if userclass_name:
            ldapuser = get_userclass_instance(userclass_name)
            ldapuser.ldap_admin = conn
            return ldapuser
    raise Exception("utilisateur %s inconnu" % login)

def get_userclass_name(objectClass):
    """
        Renvoie le nom du module gérant les objets de classe : objectClass
    """
    users_objectClass = {
            'Eleves': 'eleve',
            'administrateur': 'enseignant',
            'responsable': 'responsable',
            'administratif': 'administratif',
            'autre': 'autre',
            }
    for objectclass, module in users_objectClass.items():
        if objectclass in objectClass:
            return module
    return None

def get_userclass_instance(module):
    """
        Renvoie une instance du module module
    """
    user_module = __import__('scribe.%ss' % module, None, None, ['%ss' % module])
    user_class = user_module.__dict__[module.capitalize()]
    ldapuser = user_class()
    return ldapuser
