#########################################
### Définition du programme principal ###
#########################################

##################################################################

### Importation des modules utiles

import tkinter
import sys
import menu
import classes

##################################################################

### Définition des fonctions d'affectation des molécules à partir des menus déroulants

def affectation_molecule1(quoi_que_ce_soit):
    global molecule1
    molecule1 = menu_choix_molecule1.get()
    molecule1 = molecule1.replace("é", "e")
    molecule1 = molecule1.replace("è", "e")
    
    
def affectation_molecule2(quoi_que_ce_soit):
    global molecule2
    molecule2 = menu_choix_molecule2.get()
    molecule2 = molecule2.replace("é", "e")
    molecule2 = molecule2.replace("è", "e")

### Définition de la fonction d'ouverture des fichiers correspondants aux
### molécules sélectionnées

def ouverture():
    global molecule1
    global molecule2
    global fichier_molecule1
    global fichier_molecule2
    sys.path.append("fichiers_molecules")
    fichier_molecule1 = __import__(molecule1)
    fichier_molecule2 = __import__(molecule2)

### Définition de la fonction servant à sélectionner les orbitales
### qui interagiront (les plus proches en énergie)

def comparaison_et_selection_des_OF(fichier1, fichier2):
    '''Renvoie la liste des deux OF qui vont interagir à partir des fichiers des molécules'''
    energieHO1 = fichier1.molecule.HO.energie
    energieBV1 = fichier1.molecule.BV.energie
    energieHO2 = fichier2.molecule.HO.energie
    energieBV2 = fichier2.molecule.BV.energie
    if abs(energieHO1 - energieBV2) < abs(energieBV1 - energieHO2):
        return([fichier1.molecule.HO, fichier2.molecule.BV])
    else:
        return([fichier1.molecule.BV, fichier2.molecule.HO])

### Définition de la fonction servant à déterminer quelle sera l'interaction principale

def interaction_principale(liste_des_deux_OF):
    '''Renvoie une liste de structure [[OF1, atome_de_plus gros coefficient de l'OF1], [...]]'''
    orb_mol1 = liste_des_deux_OF[0]
    orb_mol2 = liste_des_deux_OF[1]
    couples1 = orb_mol1.tableau_de_coeffs.couple_atome_coeff
    couples2 = orb_mol2.tableau_de_coeffs.couple_atome_coeff
    
    coeff_max_1 = 0
    for i in range(1, len(couples1)):
        if abs(couples1[i][1]) >= coeff_max_1:
            coeff_max_1 = abs(couples1[i][1])
            atome1 = couples1[i][0]
            
    coeff_max_2 = 0
    for i in range(1, len(couples2)):
        if abs(couples2[i][1]) >= coeff_max_2:
            coeff_max_2 = abs(couples2[i][1])
            atome2 = couples2[i][0]

    return([[orb_mol1, atome1], [orb_mol2, atome2]])


### Définition de la fonction servant à déterminer quelle sera l'interaction secondaire et
### si elle sera favorable

def interaction_secondaire(liste_des_deux_OF):
    '''Renvoie une liste de structure \
       [favorable ou non (format str),\
       [OF1, atome de l'interaction secondaire de l'OF1],\
       [OF2, atome de l'interaction secondaire de l'OF2]]'''
    orb_mol1 = liste_des_deux_OF[0]
    orb_mol2 = liste_des_deux_OF[1]
    couples1 = orb_mol1.tableau_de_coeffs.couple_atome_coeff
    couples2 = orb_mol2.tableau_de_coeffs.couple_atome_coeff

    coeff_max_1 = 0
    for i in range(1, len(couples1)):
        if abs(couples1[i][1]) >= coeff_max_1:
            coeff_max_1 = abs(couples1[i][1])
            atome_max1 = couples1[i][0]
            
    coeff_max_2 = 0
    for i in range(1, len(couples2)):
        if abs(couples2[i][1]) >= coeff_max_2:
            coeff_max_2 = abs(couples2[i][1])
            atome_max2 = couples2[i][0]

    try:
        couples1.remove([atome_max1, coeff_max_1])
    except ValueError:
        couples1.remove([atome_max1, -coeff_max_1])

    try:
        couples2.remove([atome_max2, coeff_max_2])
    except ValueError:
        couples2.remove([atome_max2, -coeff_max_2])

    coeff_sec_1 = 0
    for i in range(1, len(couples1)):
        if abs(couples1[i][1]) >= coeff_sec_1:
            coeff_sec_1 = abs(couples1[i][1])
            atome_sec1 = couples1[i][0]
            
    coeff_sec_2 = 0
    for i in range(1, len(couples2)):
        if abs(couples2[i][1]) >= coeff_sec_2:
            coeff_sec_2 = abs(couples2[i][1])
            atome_sec2 = couples2[i][0]

    if (coeff_max_1 * coeff_max_2 > 0 and coeff_sec_1 * coeff_sec_2 > 0) or \
       (coeff_max_1 * coeff_max_2 < 0 and coeff_sec_1 * coeff_sec_2 < 0):
        fav_ou_pas = 'favorable'
    else:
        fav_ou_pas = 'défavorable'

    return([fav_ou_pas, [orb_mol1, atome_sec1], [orb_mol2, atome_sec2]])

    

### Définition de la super fonction de la mort qui va être exécutée l'air de rien lorsque
### l'utilisateur cliquera sur Combiner

def fonction_principale():
    '''Ouvre la fenêtre de résultat de la tentative d'interaction entre les deux molécules sélectionnées'''
    ouverture()
    principale = interaction_principale(comparaison_et_selection_des_OF(fichier_molecule1, fichier_molecule2))
    secondaire = interaction_secondaire(comparaison_et_selection_des_OF(fichier_molecule1, fichier_molecule2))


    fenetre_result = tkinter.Toplevel()
    fenetre_result.title("Fuuuuuuuuuuuusion !")
    #fenetre_result.geometry("800x600+100+50")


    # Ligne 1 : on affiche les noms des molécules
    
    tkinter.Label(fenetre_result, text = fichier_molecule1.molecule.nom, font=("Arial",25)).grid(row = 0, column = 0)
    tkinter.Label(fenetre_result, text = fichier_molecule2.molecule.nom, font=("Arial",25)).grid(row = 0, column = 1)


    # Ligne 2 : on affiche par quelle orbitale (HO ou BV) elles pourraient réagir

    tkinter.Label(fenetre_result, text = "(Réaction par sa " + principale[0][0].nature + ")").grid(row = 1, column = 0)
    tkinter.Label(fenetre_result, text = "(Réaction par sa " + principale[1][0].nature + ")").grid(row = 1, column = 1)


    # Ligne 3 : on affiche les images des molécules
    
    pre_image1 = tkinter.PhotoImage(file = "images/" + molecule1 + ".gif")
    largeur1 = pre_image1.width() ; hauteur1 = pre_image1.height()
    fond1 = tkinter.Canvas(fenetre_result, width = 300, height = 300, bg = 'white')
    fond1.grid(row = 2, column = 0)
    image1 = fond1.create_image(150, 150, image = pre_image1)
    
    pre_image2 = tkinter.PhotoImage(file = "images/" + molecule2 + ".gif")
    largeur2 = pre_image2.width() ; hauteur2 = pre_image2.height()
    fond2 = tkinter.Canvas(fenetre_result, width = 300, height = 300, bg = 'white')
    fond2.grid(row = 2, column = 1)
    image2 = fond2.create_image(150, 150, image = pre_image2)


    # Lignes 4 et 5 : On indique quels atomes de chaque molécule interagissent

    prim1 = 'Interaction principale : atome ' + principale[0][1].nature_lettres() + ' n°' + str(principale[0][1].numero)
    tkinter.Label(fenetre_result, text = prim1).grid(row = 4, column = 0)

    prim2 = 'Interaction principale : atome ' + principale[1][1].nature_lettres() + ' n°' + str(principale[1][1].numero)
    tkinter.Label(fenetre_result, text = prim2).grid(row = 4, column = 1)

    sec1 = 'Interaction secondaire (' + secondaire[0] + ') : atome ' + secondaire[1][1].nature_lettres() + \
           ' n°' + str(secondaire[1][1].numero)
    tkinter.Label(fenetre_result, text = sec1).grid(row = 5, column = 0)
    
    sec2 = 'Interaction secondaire (' + secondaire[0] + ') : atome ' + secondaire[2][1].nature_lettres() + \
           ' n°' + str(secondaire[2][1].numero)
    tkinter.Label(fenetre_result, text = sec2).grid(row = 5, column = 1)

    # Ligne 6 : on qualifie l'intensité de l'interaction envisagée

    ecart_E = abs(principale[0][0].energie - principale[1][0].energie)
    proba = "NaN"
    if ecart_E < 2:
        proba = "tout à fait possible"
    elif ecart_E < 4:
        proba = "possible"
    else:
        proba = "assez improbable"
    texte_interaction = "L'écart énergétique est de " + str(ecart_E) + " eV, une interaction orbitalaire est donc " + proba + "."
    txt = tkinter.Label(fenetre_result, text = texte_interaction)
    txt.grid(row = 6, column = 0, columnspan = 2)

    #Ligne 7 : Bouton retour pour quitter la fenêtre

    tkinter.Button(fenetre_result, text = "Retour", command = fenetre_result.destroy).grid(row = 7, column = 0, columnspan = 2)

    
    fenetre_result.mainloop() # Sans cette mainloop l'image n'est pas affichée...
    

##################################################################
    
### Création de la structure de l'interface

# Création de la fenêtre "conteneur"

fenetre = tkinter.Tk()
fenetre.title("Simulateur de réactions")
fenetre.geometry("800x600+100+50")

# Le bouton quitter, qui ferme la fenêtre et donc le programme

bouton_quitter = tkinter.Button(fenetre, text="Quitter", command=fenetre.destroy)
bouton_quitter.pack(side = tkinter.RIGHT)

# Les deux menus déroulants de choix des molécules

menu_choix_molecule1 = tkinter.StringVar()
menu_choix_molecule1.set("Choisissez une molécule")
option_menu1 = tkinter.OptionMenu(fenetre, menu_choix_molecule1, *menu.menu, command = affectation_molecule1)
option_menu1.pack(side = tkinter.TOP)


menu_choix_molecule2 = tkinter.StringVar()
menu_choix_molecule2.set("Choisissez une molécule")
option_menu2 = tkinter.OptionMenu(fenetre, menu_choix_molecule2, *menu.menu, command = affectation_molecule2)
option_menu2.pack(side = tkinter.TOP)


# Le bouton combiner qui va lancer la fonction centrale du programme avec
# les deux molécules choisies en variables d'entrée

bouton_combiner = tkinter.Button(fenetre, text = "Combiner", \
                                 command = fonction_principale)
bouton_combiner.pack()


# Très important, la fonction mainloop() permet d'éviter la fermeture de la
# fenêtre avant que ne soient éxecutées des actions

fenetre.mainloop()
