from django.shortcuts import get_object_or_404, render
import os
from django.conf import settings
# Create your views here.
from django.http import HttpResponse

from recuperateur_reseau_viaire.forms import Graph_viaire_ville_informationForm, \
    Graph_viaire_ville_informationFormUpdate, Graph_viaire_ville_informationForm_delete, \
    Graph_viaire_ville_informationForm_export
from recuperateur_reseau_viaire.models import Graph_viaire_ville_information, Ville, Rassemblement_ville

from recuperateur_reseau_viaire.admin import Graph_viaire_ville_informationResource
from OSM_outils.OSMnx_recuperation_graph_information import OSMnx_recuperation_graph_information
from OSM_outils.OMSnx_enregistrement import OMSnx_enregistrement


def index(request):
    """
    Cette méthode permet de gérer entre :
     - la mise à jour de plusieurs lignes de la table
     - l'affichage de la table "Graph_viaire_ville_informationResource" de la base de données.

    :param request:
    :return: une HttpResponse de la page index.html en cas d'affichage de la table
    "Graph_viaire_ville_informationResource" le retour de la view update en cas de mise à jour de plusieurs lignes de la
     table en simultané. La création de la HttpResponse se fait à l'aide de django.template.loader.render_to_string().
    """
    if request.GET.__contains__("bouton") and request.GET.getlist("bouton")[0] == "update" \
            and request.GET.__contains__("update"):
        return update(request, request.GET.getlist("update"))
    else:
        form = Graph_viaire_ville_informationForm()
        graph_viaire_ville_information_list = Graph_viaire_ville_information.objects.all()
        return render(request, 'recuperateur_reseau_viaire/index.html',
                      {'list_graph': graph_viaire_ville_information_list, 'form': form})


def valide(request):
    """
    Cette méthode a pour but de dire à l'utilisateur qu'une action viens de se terminer

    :param request:
    :return:
    """
    print("valide !! ")
    return render(request, 'recuperateur_reseau_viaire/valide.html')


def update(request, graph_id):
    """
    Cette méthode permet de mettre à jour une ligne de la table Graph_viaire_ville_information. Elle prend en paramètre
    la requête et la clef primaire.

    Cette méthode permet de gérer l'affichage ainsi que les modifications dans la base de donnée en
    fonction du formulaire compris dans la requête.

    Le formulaire se présente sous la forme suivante : un dictionnaire cleaned_data associant à un champ de formulaire,
    la valeur donné par l'utilisateur. Nous avons ici deux champs de formulaire pour chaque variable de la table
    Graph_viaire_ville_information :
     - le champ et la valeur préremplit par la table ou modifié par l'utilisateur
     - une case à cocher, si la case à cocher lla variable est modifié par la fonction associée dans la classe
     OSMnx_recuperation_graph_information

     Lorsque le nom d'une ville est modifié, nous modifions aussi le nom du fichier. Dans le cas où un nom un autre
     fichier a le même nom, on ne le renomme pas, ni le fichier ni dans la base de donnée.

    en cas de succès la page valide.html est affichée

    :param request:
    :param graph_id:
    :return:
    """
    if isinstance(graph_id, int):
        # on modifie qu'une seule instance de graph_viaire_ville_information et de Ville
        graph_viaire_ville_information_instance = Graph_viaire_ville_information.objects.filter(id=graph_id)[0]
    elif isinstance(graph_id, list):
        # on modifie plusieurs instances de graph_viaire_ville_information et de Ville
        graph_viaire_ville_information_instance = []
        for id in graph_id:
            graph_viaire_ville_information_instance.append(Graph_viaire_ville_information.objects.filter(id=id)[0])
    else:
        #sinon c'est une erreur
        return 1
    if request.method == 'POST':
        # validation ou non et exécution du formulaire modifié par l'utilisateur
        form_u = Graph_viaire_ville_informationFormUpdate(request.POST,
                                                          initial={'valeur': graph_viaire_ville_information_instance})
        if form_u.is_valid():
            #formulaire valide execution des sauvegarde des modifications
            var_OSMnx_recuperation_graph_information = OSMnx_recuperation_graph_information(None)
            liste_fonction_recup_graph_information = var_OSMnx_recuperation_graph_information.sgbd_liste_fonction()
            tableau_associatif_nom_variable_nom_fonction = {}
            #création du lien entre les méthode provenant de OSMnx_recuperation_graph_information et les colonnes de la
            #table graph_viaire_ville_information
            for func in liste_fonction_recup_graph_information:
                retour = getattr(var_OSMnx_recuperation_graph_information, func)(None)
                nom_variable_sgbd = next(iter(retour))
                tableau_associatif_nom_variable_nom_fonction[nom_variable_sgbd] = {"nom_fonction": func}
            #créé une liste de ville si ce n'est pas une ville pour traiter la suite de la même manière
            if not isinstance(graph_viaire_ville_information_instance, list):
                graph_viaire_ville_information_instance = [graph_viaire_ville_information_instance]
            #modification des tables de la base de donnée
            for gvvi_instance in graph_viaire_ville_information_instance:
                G = OMSnx_enregistrement.lire_graphe(gvvi_instance.ville.ville_nom)
                var_OSMnx_recuperation_graph_information = OSMnx_recuperation_graph_information(G)
                for sgbd_var in dir(graph_viaire_ville_information_instance[0]):
                    #récupération des variables de classes de graph_viaire_ville_information dans le formulaire
                    #uniquement ceux ayant été modifié (les checkboxes ou les entrées manuelles)
                    if (sgbd_var.startswith("gvvi_") or sgbd_var.endswith("_id")) and \
                            (sgbd_var in form_u.changed_data or sgbd_var + '_check' in form_u.changed_data or (sgbd_var == "ville_id" and "gvvi_nom" in form_u.changed_data)):
                        #case cochée ou non
                        if form_u.cleaned_data.get(sgbd_var + '_check'):
                            gvvi_instance. \
                                __setattr__(sgbd_var,
                                            getattr(var_OSMnx_recuperation_graph_information,
                                                    tableau_associatif_nom_variable_nom_fonction[sgbd_var][
                                                        "nom_fonction"])(G)[sgbd_var])
                        elif form_u.cleaned_data.get(sgbd_var) is not None:
                            gvvi_instance.__setattr__(sgbd_var, form_u.cleaned_data[sgbd_var])
                        # modification du nom de la ville à part
                        elif sgbd_var == "ville_id":
                            ville_modification_nom = Ville.objects.filter(ville=gvvi_instance.ville_id)[0]
                            OMSnx_enregistrement.renommer_fichier_graphml(ville_modification_nom.ville_nom,
                                                                        form_u.cleaned_data["gvvi_nom"])
                            ville_modification_nom.ville_nom = form_u.cleaned_data["gvvi_nom"]
                            ville_modification_nom.save()
                gvvi_instance.save()
                #supprimmer les villes rassemblées cochées :
                ville_rassemblements_liste_instance = Rassemblement_ville.objects.\
                    filter(ville_englobante=gvvi_instance.ville_id).filter(ville__in=request.POST.getlist("ville_englobe"))
                for ville_rassemblement_instance in ville_rassemblements_liste_instance:
                    ville_rassemblement_instance.delete()
            return valide(request)
        else:
            return render(request, "recuperateur_reseau_viaire/update.html", {'form_u': form_u})
        # création du formulaire prérempli
    form_u = Graph_viaire_ville_informationFormUpdate(initial={'valeur': graph_viaire_ville_information_instance})
    liste_ville_englobe = []
    # si nous avons une liste d'instance graph_viaire_ville_information nous n'affichons pas les villes englobées
    if not isinstance(graph_viaire_ville_information_instance, list):
        for ville_englobe in Rassemblement_ville.objects.filter(ville_englobante=graph_viaire_ville_information_instance.ville_id):
            #liste_ville_englobe.append(villle_englobe)
            liste_ville_englobe.append(ville_englobe.ville)
    return render(request, "recuperateur_reseau_viaire/update.html", {'form_u': form_u, 'liste_villes_englobe': liste_ville_englobe})


def delete(request, graph_id):
    graph_viaire_ville_information_instance = Graph_viaire_ville_information.objects.filter(id=graph_id)[0]
    if request.method == 'POST':
        form_u = Graph_viaire_ville_informationForm_delete(request.POST,
                                                           initial={'valeur': graph_viaire_ville_information_instance})
        if form_u.is_valid():
            graph_viaire_ville_information_instance.gvvi_nom = form_u.cleaned_data['gvvi_nom']
            graph_viaire_ville_information_instance.gvvi_nb_intersection = form_u.cleaned_data['gvvi_nb_intersection']
            if os.path.isfile(os.path.join(settings.REGISTER_DIR, form_u.cleaned_data['gvvi_nom'] + ".graphml")):
                os.remove(os.path.join(settings.REGISTER_DIR, form_u.cleaned_data['gvvi_nom'] + ".graphml"))
            graph_viaire_ville_information_instance.delete()
            #suppression Rassemblement ville
            ville_rassemblements_liste_instance = Rassemblement_ville.objects.\
                filter(ville_englobante=graph_viaire_ville_information_instance.ville_id)
            for ville_rassemblement_instance in ville_rassemblements_liste_instance:
                ville_rassemblement_instance.delete()
            return valide(request)
    else:
        form_u = Graph_viaire_ville_informationForm_delete(initial={'valeur': graph_viaire_ville_information_instance})
        return render(request, "recuperateur_reseau_viaire/delete.html", {'form_d': form_u})


def export(request):
    if request.method == 'POST':
        form_e = Graph_viaire_ville_informationForm_export(request.POST,
                                                           initial={'formats_exports': format})
        if form_e.is_valid():
            sgbd_donnees = getattr(Graph_viaire_ville_informationResource().export(),
                                   Graph_viaire_ville_information.formats_exports[
                                       int(form_e.cleaned_data['choix_format_export'])][1])()
            fichier = open(settings.REGISTER_DIR + "/export_sgbd." + Graph_viaire_ville_information.formats_exports[
                int(form_e.cleaned_data['choix_format_export'])][1].removeprefix("get_"), "w")
            fichier.write(sgbd_donnees)
            fichier.close()
            graph_viaire_ville_information_instance = Graph_viaire_ville_information()
            return valide(request)
    else:

        form_e = Graph_viaire_ville_informationForm_export()
        return render(request, 'recuperateur_reseau_viaire/export.html', {'form_e': form_e})


def atributs_graph(request, graph_id):
    graph = get_object_or_404(Graph_viaire_ville_information, graph_id)
    return render(request, 'recuperateur_reseau_viaire/graph_id.html', {'graph': graph})


def telecharge_liste_commune(request):
    """
    Cette méthode a pour but de créer un formulaire de création de communes. Les communes peuvent être soit téléchargé
    seule, soit en en groupe.

    Elle reçoit une requête de récupération GET pour la création du formulaire et une requête de modification de la base
    de donnée POST à la fin de la validation du formulaire.

    :param request:
    :return: une HttpResponse de la page telecharge_liste_commune.html pour la création du formulaire et sa validation
    et valide.html en cas de validation du formulaire à l'aide de django.template.loader.render_to_string().
    """
    if request.method == "GET":
        form = Graph_viaire_ville_informationForm()
        return render(request, 'recuperateur_reseau_viaire/telecharge_liste_commune.html',
                      {'form': form})
    else:
        form = Graph_viaire_ville_informationForm(request.POST)
        #récupération unique des nom des villes impliqué dans la création
        nom_villes = request.POST.getlist("gvvi_nom_ajout")
        nom_villes.append(request.POST.getlist("gvvi_nom")[0])
        ville_instance_liste = Ville.objects.filter(ville_nom__in=nom_villes)
        if form.is_valid():
            graph_viaire_ville_information_instance = Graph_viaire_ville_information()
            #création de la nouvelle ville si elle n'existe pas
            if not ville_instance_liste.filter(ville_nom=request.POST.getlist("gvvi_nom")[0]).exists():
                Ville.objects.create(ville_nom=form.cleaned_data["gvvi_nom"])
            ville_ajoutee = Ville.objects.filter(ville_nom=form.cleaned_data["gvvi_nom"])[0]
            form.cleaned_data.pop("gvvi_nom")
            graph_viaire_ville_information_instance.ville_id = ville_ajoutee.ville
            for clef in form.cleaned_data.keys():
                graph_viaire_ville_information_instance.__setattr__(clef, form.cleaned_data[clef])
            graph_viaire_ville_information_instance.save()
            for nom_ville_englobe in request.POST.getlist("gvvi_nom_ajout"):
                #création des villes qui n'existent pas
                try :
                    ville_instance = Ville()
                    ville_instance.ville_nom = nom_ville_englobe
                    ville_instance.save()
                except Exception:
                    pass
            ville_instance_englobe_liste = ville_instance_liste.filter(ville_nom__in=request.POST.getlist("gvvi_nom_ajout"))
            for ville_englobe in ville_instance_englobe_liste:
                #ajout dans la table rassemblement_ville des villes faisant parties d'une ville
                rassemblement_ville_instance = Rassemblement_ville()
                rassemblement_ville_instance.ville_englobante_id = ville_ajoutee.ville
                rassemblement_ville_instance.ville_id = ville_englobe.ville
                rassemblement_ville_instance.save()
            return valide(request)
        else:
            nom_villes = request.POST.getlist("gvvi_nom_ajout")
            return render(request, 'recuperateur_reseau_viaire/telecharge_liste_commune.html',
                      {'form': form, 'nom_villes_ajout' : nom_villes})
