# -*- mode: python -*-
# -*- coding: utf-8 -*-

##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2021 Emmanuel Viennet.  All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#   Emmanuel Viennet      emmanuel.viennet@viennet.net
#
##############################################################################

"""Import / Export de formations
"""
from operator import itemgetter
import xml.dom.minidom

import sco_utils as scu

import notesdb as ndb
from notes_log import log
import sco_codes_parcours
import sco_formsemestre
import sco_tag_module
from gen_tables import GenTable
from sco_exceptions import ScoValueError
from sco_permissions import ScoChangeFormation
import VERSION


def formation_export(
    context, formation_id, export_ids=False, export_tags=True, format=None, REQUEST=None
):
    """Get a formation, with UE, matieres, modules
    in desired format
    """
    F = context.formation_list(args={"formation_id": formation_id})[0]
    ues = context.do_ue_list({"formation_id": formation_id})
    F["ue"] = ues
    for ue in ues:
        ue_id = ue["ue_id"]
        if not export_ids:
            del ue["ue_id"]
            del ue["formation_id"]
        if ue["ects"] is None:
            del ue["ects"]
        mats = context.do_matiere_list({"ue_id": ue_id})
        ue["matiere"] = mats
        for mat in mats:
            matiere_id = mat["matiere_id"]
            if not export_ids:
                del mat["matiere_id"]
                del mat["ue_id"]
            mods = context.do_module_list({"matiere_id": matiere_id})
            mat["module"] = mods
            for mod in mods:
                if export_tags:
                    # mod['tags'] = sco_tag_module.module_tag_list(context, module_id=mod['module_id'])
                    tags = sco_tag_module.module_tag_list(
                        context, module_id=mod["module_id"]
                    )
                    if tags:
                        mod["tags"] = [{"name": x} for x in tags]
                if not export_ids:
                    del mod["ue_id"]
                    del mod["matiere_id"]
                    del mod["module_id"]
                    del mod["formation_id"]
                if mod["ects"] is None:
                    del mod["ects"]

    return scu.sendResult(
        REQUEST, F, name="formation", format=format, force_outer_xml_tag=False
    )


ELEMENT_NODE = 1
TEXT_NODE = 3


def XMLToDicts(element, encoding):
    """Represent dom element as a dict
    Example:
       <foo x="1" y="2"><bar z="2"/></foo>
    will give us:
       ('foo', {'y': '2', 'x': '1'}, [('bar', {'z': '2'}, [])])
    """
    d = {}
    # attributes
    if element.attributes:
        for i in range(len(element.attributes)):
            a = element.attributes.item(i).nodeName.encode(encoding)
            v = element.getAttribute(element.attributes.item(i).nodeName)
            d[a] = v.encode(encoding)
    # descendants
    childs = []
    for child in element.childNodes:
        if child.nodeType == ELEMENT_NODE:
            childs.append(XMLToDicts(child, encoding))
    return (element.nodeName.encode(encoding), d, childs)


def formation_import_xml(
    context, REQUEST, doc, import_tags=True, encoding=scu.SCO_ENCODING
):
    """Create a formation from XML representation
    (format dumped by formation_export( format='xml' ))
    """
    log("formation_import_xml: doc=%s" % doc)
    try:
        dom = xml.dom.minidom.parseString(doc)
    except:
        log("formation_import_xml: invalid XML data")
        raise ScoValueError("Fichier XML invalide")

    f = dom.getElementsByTagName("formation")[0]  # or dom.documentElement
    D = XMLToDicts(f, encoding)
    assert D[0] == "formation"
    F = D[1]
    F_quoted = F.copy()
    log("F=%s" % F)
    ndb.quote_dict(F_quoted)
    log("F_quoted=%s" % F_quoted)
    # find new version number
    cnx = context.GetDBConnexion()
    cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
    log(
        "select max(version) from notes_formations where acronyme=%(acronyme)s and titre=%(titre)s"
        % F_quoted
    )
    cursor.execute(
        "select max(version) from notes_formations where acronyme=%(acronyme)s and titre=%(titre)s",
        F_quoted,
    )
    res = cursor.fetchall()
    try:
        version = int(res[0][0]) + 1
    except:
        version = 1
    F["version"] = version
    # create formation
    # F_unquoted = F.copy()
    # unescape_html_dict(F_unquoted)
    formation_id = context.do_formation_create(F, REQUEST)
    log("formation %s created" % formation_id)
    ues_old2new = {}  # xml ue_id : new ue_id
    modules_old2new = {}  # xml module_id : new module_id
    # (nb: mecanisme utilise pour cloner semestres seulement, pas pour I/O XML)
    # -- create UEs
    for ue_info in D[2]:
        assert ue_info[0] == "ue"
        ue_info[1]["formation_id"] = formation_id
        if "ue_id" in ue_info[1]:
            xml_ue_id = ue_info[1]["ue_id"]
            del ue_info[1]["ue_id"]
        else:
            xml_ue_id = None
        ue_id = context.do_ue_create(ue_info[1], REQUEST)
        if xml_ue_id:
            ues_old2new[xml_ue_id] = ue_id
        # -- create matieres
        for mat_info in ue_info[2]:
            assert mat_info[0] == "matiere"
            mat_info[1]["ue_id"] = ue_id
            mat_id = context.do_matiere_create(mat_info[1], REQUEST)
            # -- create modules
            for mod_info in mat_info[2]:
                assert mod_info[0] == "module"
                if "module_id" in mod_info[1]:
                    xml_module_id = mod_info[1]["module_id"]
                    del mod_info[1]["module_id"]
                else:
                    xml_module_id = None
                mod_info[1]["formation_id"] = formation_id
                mod_info[1]["matiere_id"] = mat_id
                mod_info[1]["ue_id"] = ue_id
                mod_id = context.do_module_create(mod_info[1], REQUEST)
                if xml_module_id:
                    modules_old2new[xml_module_id] = mod_id
                if import_tags:
                    if len(mod_info) > 2:
                        tag_names = [t[1]["name"] for t in mod_info[2]]
                        sco_tag_module.module_tag_set(context, mod_id, tag_names)

    return formation_id, modules_old2new, ues_old2new


def formation_list_table(context, formation_id=None, args={}, REQUEST=None):
    """List formation, grouped by titre and sorted by versions
    and listing associated semestres
    returns a table
    """
    formations = context.formation_list(formation_id=formation_id, args=args)
    title = "Programmes pédagogiques"
    lockicon = scu.icontag(
        "lock32_img", title="Comporte des semestres verrouillés", border="0"
    )
    suppricon = scu.icontag(
        "delete_small_img", border="0", alt="supprimer", title="Supprimer"
    )
    editicon = scu.icontag(
        "edit_img", border="0", alt="modifier", title="Modifier titres et code"
    )

    editable = REQUEST.AUTHENTICATED_USER.has_permission(ScoChangeFormation, context)

    # Traduit/ajoute des champs à afficher:
    for f in formations:
        try:
            f["parcours_name"] = sco_codes_parcours.get_parcours_from_code(
                f["type_parcours"]
            ).NAME
        except:
            f["parcours_name"] = ""
        f["_titre_target"] = "ue_list?formation_id=%(formation_id)s" % f
        f["_titre_link_class"] = "stdlink"
        # Ajoute les semestres associés à chaque formation:
        f["sems"] = sco_formsemestre.do_formsemestre_list(
            context, args={"formation_id": f["formation_id"]}
        )
        f["sems_list_txt"] = ", ".join([s["session_id"] for s in f["sems"]])
        f["_sems_list_txt_html"] = ", ".join(
            [
                '<a class="discretelink" href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(session_id)s<a>'
                % s
                for s in f["sems"]
            ]
            + [
                '<a class="stdlink" href="formsemestre_createwithmodules?formation_id=%(formation_id)s&amp;semestre_id=1">ajouter</a>'
                % f
            ]
        )
        if f["sems"]:
            f["date_fin_dernier_sem"] = max([s["date_fin_iso"] for s in f["sems"]])
            f["annee_dernier_sem"] = f["date_fin_dernier_sem"].split("-")[0]
        else:
            f["date_fin_dernier_sem"] = ""
            f["annee_dernier_sem"] = ""
        locked = context.formation_has_locked_sems(f["formation_id"])
        #
        if locked:
            but_locked = lockicon
        else:
            but_locked = '<span class="but_placeholder"></span>'
        if editable and not locked:
            but_suppr = (
                '<a class="stdlink" href="formation_delete?formation_id=%s">%s</a>'
                % (f["formation_id"], suppricon)
            )
        else:
            but_suppr = '<span class="but_placeholder"></span>'
        if editable:
            but_edit = (
                '<a class="stdlink" href="formation_edit?formation_id=%s">%s</a>'
                % (f["formation_id"], editicon)
            )
        else:
            but_edit = '<span class="but_placeholder"></span>'
        f["buttons"] = ""
        f["_buttons_html"] = but_locked + but_suppr + but_edit
    # Tri par annee_denier_sem, type, acronyme, titre, version décroissante
    formations.sort(key=itemgetter("version"), reverse=True)
    formations.sort(key=itemgetter("titre"))
    formations.sort(key=itemgetter("acronyme"))
    formations.sort(key=itemgetter("parcours_name"))
    formations.sort(
        key=itemgetter("annee_dernier_sem"), reverse=True
    )  # plus recemments utilises en tete

    #
    columns_ids = (
        "buttons",
        "acronyme",
        "parcours_name",
        "formation_code",
        "version",
        "titre",
        "sems_list_txt",
    )
    titles = {
        "buttons": "",
        "acronyme": "Acro.",
        "parcours_name": "Type",
        "titre": "Titre",
        "version": "Version",
        "formation_code": "Code",
        "sems_list_txt": "Semestres",
    }
    return GenTable(
        columns_ids=columns_ids,
        rows=formations,
        titles=titles,
        origin="Généré par %s le " % VERSION.SCONAME + scu.timedate_human_repr() + "",
        caption=title,
        html_caption=title,
        table_id="formation_list_table",
        html_class="formation_list_table table_leftalign",
        html_with_td_classes=True,
        html_sortable=True,
        base_url="%s?formation_id=%s" % (REQUEST.URL0, formation_id),
        page_title=title,
        pdf_title=title,
        preferences=context.get_preferences(),
    )
