#! /usr/bin/python3
# -*- coding: utf-8 -*-
###########################################################################
#
# Eole NG
# 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
#
###########################################################################

"""

Importation automatique des fichiers AAF synchronisés via Zéphir :
- décompression des fichiers AAF
- lecture des responsables et des élèves
- écriture des responsables et des élèves
- lecture des personnels
- écriture des personnels (enseignants et administratifs)

"""

import sys
import tarfile
from os import unlink
from os.path import join, dirname, basename, isfile
from creole.client import CreoleClient
from scribe.parsing import aaf
from scribe.eoleldap import Ldap
from scribe.importation import log
from pyeole.process import system_out
from scribe.ldapconf import MAIL_ADMIN, num_etab
from scribe.storage import init_store
from scribe.importation import writer, config
from scribe.eoletools import nscd_start, nscd_stop

CATEGORY_PATTERN = {'eleves':'_Eleve_', 'personnels':'_PersEducNat_'}
OPTIONNAL_CATEGORY = {'responsables':'_PersRelEleve_'}

def extract(fname):
    """
    extraction des fichiers
    """
    tarball = tarfile.open(fname)
    tarball.extractall(config.TMP_DIR)
    return tarball.getnames()

def map_names(names):
    """
    associe les noms de fichiers aux catégories
    """
    result = {}
    for category, pat in CATEGORY_PATTERN.items():
        result[category] = filter_name(names, pat)
    # catégories optionnelles #1947
    for category, pat in OPTIONNAL_CATEGORY.items():
        try:
            result[category] = filter_name(names, pat)
        except:
            continue
    return result

def filter_name(tarfiles, name):
    """
    recherche des fichiers associés à une catégorie
    """
    fnames = [elt for elt in tarfiles if name in elt]
    assert len(fnames) == 1, "Unexpected lenght in %s" % str(fnames)
    return fnames[0]

def write_eleves(store, import_type):
    """
    écriture des élèves et des responsables
    """
    log.debuglog("Arrêt de LSC...", title=True)
    nscd_stop()
    connexion = Ldap()
    connexion.connect()
    if import_type == 'annuel':
        writer.purge_eleves_options(connexion=connexion)
    writer.write_niveau(store=store, connexion=connexion)
    writer.write_classe(store=store, connexion=connexion)
    if config.WRITE_OPTS == "oui":
        writer.write_option(store=store, connexion=connexion)
    writer.write_eleve(store=store, connexion=connexion)
    writer.write_responsable(store=store, connexion=connexion)
    writer.write_samba(connexion)
    connexion.close()
    log.debuglog("Démarrage de LSC...", title=True)
    nscd_start()

def write_personnels(store, import_type):
    """
    écriture des enseignants et personnels administratifs
    """
    log.debuglog("Arrêt de LSC...", title=True)
    nscd_stop()
    connexion = Ldap()
    connexion.connect()
    if import_type == 'annuel':
        writer.purge_equipes(connexion=connexion)
    writer.verify_classe(store=store, connexion=connexion)
    writer.write_matiere(store=store, connexion=connexion)
    writer.verify_option(store=store, connexion=connexion)
    writer.write_enseignant(store=store, connexion=connexion)
    writer.write_service(store=store, connexion=connexion)
    writer.write_administratif(store=store, connexion=connexion)
    writer.write_samba(connexion)
    connexion.close()
    log.debuglog("Démarrage de LSC...", title=True)
    nscd_start()

def send_error_mail(dest, fname, erreur):
    """
    Envoi d'un mail cas d'erreur lors de l'import
    """
    subject = "[{1}] Erreur lors de l'import automatique du fichier {0}".format(fname, num_etab)
    body = erreur
    for address in dest:
        cmd = ['s-nail', '-s', subject, '-r', MAIL_ADMIN, address]
        system_out(cmd, container='mail', stdin=body)

def run():
    """
    c'est parti !!!
    """
    if len(sys.argv) < 2:
        sys.exit(1)

    aaf_tar_fname = sys.argv[1]
    if len(sys.argv) == 3 and sys.argv[2] == 'annuel':
        import_type = 'annuel'
    else:
        import_type = 'maj'
    locked = False
    import_dir = dirname(aaf_tar_fname)
    err_lockfile = join(import_dir, '.%s.lock' % basename(aaf_tar_fname))
    try:
        log.start_importation('auto')
        log.log.info("type d'import : %s" % import_type)
        log.log.info("source de données : aaf")
        log.add_lock()
        locked = True
        if isfile(err_lockfile):
            unlink(err_lockfile)
        names = extract(aaf_tar_fname)
        category_files = map_names(names)
        store = init_store(config.DB_DIR)
        # gestion des élèves et des responsables
        if 'responsables' in category_files:
            aaf.parse_aaf_responsables(store, join(config.TMP_DIR, category_files['responsables']))
        aaf.parse_aaf_eleves(store, join(config.TMP_DIR, category_files['eleves']))
        write_eleves(store, import_type)
        # gestion des personnels
        aaf.parse_aaf_profs(store, join(config.TMP_DIR, category_files['personnels']))
        write_personnels(store, import_type)
        log.end_importation('auto')
        log.del_lock()
    except:
        import traceback
        erreur = traceback.format_exc()
        print(erreur)
        log.log.exception("Erreur lors de l'importation automatique AAF")
        ficp = open(err_lockfile, 'a')
        ficp.close()
        if locked:
            log.del_lock()
        client = CreoleClient()
        if client.get_creole('synchro_aaf_sendmail') == 'oui':
            send_error_mail(client.get_creole('synchro_aaf_mail'), basename(aaf_tar_fname), erreur)
        sys.exit(1)

run()
