package database.migration.etape1.client;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import tool.regEx.Adresse;
import database.dataset.Client;
import database.dataset.Groupe;
import database.dataset.Telephone;
import database.dataset.TelephoneType;
import database.dataset.Ville;
import database.migration.SqlFactory;

public class NormalisedClient {
	private final Set<Ville> villes;
	private final Set<Adresse> adresses;
	private final Set<Client> clients;
	private final Set<Groupe> groupes;
	private final Set<Telephone> telephones;
	private final Set<TelephoneType> telephones_type;
	private final Map<Integer, Integer> list_de_client_deduplique;
	
	public NormalisedClient(Set<Ville> villes, Set<Adresse> adresses,
			Set<Client> clients, Set<Groupe> groupes, Set<Telephone> telephones) {
		super();
		this.villes = villes;
		this.adresses = adresses;
		this.clients = clients;
		this.groupes = groupes;
		this.telephones = telephones;
		this.telephones_type = new HashSet<>();
		telephones_type.add(new TelephoneType(1, "MAISON"));
		telephones_type.add(new TelephoneType(2, "TRAVAIL"));
		telephones_type.add(new TelephoneType(3, "MOBILE"));
		telephones_type.add(new TelephoneType(4, "VOIP"));
		
		this.list_de_client_deduplique = new HashMap<>();
	}

	public Set<Ville> getVilles() {
		return villes;
	}
	public Set<Adresse> getAdresses() {
		return adresses;
	}
	public Set<Client> getClients() {
		return clients;
	}
	public Set<Groupe> getGroupes() {
		return groupes;
	}
	public Set<Telephone> getTelephones() {
		return telephones;
	}

	public Set<TelephoneType> getTelephones_type() {
		return telephones_type;
	}

	/***************************************************************************
	 * 
	 **************************************************************************/	
	public static NormalisedClient from(List<ReadClient> rclst){
		System.out.println("normalise client");
		for (ReadClient rc : rclst)
			rc.normalisationDesDonnees();

		Set<Telephone> telephoneUnique = deduplicationDestelephones(rclst);
//		System.out.println("reduit le nombre de telephone à " + telephoneUnique.size());
		
		Set<Ville> villeUnique = deduplicationDesVille(rclst);
//		System.out.println("reduit le nombre de villes à " + villeUnique.size());
		
		Set<Adresse> adresseUnique = deduplicationDesAdresses(rclst);
//		System.out.println("reduit le nombre d'adresses à " + adresseUnique.size());
		
		Set<Client> clientUnique = deduplicationDesClients(rclst);
		//System.out.println("reduit le nombre de clients à " + clientUnique.size());
//		System.out.println("nous ne somme pas pret à réduire le nombre de client maintenant");
		
		Set<Groupe> groupeUnique = deduplicationDesGroupes(rclst);
//		System.out.println("reduit le nombre de groupes à " + groupeUnique.size());

		return new NormalisedClient(villeUnique, adresseUnique, clientUnique, groupeUnique, telephoneUnique);
	}
	/***************************************************************************
	 * 
	 **************************************************************************/
	/**/
	private static boolean duplicataClient(Client clientA, Client clientB){
		return clientA.getClient_nom().equals(clientB.getClient_nom()) &&
			   clientA.getClient_prenom().equals(clientB.getClient_prenom()) &&
			   clientA.getAdresse_fk_id() == clientB.getAdresse_fk_id();
	}
	
	private static Client trouverDuplicationDesClients(Client aVerifier, Set<Client> dejaVerifier){
		for (Client c : dejaVerifier)
			if (duplicataClient(c, aVerifier))
				return c;
		return null;
	}
	
	private static Set<Client> deduplicationDesClients(List<ReadClient> rclst){
//		System.out.println("recherche de duplicata de client");
		int dupeClient = 0;
		
		Set<Client> clientDejaVerifier = new HashSet<Client>();
		for (ReadClient rc : rclst){
			/*on ne peut pas déduplique les client maintenant*/
//			Client c = trouverDuplicationDesClients(rc.get_client(),clientDejaVerifier);
//			if (c==null){
				clientDejaVerifier.add(rc.get_client());
//			}
//			else{
//				//System.out.println("deduplication dans les clé et les référence");
//				rc.get_groupe().setClient_fk_id(c.getClient_p_id());
//				for (Telephone t : rc.get_telephones())
//					t.setClient_fk_id(c.getClient_p_id());
//				rc.set_client(c);
//				
//				
//				dupeClient++;
//			}
		}
//		System.out.println(dupeClient + " client dupliquées");
		
		return clientDejaVerifier;
	}
	/**/
	private static boolean duplicataGroupe(Groupe groupeA, Groupe groupeB){
		return groupeA.getGroupe_nom().equals(groupeB.getGroupe_nom()) &&
			   groupeA.getClient_fk_id() == groupeB.getClient_fk_id();
	}
	
	private static Groupe trouverDuplicationDesGroupes(Groupe aVerifier, Set<Groupe> dejaVerifier){
		for (Groupe g : dejaVerifier)
			if (duplicataGroupe(g, aVerifier))
				return g;
		return null;
	}
	
	private static Set<Groupe> deduplicationDesGroupes(List<ReadClient> rclst){
//		System.out.println("recherche de duplicata de groupe");
		int dupeGroupe = 0;
		
		Set<Groupe> groupeDejaVerifier = new HashSet<Groupe>();
		for (ReadClient rc : rclst){
			Groupe g = trouverDuplicationDesGroupes(rc.get_groupe(),groupeDejaVerifier);
			if (g==null){
				groupeDejaVerifier.add(rc.get_groupe());
			}
			else{
				//System.out.println("deduplication dans les clé et les référence");
				dupeGroupe++;
			}
		}
//		System.out.println(dupeGroupe + " groupe dupliquées");
		
		return groupeDejaVerifier;
	}
	
	/**/
	private static boolean duplicataAdresse(Adresse adresseA, Adresse adresseB){
		return adresseA.getAdresse_codepostal().equals(adresseB.getAdresse_codepostal()) &&
			   adresseA.getadresse_no_rue_app().equals(adresseB.getadresse_no_rue_app()) &&
			   adresseA.getVille_fk_id() == adresseB.getVille_fk_id();
	}
	
	private static Adresse trouverDuplicationDesAdresses(Adresse aVerifier, Set<Adresse> dejaVerifier){
		for (Adresse a : dejaVerifier){
			if (duplicataAdresse(aVerifier, a)){
				//System.out.println("Adresse dupliquées :" + aVerifier + " = " + a.toString());
				return a;
			}
		}
		return null;
	}
	
	/*mutation du paramètre*/
	private static Set<Adresse> deduplicationDesAdresses(List<ReadClient> rclst){
//		System.out.println("recherche de duplicata d Adresse");
		int dupeAdresse = 0;
		
		Set<Adresse> adresseDejaVerifier = new HashSet<Adresse>();
		for (ReadClient rc : rclst){
			Adresse a = trouverDuplicationDesAdresses(rc.get_adresse(),adresseDejaVerifier);
			if (a==null){
				adresseDejaVerifier.add(rc.get_adresse());
			}
			else{
				//System.out.println("deduplication dans les clé et les référence");
				rc.get_client().setAdresse_fk_id(a.getadresse_p_id());
				rc.set_adresse(a);
				dupeAdresse++;
			}
		}
//		System.out.println(dupeAdresse + " Adresse dupliquées");
		
		return adresseDejaVerifier;
	}
	/**/
	private static boolean duplicataVille(Ville villeA, Ville villeB){
		return villeA.getVille_nom().equals(villeB.getVille_nom()) &&
			   villeA.getVille_pays().equals(villeB.getVille_pays()) &&
			   villeA.getVille_province().equals(villeB.getVille_province());
	}
	
	private static Ville trouverDuplicationDeVille(Ville aVerifier, Set<Ville> dejaVerifier){
		for (Ville v : dejaVerifier){
			if (duplicataVille(aVerifier, v)){
				//System.out.println("villes dupliquées :" + aVerifier + " = " + v.toString());
				return v;
			}
		}
		return null;
	}
	
	/*mutation du paramètre*/
	private static Set<Ville> deduplicationDesVille(List<ReadClient> rclst){
//		System.out.println("recherche de duplicata de ville");
		int dupeVille = 0;
		
		Set<Ville> villeDejaVerifier = new HashSet<Ville>();
		for (ReadClient rc : rclst){
			Ville v = trouverDuplicationDeVille(rc.get_ville(),villeDejaVerifier);
			if (v==null){
				villeDejaVerifier.add(rc.get_ville());
			}
			else{
				//System.out.println("deduplication dans les clé et les référence");
				rc.get_adresse().setVille_fk_id(v.getville_p_id());
				rc.set_ville(v);
				dupeVille++;
			}
		}
//		System.out.println(dupeVille + " dupliquées");
		
		return villeDejaVerifier;
	}
	
	/**/
	
	private static boolean duplicataTelephone(Telephone telephoneA, Telephone telephoneB){
		return telephoneA.getTelephone_numero().equals(telephoneB.getTelephone_numero()) &&
			   telephoneA.getClient_fk_id() == telephoneB.getClient_fk_id() &&
			   telephoneA.getTelephone_type_fk_id() == telephoneB.getTelephone_type_fk_id();
	}
	
	private static Telephone trouverDuplicationDeTelephone(Telephone aVerifier, Set<Telephone> dejaVerifier){
		for (Telephone t : dejaVerifier){
			if (duplicataTelephone(aVerifier, t)){
				return t;
			}
		}
		return null;
	}
	
	/*mutation du paramètre*/
	private static Set<Telephone> deduplicationDestelephones(List<ReadClient> rclst){
//		System.out.println("recherche de duplicata de telephone");
		int dupetelephone = 0;
		
		Set<Telephone> telephoneDejaVerifier = new HashSet<Telephone>();
		for (ReadClient rc : rclst){
			for (Telephone tel : rc.get_telephones()){
				Telephone v = trouverDuplicationDeTelephone(tel,telephoneDejaVerifier);
				if (v==null){
					telephoneDejaVerifier.add(tel);
				}
				else{
					dupetelephone++;
				}
			}
		}
//		System.out.println(dupetelephone + " dupliquées");
		
		return telephoneDejaVerifier;
	}
	
	/***************************************************************************
	 * 
	 **************************************************************************/
	@SuppressWarnings("unused")
	public static void main(String ... args) throws FileNotFoundException, SQLException, IOException{
		System.out.println("connection");
		Connection connection = SqlFactory.connect(SqlFactory.loadProperties("hotel_orford_import.xml"));
		
		System.out.println("lecture massive");
		List<ReadClient> imported_client = ReadClient.loadFrom(connection);
		
		System.out.println("deconnection");
		connection.close();
		
		System.out.println("nombre de client lu : " + imported_client.size());
		
		
		NormalisedClient nc = NormalisedClient.from(imported_client);
	}
}
