package clustering;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.FileReader;

import java.util.*;

import round.Roundness;

public class Hierarchical {
	
	int[] pocet;
	//int numberResult;
	int scale = 30;
	
	int numberImage;
	int[] numberResult;
	
	//numberresult je pocet obrazkov, zatial bude 2
/*	public Hierarchical(int numberResult) {
		this.numberResult = numberResult;
		pocet = new int[numberResult];
	}*/
	
	public Hierarchical(int numberImage, int[] numberResult) {
		this.numberImage = numberImage;
		this.numberResult = new int[numberImage];
		this.numberResult = numberResult;
		System.out.println("numberResult[0]Hier "+numberResult[0]);
		System.out.println("numberResult[1]Hier "+numberResult[1]);			
		pocet = new int[numberImage];
	}	
	
	class Grapheme {
		int[][] value;
		int numberResult;//ktory je to z obrazkov //nesie info o tom, ku ktoremu obrazku patri
		boolean uzVybraty = false; //info o tom ci uz bol zaradadeny do clustera
		String name;
	}
	
	//jeden cluster
	class Cluster {
		int number; //pocet graphem v clusteri
		ArrayList g = new ArrayList(); //cisla grafem
		boolean uzVybraty = false; //info o tom ci uz bol zaradadeny do clustera
	}	
	
	//chceme z kazdej ulozenej grafemy ziskat 2jice kde je cierny bod
	//tj x_0,y_0 x_1,y_1,...
	public double[] obtainFeatures(){
		
		for (int i = 0; i < numberImage; i++) {
			//open file
			try{
				FileReader fr = new FileReader("pics\\graphemes\\"+numberResult[i]+"\\info2.txt");
				BufferedReader br = new BufferedReader(fr);
				String line = br.readLine();
				pocet[i] = Integer.parseInt(line);
				System.out.println("pocet "+pocet[i]);
				br.close();
				fr.close();
			} catch (Exception e) {
				System.out.println(e.getMessage());
			}		
		}
		////////////
		/////////////	
		///////
		//////
		int pocVsetGrap = 0;
		//na zaciatku mame v kazdom clusteri 1 graphemu
		for (int i = 0; i < pocet.length; i++) {
			pocVsetGrap = pocVsetGrap + pocet[i];
		}
		///////////
		Grapheme[] g = new Grapheme[pocVsetGrap];

		int n = 0;	
			
		for (int i = 0; i < numberImage; i++) {
			
			for (int j = 0; j < pocet[i]; j++) {
				
				g[n] = new Grapheme();
				g[n].value = new int[scale][scale];
				//open file
				try{
					FileReader fr = new FileReader("pics\\graphemes\\"+numberResult[i]+"\\"+numberResult[i]+"a"+j+".txt");
					BufferedReader br = new BufferedReader(fr);
					for (int k = 0; k < scale; k++) {
						String line = br.readLine(); //1 riadok ma 40 cisel
					//	System.out.println("line "+line);
						for (int index = 0; index < scale; index++) {
							String l = line.substring(0, line.indexOf(' '));
							//System.out.println("l "+l);
							//	System.out.println(i+"a"+j+".txt");
							//	System.out.println("k "+k);
							//	System.out.println("index "+index);
							g[n].value[k][index] = Integer.parseInt(l);
							g[n].numberResult = numberResult[i];
							g[n].name = numberResult[i]+"a"+j+".txt";
							//System.out.println("g[i][k][index] "+g[i][k][index]);
							line = line.substring(line.indexOf(' ') + 1, line.length());		
						}					
					}
					br.close();
					fr.close();
				} catch (Exception e) {
					System.out.println(e.getMessage());
				}	
				
				n++;
			}
		}	
		//////////////////////////////
		//na zaciatku mame pocVsetGrap clusterov
		ArrayList clus = new ArrayList();
		
		for (int i = 0; i < pocVsetGrap; i++) {
			if (!g[i].uzVybraty) { //este nie je v ziadnom novom clusteri
				//hladam najblizsiu graphemu
				double distance = 456440;
				int najlepsiaGrap = 0;
				for (int j = 0; j < pocVsetGrap; j++) {
					if ( (i != j) && (!g[j].uzVybraty) ) {
						//System.out.println("EuclidianDistance(g[i], g[j]) "+EuclidianDistance(g[i], g[j]));
						double euclid = EuclidianDistance(g[i], g[j], distance);
						//System.out.println("euclid +"+euclid);
						if (distance > euclid) {
							distance = euclid;
							najlepsiaGrap = j;
						}
					}
				}
			//	System.out.println("najlepsiaGrap "+najlepsiaGrap);
				Cluster c = new Cluster();
				c.number = 1;
				c.g.add(i);
				if (distance != 456440) {
					c.g.add(najlepsiaGrap);
					g[najlepsiaGrap].uzVybraty = true;
					c.number = 2;
				}
				g[i].uzVybraty = true;
				clus.add(c);
			}
		}
/*		////
		for (int i = 0; i < clus.size(); i++) {
			Cluster c = (Cluster)(clus.get(i));
		//	int podobnost = 0;
			for (int j = 0; j < c.g.size(); j++) {
				//System.out.println("g[(Integer)(c.g.get(j))].numberResult"+g[(Integer)(c.g.get(j))].numberResult+" "+g[(Integer)(c.g.get(j))].name);
				
			}
			//System.out.println("");
		}*/
		
		int podobnost = 0;
		for (int i = 0; i < clus.size(); i++) {
			Cluster c = (Cluster)(clus.get(i));
			if (c.g.size() > 1)
				if ( g[(Integer)(c.g.get(0))].numberResult == g[(Integer)(c.g.get(1))].numberResult )
					podobnost++;
		}
		System.out.println("clus.size() "+clus.size());
		System.out.println("v jednom clustreri od rovnakeho autora "+podobnost);
		
		double percento = ((double)(podobnost) / ((double)(clus.size()) / (double)(100)));
		percento = Roundness.roundTwoDecimal(percento);
		System.out.println("percento: "+percento);
		
		////////////////////////////
		//////////////////////////////
		//mame clus.size() clusterov
		ArrayList clus2 = new ArrayList();
		
		for (int i = 0; i < clus.size(); i++) {
			Cluster c1 = (Cluster)(clus.get(i));
			if (!c1.uzVybraty) { //este nie je v ziadnom novom clusteri
				//hladam najblizsiu graphemu
				double distance = 456440;
				Cluster najlepsiaGrap = new Cluster();
				for (int j = 0; j < clus.size(); j++) {
					Cluster c2 = (Cluster)(clus.get(j));
					if ( (i != j) && (!c2.uzVybraty) ) {
						//System.out.println("EuclidianDistance(g[i], g[j]) "+EuclidianDistance(g[i], g[j]));
						double euclid = EuclidianDistance2(c1, c2, g, distance);
						if (distance > euclid) {
							distance = euclid;
							najlepsiaGrap = c2;
						}
					}
				}
			//	System.out.println("najlepsiaGrap "+najlepsiaGrap);
				Cluster c = new Cluster();
				c.number = c1.number + najlepsiaGrap.number;
				for (int j = 0; j < c1.number; j++) 
					c.g.add((Integer)(c1.g.get(j)));
				if (distance != 456440) {
					for (int j = 0; j < najlepsiaGrap.number; j++) 
						c.g.add((Integer)(najlepsiaGrap.g.get(j)));
					najlepsiaGrap.uzVybraty = true;
				}
				c1.uzVybraty = true;
				clus2.add(c);
			}
		}
		////////////////////////////
/*		for (int i = 0; i < clus2.size(); i++) {
			Cluster c = (Cluster)(clus2.get(i));
		//	int podobnost = 0;
			for (int j = 0; j < c.g.size(); j++) {
			//	System.out.println("g[(Integer)(c.g.get(j))].numberResult"+g[(Integer)(c.g.get(j))].numberResult+" "+g[(Integer)(c.g.get(j))].name);
				
			}
			//System.out.println("");
		}
*/		/////////////////////////////////
		int[] podobnost2 = new int[3];
		double[] percento2 = new double[4];
		percento2[0] = percento;
		
		for (int i = 0; i < clus2.size(); i++) {
			Cluster c = (Cluster)(clus2.get(i));
			if (c.g.size() > 3) {
				int sum = 0;
				for (int j = 0; j < c.number; j++) {
					sum = sum + g[(Integer)(c.g.get(j))].numberResult;
					//System.out.println("g[(Integer)(c.g.get(j))].numberResult "+g[(Integer)(c.g.get(j))].numberResult);
				}	
				
				if ( (sum == (numberResult[0]*4))  || (sum == (numberResult[1]*4)))
				//if ((sum == 4) || (sum == 0))
					podobnost2[0]++;
				//if ((sum == 3) || (sum == 1))
				//	podobnost2[1]++;	
				//if (sum == 2) 
				//	podobnost2[2]++;				
			}
		}
		System.out.println("clus.size() "+clus2.size());
		for (int i = 0; i < podobnost2.length; i++) {
			System.out.println("podobnost2 "+podobnost2[i]);
		}
		for (int i = 0; i < podobnost2.length; i++) {
			percento2[i+1] = ((double)(podobnost2[i]) / ((double)(clus2.size()) / (double)(100)));
			percento2[i+1] = Roundness.roundTwoDecimal(percento2[i+1]);
			System.out.println("percento2[i+1] "+percento2[i+1]);
		}
		//////////////////////////////////////////

		return percento2;
	}
	
	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("Clustering FINALIZED");
		super.finalize();
	}
	
	private double EuclidianDistance(Grapheme g1, Grapheme g2, double distance){
		double dif = 0;
		for (int i = 0; i < scale; i++) {
			for (int j = 0; j < scale; j++) {
				dif = dif + Math.pow(g1.value[i][j] - g2.value[i][j], 2);
				//System.out.println("dif "+dif);
				if (Math.sqrt(dif) > distance) 
					return Math.sqrt(dif);
			}
		}
		dif = Math.sqrt(dif);
		return dif;
	}
	
	private double EuclidianDistance2(Cluster c1, Cluster c2, Grapheme[] g, double distance){
		double dif = 0;
	//	System.out.println("c1.number "+c1.number);
	//	System.out.println("c2.number "+c2.number);
	//	System.out.println("(c1.number * c2.number) "+(c1.number * c2.number));
		for (int i = 0; i < c1.number; i++) {
			for (int j = 0; j < c2.number; j++) {
				dif = dif + EuclidianDistance(g[(Integer)(c1.g.get(i))], g[(Integer)(c2.g.get(j))], 4545454);
				if ( (dif / (c1.number * c2.number)) > distance) 
					return (dif / (c1.number * c2.number));
			}
		}
		dif = dif / (c1.number * c2.number);
		return dif;
	}	
	
/*	public static void main(String[] args) {
		Hierarchical c = new Hierarchical(2);
		c.obtainFeatures();
	}*/
}
