import tkinter as tk     		#Sert à la création d'interfaces
from tkinter import messagebox
import os				#Pour les opérations relatives aux chemins et les emplacements des fichiers 
import matplotlib.pyplot as plt		#Pour les créations de grahiques
import shutil  				#Utilisé pour la copie et le déplacement de fichiers  
import xml.etree.ElementTree as ET	#Pour l'intéraction avec Inkscape
import base64
import numpy as np			#Bibliothèque mathématique
import subprocess 
import sys
import json


# Format: (Z, 'Symbol', 'Nom en anglais', 'Groupe', col, row)

elements = [
    (1, 'H', 'Hydrogen', 'Nonmetal', 1, 1),
    (2, 'He', 'Helium', 'Noble gas', 18, 1),
    (3, 'Li', 'Lithium', 'Alkali metal', 1, 2),
    (4, 'Be', 'Beryllium', 'Alkaline earth metal', 2, 2),
    (5, 'B', 'Boron', 'Metalloid', 13, 2),
    (6, 'C', 'Carbon', 'Nonmetal', 14, 2),
    (7, 'N', 'Nitrogen', 'Nonmetal', 15, 2),
    (8, 'O', 'Oxygen', 'Nonmetal', 16, 2),
    (9, 'F', 'Fluorine', 'Halogen', 17, 2),
    (10, 'Ne', 'Neon', 'Noble gas', 18, 2),
    (11, 'Na', 'Sodium', 'Alkali metal', 1, 3),
    (12, 'Mg', 'Magnesium', 'Alkaline earth metal', 2, 3),
    (13, 'Al', 'Aluminium', 'Post-transition metal', 13, 3),
    (14, 'Si', 'Silicon', 'Metalloid', 14, 3),
    (15, 'P', 'Phosphorus', 'Nonmetal', 15, 3),
    (16, 'S', 'Sulfur', 'Nonmetal', 16, 3),
    (17, 'Cl', 'Chlorine', 'Halogen', 17, 3),
    (18, 'Ar', 'Argon', 'Noble gas', 18, 3),
    (19, 'K', 'Potassium', 'Alkali metal', 1, 4),
    (20, 'Ca', 'Calcium', 'Alkaline earth metal', 2, 4),
    (21, 'Sc', 'Scandium', 'Transition metal', 3, 4),
    (22, 'Ti', 'Titanium', 'Transition metal', 4, 4),
    (23, 'V', 'Vanadium', 'Transition metal', 5, 4),
    (24, 'Cr', 'Chromium', 'Transition metal', 6, 4),
    (25, 'Mn', 'Manganese', 'Transition metal', 7, 4),
    (26, 'Fe', 'Iron', 'Transition metal', 8, 4),
    (27, 'Co', 'Cobalt', 'Transition metal', 9, 4),
    (28, 'Ni', 'Nickel', 'Transition metal', 10, 4),
    (29, 'Cu', 'Copper', 'Transition metal', 11, 4),
    (30, 'Zn', 'Zinc', 'Post-transition metal', 12, 4),
    (31, 'Ga', 'Gallium', 'Post-transition metal', 13, 4),
    (32, 'Ge', 'Germanium', 'Metalloid', 14, 4),
    (33, 'As', 'Arsenic', 'Metalloid', 15, 4),
    (34, 'Se', 'Selenium', 'Nonmetal', 16, 4),
    (35, 'Br', 'Bromine', 'Halogen', 17, 4),
    (36, 'Kr', 'Krypton', 'Noble gas', 18, 4),
    (37, 'Rb', 'Rubidium', 'Alkali metal', 1, 5),
    (38, 'Sr', 'Strontium', 'Alkaline earth metal', 2, 5),
    (39, 'Y', 'Yttrium', 'Transition metal', 3, 5),
    (40, 'Zr', 'Zirconium', 'Transition metal', 4, 5),
    (41, 'Nb', 'Niobium', 'Transition metal', 5, 5),
    (42, 'Mo', 'Molybdenum', 'Transition metal', 6, 5),
    (43, 'Tc', 'Technetium', 'Transition metal', 7, 5),
    (44, 'Ru', 'Ruthenium', 'Transition metal', 8, 5),
    (45, 'Rh', 'Rhodium', 'Transition metal', 9, 5),
    (46, 'Pd', 'Palladium', 'Transition metal', 10, 5),
    (47, 'Ag', 'Silver', 'Transition metal', 11, 5),
    (48, 'Cd', 'Cadmium', 'Post-transition metal', 12, 5),
    (49, 'In', 'Indium', 'Post-transition metal', 13, 5),
    (50, 'Sn', 'Tin', 'Post-transition metal', 14, 5),
    (51, 'Sb', 'Antimony', 'Metalloid', 15, 5),
    (52, 'Te', 'Tellurium', 'Metalloid', 16, 5),
    (53, 'I', 'Iodine', 'Halogen', 17, 5),
    (54, 'Xe', 'Xenon', 'Noble gas', 18, 5),
    (55, 'Cs', 'Caesium', 'Alkali metal', 1, 6),
    (56, 'Ba', 'Barium', 'Alkaline earth metal', 2, 6),
    (100000000000000000000000000000000000000000000000000, '-', 'Lanthanides', 'Lanthanide', 3, 6),    #placeholder pour l'affichage du tableau
    (57, 'La', 'Lanthanum', 'Lanthanide', 3, 9),
    (58, 'Ce', 'Cerium', 'Lanthanide', 4, 9),
    (59, 'Pr', 'Praseodymium', 'Lanthanide', 5, 9),
    (60, 'Nd', 'Neodymium', 'Lanthanide', 6, 9),
    (61, 'Pm', 'Promethium', 'Lanthanide', 7, 9),
    (62, 'Sm', 'Samarium', 'Lanthanide', 8, 9),
    (63, 'Eu', 'Europium', 'Lanthanide', 9, 9),
    (64, 'Gd', 'Gadolinium', 'Lanthanide', 10, 9),
    (65, 'Tb', 'Terbium', 'Lanthanide', 11, 9),
    (66, 'Dy', 'Dysprosium', 'Lanthanide', 12, 9),
    (67, 'Ho', 'Holmium', 'Lanthanide', 13, 9),
    (68, 'Er', 'Erbium', 'Lanthanide', 14, 9),
    (69, 'Tm', 'Thulium', 'Lanthanide', 15, 9),
    (70, 'Yb', 'Ytterbium', 'Lanthanide', 16, 9),
    (71, 'Lu', 'Lutetium', 'Lanthanide', 17, 9),
    (72, 'Hf', 'Hafnium', 'Transition metal', 4, 6),
    (73, 'Ta', 'Tantalum', 'Transition metal', 5, 6),
    (74, 'W', 'Tungsten', 'Transition metal', 6, 6),
    (75, 'Re', 'Rhenium', 'Transition metal', 7, 6),
    (76, 'Os', 'Osmium', 'Transition metal', 8, 6),
    (77, 'Ir', 'Iridium', 'Transition metal', 9, 6),
    (78, 'Pt', 'Platinum', 'Transition metal', 10, 6),
    (79, 'Au', 'Gold', 'Transition metal', 11, 6),
    (80, 'Hg', 'Mercury', 'Post-transition metal', 12, 6),
    (81, 'Tl', 'Thallium', 'Post-transition metal', 13, 6),
    (82, 'Pb', 'Lead', 'Post-transition metal', 14, 6),
    (83, 'Bi', 'Bismuth', 'Post-transition metal', 15, 6),
    (84, 'Po', 'Polonium', 'Post-transition metal', 16, 6),
    (85, 'At', 'Astatine', 'Halogen', 17, 6),
    (86, 'Rn', 'Radon', 'Noble gas', 18, 6),
    (87, 'Fr', 'Francium', 'Alkali metal', 1, 7),
    (88, 'Ra', 'Radium', 'Alkaline earth metal', 2, 7),
    (200000000000000000000000000000000000000000000000000, '_', 'Actinides', 'Actinide', 3, 7),       #placeholder pour l'affichage du tableau
    (89, 'Ac', 'Actinium', 'Actinide', 3, 10),
    (90, 'Th', 'Thorium', 'Actinide', 4, 10),
    (91, 'Pa', 'Protactinium', 'Actinide', 5, 10),
    (92, 'U', 'Uranium', 'Actinide', 6, 10),
    (93, 'Np', 'Neptunium', 'Actinide', 7, 10),
    (94, 'Pu', 'Plutonium', 'Actinide', 8, 10),
    (95, 'Am', 'Americium', 'Actinide', 9, 10),
    (96, 'Cm', 'Curium', 'Actinide', 10, 10),
    (97, 'Bk', 'Berkelium', 'Actinide', 11, 10),
    (98, 'Cf', 'Californium', 'Actinide', 12, 10),
    (99, 'Es', 'Einsteinium', 'Actinide', 13, 10),
    (100, 'Fm', 'Fermium', 'Actinide', 14, 10),
    (101, 'Md', 'Mendelevium', 'Actinide', 15, 10),
    (102, 'No', 'Nobelium', 'Actinide', 16, 10),
    (103, 'Lr', 'Lawrencium', 'Actinide', 17, 10),
    (104, 'Rf', 'Rutherfordium', 'Transition metal', 4, 7),
    (105, 'Db', 'Dubnium', 'Transition metal', 5, 7),
    (106, 'Sg', 'Seaborgium', 'Transition metal', 6, 7),
    (107, 'Bh', 'Bohrium', 'Transition metal', 7, 7),
    (108, 'Hs', 'Hassium', 'Transition metal', 8, 7),
    (109, 'Mt', 'Meitnerium', 'none', 9, 7),
    (110, 'Ds', 'Darmstadtium', 'none', 10, 7),
    (111, 'Rg', 'Roentgenium', 'none', 11, 7),
    (112, 'Cn', 'Copernicium', 'Transition metal', 12, 7),
    (113, 'Nh', 'Nihonium', 'none', 13, 7),
    (114, 'Fl', 'Flerovium', 'none', 14, 7),
    (115, 'Mc', 'Moscovium', 'none', 15, 7),
    (116, 'Lv', 'Livermorium', 'none', 16, 7),
    (117, 'Ts', 'Tennessine', 'none', 17, 7),
    (118, 'Og', 'Oganesson', 'none', 18, 7),
]





buttons = {}
class PeriodicTableApp:					#Création d'un objet 
	def __init__(self, master):			#Fonction qui se lance automatiquement lors de la création de l'objet
		self.master = master			#Permet de combiner la fenêtre tkinter à l'objet
		self.last_clicked = None  		#Création d'une variable pour stocker le dernier click effectué
		for (num, sym, name, fam, col, row) in elements: 		#Parcourt la liste des éléments 
			btn = tk.Button(master, text=sym, width=5, height=2,  font=("Georgia", 11, "bold"), command=lambda s=sym: self.on_click(s))		#Paramètres d'affichage du bouton
			btn.grid(row=row, column=col)			#Grille des boutons avec les coordonnées
			buttons[sym] = btn
		for (num, sym, name, fam, *_) in elements :           #Donne au couleur au bouton selon le groupe de l'élément
			if fam == "Halogen" : 
				buttons[sym].config(bg="yellow")
				buttons[sym].config(fg="black")
			elif fam == "Nonmetal" :
				buttons[sym].config(bg="light green")
				buttons[sym].config(fg="black")
			elif fam == "Transition metal" :
				buttons[sym].config(bg="pink")
				buttons[sym].config(fg="black")
			elif fam == "Noble gas" :
				buttons[sym].config(bg="steelblue")
				buttons[sym].config(fg="white")
			elif fam == "Post-transition metal" :
				buttons[sym].config(bg="gray")
				buttons[sym].config(fg="black")
			elif fam == "Metalloid" :
				buttons[sym].config(bg="brown")
				buttons[sym].config(fg="black")
			elif fam == "Alkali metal" :
				buttons[sym].config(bg="red")
				buttons[sym].config(fg="black")
			elif fam == "Alkaline earth metal" :
				buttons[sym].config(bg="orange")
				buttons[sym].config(fg="black")
			elif fam == "Lanthanide" :
				buttons[sym].config(bg="blue")
				buttons[sym].config(fg="white")
			elif fam == "Actinide" :
				buttons[sym].config(bg="purple")
				buttons[sym].config(fg="white")
			elif fam == "none":
				buttons[sym].config(fg="white")
				buttons[sym].config(bg="black")

			

	def on_click(self, symbol):			#Fonction qui s'active lors d'un click sur un bouton
		famille=""
		for i in range(len(elements)) :							#Parcourt la liste d'éléments 
			if symbol in elements[i] and len(symbol)==len(elements[i][1]) :	
				famille=elements[i][3]
				name=elements[i][2]
				num=elements[i][0]
		buttons[symbol].config(bg="white")			#Le bouton sélectionné devient blanc


		if famille == "Halogen" : 
			buttons[symbol].config(fg="gold")
		elif famille == "Nonmetal" :
			buttons[symbol].config(fg="green")
		elif famille == "Transition metal" :
			buttons[symbol].config(fg="deeppink")
		elif famille == "Noble gas" :
			buttons[symbol].config(fg="steelblue")
		elif famille == "Post-transition metal" :
			buttons[symbol].config(fg="dimgray")
		elif famille == "Metalloid" :
			buttons[symbol].config(fg="brown")
		elif famille == "Alkali metal" :
			buttons[symbol].config(fg="red")
		elif famille == "Alkaline earth metal" :
			buttons[symbol].config(fg="darkorange")
		elif famille == "Lanthanide" :
			buttons[symbol].config(fg="blue")
		elif famille == "Actinide" :
			buttons[symbol].config(fg="purple")
		elif famille == "none":
			buttons[symbol].config(fg="black")






#		buttons[symbol].config(fg="black")                      #Le texte du bouton sélectionné devient noir
		self.last_clicked = symbol		#Stocke le symbole dans la variable 
		print("Clic sur :", name, "-", symbol, "-", num, f"({famille})")		#Affiche dans le terminal l'élément clické (symbol)



		reponse = messagebox.askokcancel("Group of the element ?", f"Click on {name} ({symbol}), Do you want to select the rest of the group ({famille})?") 
		if reponse is True :
			for (num, sym, name, fam, *_) in elements :
				if fam == famille : 				#Sélection du groupe entier
					buttons[sym].config(bg="white")
					
					if famille == "Halogen" : 
						buttons[sym].config(fg="gold")
					elif famille == "Nonmetal" :
						buttons[sym].config(fg="green")
					elif famille == "Transition metal" :
						buttons[sym].config(fg="deeppink")
					elif famille == "Noble gas" :
						buttons[sym].config(fg="steelblue")
					elif famille == "Post-transition metal" :
						buttons[sym].config(fg="dimgray")
					elif famille == "Metalloid" :
						buttons[sym].config(fg="brown")
					elif famille == "Alkali metal" :
						buttons[sym].config(fg="red")
					elif famille == "Alkaline earth metal" :
						buttons[sym].config(fg="darkorange")
					elif famille == "Lanthanide" :
						buttons[sym].config(fg="blue")
					elif famille == "Actinide" :
						buttons[sym].config(fg="purple")
					elif famille == "none":
						buttons[sym].config(fg="black")

#					buttons[sym].config(fg="black")

			print(f"Selecting the {famille} group")
			reponse2 = messagebox.askokcancel("Group engraving", f"Click on {famille}, create a file ?")
			if reponse2 is True :

				list_col=[[] for i in range(18)]
				for (num, sym, name, fam, col, row) in elements :
					if fam == famille :	#Boucle pour la création d'une liste regroupant les infos du groupe sélectionné
						if sym == "-" or sym == "_":
							continue   #Exclue les placholders s'il y en a
						list_data=[]
						list_data.append(sym)
						list_data.append(num)
						list_data.append(name)
						list_data.append(fam)
						list_data.append(col)
						list_data.append(row)
						list_col[col-1].append(list_data)
				print(list_col)

#Création du .svg
				width_mm = 600
				height_mm = 300
				square_size=80
				square_sizeh=60
				stroke_width=1
				svg_content = f'''<?xml version="1.0" encoding="UTF-8"?>
			<svg xmlns="http://www.w3.org/2000/svg" width="600mm" height="300mm">

'''

				for i in range(len(list_col)):
					for j in range(len(list_col[i])):
						x = 50 + i * square_size  # Each square starts exactly where previous ends
						y = 50 + list_col[i][j][5] * square_sizeh
						svg_content += f'  <rect x="{x}" y="{y}" width="{square_size}" height="{square_sizeh}"	fill="none" stroke="blue" stroke-width="{stroke_width}"/>'
						svg_content += f'  <rect x="{x}" y="{y+700}" width="{square_size}" height="{square_sizeh}"	fill="none" stroke="red" stroke-width="{stroke_width}"/>'
						text_x=x+square_size/2
						text_y=y+square_sizeh/2
        
						text_content_sym = str(list_col[i][j][0])
						if len(str(list_col[i][j][0]))==1:
							font_size = square_size * 0.55
						if len(str(list_col[i][j][0]))==2: 
							font_size = square_size * 0.50 
						svg_content += f'''  <text x="{text_x-0.1}" y="{text_y-4}" 
						text-anchor="middle" dominant-baseline="middle"
						font-size="{font_size}" font-family="Elephant" fill="black">{text_content_sym}</text>
'''

						
						text_content_num = str(list_col[i][j][1])
						if len(str(list_col[i][j][1]))==1:
							font_size = square_size * 0.68
						if len(str(list_col[i][j][1]))==2: 
					   		font_size = square_size * 0.63 
						if len(str(list_col[i][j][1]))==3: 
							font_size = square_size * 0.48 
						svg_content += f'''  <text x="{text_x}" y="{text_y}" 
						text-anchor="middle" dominant-baseline="middle"
						font-size="{font_size}" font-family="Elephant" fill="none" stroke="blue" stroke-width="{stroke_width * 0.3}">{text_content_num}</text>

						
'''

    
						text_content_name = str(list_col[i][j][2])
						if len(str(list_col[i][j][2]))>4 and len(str(list_col[i][j][2]))<9:
							font_size = (square_size * 0.2)/(len(str(list_col[i][j][2]))*0.18)
						elif len(str(list_col[i][j][2]))<5 :
							font_size = (square_size * 0.2)/(len(str(list_col[i][j][2]))*0.3)
						elif len(str(list_col[i][j][2]))>5 :
							font_size = (square_size * 0.2)/(len(str(list_col[i][j][2]))*0.14)
						svg_content += f'''  <text x="{text_x-0.1}" y="{text_y+19}" 
						text-anchor="middle" dominant-baseline="middle"
						font-size="{font_size}" font-family="Elephant" fill="black">{text_content_name}</text>
'''			

				svg_content += '</svg>'
    
				with open(f'{famille}grp.svg', 'w') as f:
					f.write(svg_content)
    
				print(f"SVG created: {famille}grp")
				os.startfile(f"D:/fbalba/prog/{famille}grp.svg")   #Ouvre le .svg


						
			if reponse2 is False :					#Pour que les boutons récupèrent leur couleur originale s'ils ne sont plus sélectionnés
				for (num, sym, name, fam, *_) in elements :
					if fam == famille : 
						if famille == "Halogen" : 
							buttons[sym].config(bg="yellow")
							buttons[sym].config(fg="black")
						elif famille == "Nonmetal" :
							buttons[sym].config(bg="light green")
							buttons[sym].config(fg="black")
						elif famille == "Transition metal" :
							buttons[sym].config(bg="pink")
							buttons[sym].config(fg="black")
						elif famille == "Noble gas" :
							buttons[sym].config(bg="steelblue")
							buttons[sym].config(fg="white")
						elif famille == "Post-transition metal" :
							buttons[sym].config(bg="gray")
							buttons[sym].config(fg="black")
						elif famille == "Metalloid" :
							buttons[sym].config(bg="brown")
							buttons[sym].config(fg="black")
						elif famille == "Alkali metal" :
							buttons[sym].config(bg="red")
							buttons[sym].config(fg="black")
						elif famille == "Alkaline earth metal" :
							buttons[sym].config(bg="orange")
							buttons[sym].config(fg="black")
						elif famille == "Lanthanide" :
							buttons[sym].config(bg="blue")
							buttons[sym].config(fg="white")
						elif famille == "Actinide" :
							buttons[sym].config(bg="purple")
							buttons[sym].config(fg="white")
						elif famille == "none":
							buttons[sym].config(fg="white")
							buttons[sym].config(bg="black")
			
		
		if reponse is False : 
			reponse3 = messagebox.askokcancel("Element engraving", f"Click on {name} ({symbol}), create a file ?")
			
			if reponse3 is True :				
				JSON_PATH = f"{symbol}.json"			#Crée un fichier .json 
				with open(JSON_PATH, "w", encoding="utf-8") as f:		#Rédige le .json avec la case à cliquer 
					json.dump({"symbol": symbol}, f, ensure_ascii=False, indent=2)
				subprocess.Popen(["start", "powershell",  "-NoExit", "-Command", "python updaterunna.py"], shell=True)
# la ligne précédente ouvre un autre powershell et lance updaterunna.py dans celui-ci. Ce porgramme lit ensuite le .json le plus récent du dossier pour cliquer la case voulue.


			if reponse3 is False :						#Pour que les boutons récupèrent leur couleur originale s'ils ne sont plus sélectionnés
				if famille == "Halogen" : 
					buttons[symbol].config(bg="yellow")
					buttons[symbol].config(fg="black")
				elif famille == "Nonmetal" :
					buttons[symbol].config(bg="light green")
					buttons[symbol].config(fg="black")
				elif famille == "Transition metal" :
					buttons[symbol].config(bg="pink")
					buttons[symbol].config(fg="black")
				elif famille == "Noble gas" :
					buttons[symbol].config(bg="steelblue")
					buttons[symbol].config(fg="white")
				elif famille == "Post-transition metal" :
					buttons[symbol].config(bg="gray")
					buttons[symbol].config(fg="black")
				elif famille == "Metalloid" :
					buttons[symbol].config(bg="brown")
					buttons[symbol].config(fg="black")
				elif famille == "Alkali metal" :
					buttons[symbol].config(bg="red")
					buttons[symbol].config(fg="black")
				elif famille == "Alkaline earth metal" :
					buttons[symbol].config(bg="orange")
					buttons[symbol].config(fg="black")
				elif famille == "Lanthanide" :
					buttons[symbol].config(bg="blue")
					buttons[symbol].config(fg="white")
				elif famille == "Actinide" :
					buttons[symbol].config(bg="purple")
					buttons[symbol].config(fg="white")
				elif famille == "none":
					buttons[symbol].config(fg="white")
					buttons[symbol].config(bg="black")
			
			
		

root = tk.Tk()				#Permet de créer la fenêtre
root.configure(bg="white")
root.title("Periodic Table")	#Nom de la fenêtre 
app = PeriodicTableApp(root)		#Permet à l'objet PeriodicTableApp de s'afficher dans la fenêtre 
root.mainloop()				#Fait fonctionner la fenêtre jusqu'à sa fermeture

