"""

    Version 1.0
    Date 27/03/2025
    Auteur : Stéphan Peccini

    Ce script met à jour les valeurs ihh en fonction des données
    de part de marché des pays où des acteurs.
    https://fr.wikipedia.org/wiki/Indice_de_Herfindahl-Hirschmann

    Important :
    -----------------------
    Pour faciliter le travail, tout est fait avec un graphe NetworkX et ensuite sauvé
    au format DOT sans aucune structure hiérarchique.
    Il suffit alors de passer le fichier résultat dans beautify.py pour avoir un fichier
    DOT conforme aux attentes.

"""

import networkx as nx
from networkx.drawing.nx_pydot import write_dot
import sys
import re

def calcul_ihh(graphe, depart, arrivee):
    ihh = 0
    print("Appel à calcul_ihh")
    for noeud in arrivee:
        print(f"nœud : {noeud}")
        print(depart)
        print(arrivee)
        if depart in noeud: # Gestion simplifiée de l'intégration des Connexes
            print("Départ dans le nœud")
            if arrivee not in list(graphe.successors(depart)):
                depart_2 = list(graphe.predecessors(noeud))[0]
                relation = graphe.get_edge_data(depart_2, noeud)
            else:
                relation = graphe.get_edge_data(depart, noeud)
            print(relation)
            print(relation['label'])
            ihh_inter = int(int(relation['label'].strip("%"))**2)
            print(ihh_inter)
            ihh += ihh_inter
            print(ihh)
    ihh = int(round(ihh/100))
    return ihh

def mettre_a_jour_ihh(graph, noeuds):
    for noeud in noeuds:
        sous_graphe = nx.DiGraph()
        try:
            for chemin in nx.edge_bfs(graph, source=noeud):
                sous_graphe.add_edge(*chemin)

            # Ajouter les attributs des nœuds
            for node in sous_graphe.nodes():
                if node in graph.nodes():
                    sous_graphe.nodes[node].update(graph.nodes[node])

            # Ajouter les attributs des arêtes
            for edge in sous_graphe.edges():
                if edge in graph.edges():
                    sous_graphe.edges[edge].update(graph.edges[edge])

            niveaux_ihh = nx.get_node_attributes(sous_graphe, "niveau")
            operation = noeud.split('_')[0]

            # La hiérarchie Traitement est particulière. En effet, les acteurs du traitement se fournissent
            # auprès des acteurs de l'extraction. Il y a une relations entre chaque acteur de traitement
            # et les pays auprès desquels il se fournit en minerai.
            if "Traitement" in operation:
                noeuds_pays_ihh = [n for n, v in niveaux_ihh.items() if (v == "11" or v == "1011") and operation in n]
                noeuds_acteurs_ihh = [n for n, v in niveaux_ihh.items() if (v == "12" or v == "1012") and operation in list(sous_graphe.predecessors(n))[0]]

            else:
                noeuds_pays_ihh = [n for n, v in niveaux_ihh.items() if (v == "11" or v == "1011")]
                noeuds_acteurs_ihh = [n for n, v in niveaux_ihh.items() if (v == "12" or v == "1012")]

            # Le calcul de l'indice de Herfindahl-Hirschmann se fait normalement au niveau d'une entreprise.
            # Toutefois, il se fait au niveau des pays et au niveau des acteurs pour l'opération qui est menée.
            ihh_pays = calcul_ihh(sous_graphe, noeud, noeuds_pays_ihh)
            nx.set_node_attributes(graph, {noeud: {"ihh_pays": f"{ihh_pays}"}})
            ihh_acteurs = calcul_ihh(sous_graphe, noeud, noeuds_acteurs_ihh)
            nx.set_node_attributes(graph, {noeud: {"ihh_acteurs": f"{ihh_acteurs}"}})

        except nx.NetworkXNoPath:
            pass  # Ignore les chemins inexistants

    return graph

def mettre_a_jour_ihh_reserves(graph, noeuds):
    for noeud in noeuds:
        sous_graphe = nx.DiGraph()
        try:
            for chemin in nx.edge_bfs(graph, source=noeud):
                sous_graphe.add_edge(*chemin)

            # Ajouter les attributs des nœuds
            for node in sous_graphe.nodes():
                if node in graph.nodes():
                    sous_graphe.nodes[node].update(graph.nodes[node])

            # Ajouter les attributs des arêtes
            for edge in sous_graphe.edges():
                if edge in graph.edges():
                    sous_graphe.edges[edge].update(graph.edges[edge])

            niveaux_ihh = nx.get_node_attributes(sous_graphe, "niveau")

            noeuds_pays_ihh = [n for n, v in niveaux_ihh.items() if (v == "11" or v == "1011")]

            # Le calcul de l'indice de Herfindahl-Hirschmann se fait normalement au niveau d'une entreprise.
            # Toutefois, il se fait au niveau des pays et au niveau des acteurs pour l'opération qui est menée.
            ihh_pays = calcul_ihh(sous_graphe, noeud, noeuds_pays_ihh)
            nx.set_node_attributes(graph, {noeud: {"ihh_pays": f"{ihh_pays}"}})

        except nx.NetworkXNoPath:
            pass  # Ignore les chemins inexistants

    return graph

def main():
    """ Fonction principale pour interagir avec l'utilisateur. """
    if len(sys.argv) != 3:
        print("Usage: python ihh.py fichier_en_entree.dot fichier_en_sortie.dot")
        return

    fichier_en_entree = sys.argv[1]
    fichier_en_sortie = sys.argv[2]

    graph = nx.DiGraph(nx.nx_agraph.read_dot(fichier_en_entree))
    niveaux = nx.get_node_attributes(graph, "niveau")

    noeuds_niveau_10 = [n for n, v in niveaux.items() if (v == "10" or v == "1010") and not re.search(r'Reserves', n)]
    noeuds_niveau_10.sort()

    graphe = mettre_a_jour_ihh(graph, noeuds_niveau_10)

    noeuds_niveau_10 = [n for n, v in niveaux.items() if (v == "10" or v == "1010") and re.search(r'Reserves', n)]
    noeuds_niveau_10.sort()

    graphe = mettre_a_jour_ihh_reserves(graphe, noeuds_niveau_10)

    write_dot(graphe, fichier_en_sortie)

if __name__ == "__main__":
    main()
