package kohonenSOM;

import java.applet.*;
import java.awt.*;
import java.io.*;
import java.util.Arrays;
import java.util.ArrayList;

import javax.swing.JPanel;

import round.Roundness;

public class SOMDemoCodebook {

	public double run(int[] countGrapheme, int[] number2, int[][] number1, int numberResult) {
		
		this.countGrapheme = new int[countGrapheme.length];
		for (int i = 0; i < countGrapheme.length; i++) {
			this.countGrapheme[i] = countGrapheme[i];
			countGraphemeAll = countGraphemeAll + this.countGrapheme[i];
		}
		
		//System.out.println("countGrapheme "+countGrapheme);
		som_width = (int)(Math.sqrt(countGraphemeAll));
		som_height = (int)(Math.sqrt(countGraphemeAll));
		
		//System.out.println("som_width "+som_width);
		//System.out.println("som_height "+som_height);
		
		this.countGraphemeAll = som_height * som_width;
	//	System.out.println("this.countGraphemeAll "+this.countGraphemeAll);
		
		for (int i = 0; i < countGrapheme.length - 1; i++) {
			this.countGrapheme[i] = countGraphemeAll / numberResult;
		//	System.out.println("this.countGrapheme[i] "+this.countGrapheme[i]);
		}
		this.countGrapheme[this.countGrapheme.length - 1] = countGraphemeAll - ( (countGraphemeAll / numberResult) * (this.countGrapheme.length -1));
		//System.out.println("this.countGrapheme[countGrapheme.length - 1] "+this.countGrapheme[this.countGrapheme.length - 1]);
		
		//System.out.println("countGraphemeAll "+this.countGraphemeAll);
		this.numberResult = numberResult;
		
		this.number2 = new int[number2.length];
		for (int i = 0; i < number2.length; i++) {
			this.number2[i] = number2[i];
		}
		this.number1 = new int[number1.length][];
		for (int i = 0; i < number1.length; i++) {
			this.number1[i] = new int[number1[i].length];
			for (int j = 0; j < number1[i].length; j++) {
				this.number1[i][j] = number1[i][j];
			}
		}
		initSOM();
		for (int i = 0; i <= end; i++) {
			updateSOM(i);
			
			System.runFinalization();
			System.gc();
		}
		vysledok = Roundness.roundTwoDecimal(vysledok);

		return vysledok;
	}
	
	public void initSOM() {
		readGraphemes();
		som = new SelfOrganisingMap(num_inputs, som_width, som_height);
		som.setInitialLearningRate(0.1);
		som.setUseGaussianUpdate(false);
		som.setWrapBorders(false);
		som.init();
		som.getOutputs(outputs);
		weights = som.getWeights(weights);

		//inputs[0] = 0.5;
		//inputs[1] = 0.5;
/*		for (int i = 0; i < inputs.length; i++) {
			inputs[i] = grapheme[numberOfInput][i];
		}
		numberOfInput++;*/
	}

	public void updateSOM(int epoch)
	{
	//	inputs[0] = Math.random(); //<0, 1)
//		inputs[1] = Math.random();
		
		//System.out.println("numResultGraph "+numResultGraph);
		//System.out.println("numberOfInput "+numberOfInput);
		//System.out.println("grapheme.length "+grapheme.length);
		//System.out.println("numberOfInput "+numberOfInput);
		
		for (int i = 0; i < inputs.length; i++) {
			inputs[i] = grapheme[numResultGraph][numberOfInput][i];
		}
		if (numberOfInput == (countGrapheme[numResultGraph]-1)) {
			if (numResultGraph < numberResult -1)
				numResultGraph++;
			else 
				numResultGraph = 0;
			numberOfInput = 0;
		} else 
			numberOfInput++;
		som.train(inputs);
		
		weights = som.getWeights(weights);

		//	System.out.println("weights[x][y][w] ");
		if (epoch == end) {	
			
			int indexY[] = new int[countGraphemeAll];
			int indexX[] = new int[countGraphemeAll];
			int indexNumRes[] = new int[countGraphemeAll];
			int indexNumRes2[] = new int[countGraphemeAll];
			int s = 0;
			
			
			for (int d = 0; d < grapheme.length; d++) {
				
				for (int i = 0; i < grapheme[d].length; i++) {
					double difference = 23324232;
					for (int y = 0; y < weights.length; y++) {
						//System.out.println("weights[y][0][0] "+weights[y][0][0]);
						for (int x = 0; x < weights[y].length; x++) {
							double dif = 0;
							for (int w = 0; w < weights[y][x].length; w++) {
								dif = dif + Math.pow(weights[y][x][w] - grapheme[d][i][w], 2);
							}
							dif = Math.sqrt(dif);
							//System.out.println("dif "+dif);
							if (dif < difference) {
								difference = dif;
								indexY[s] = y;
								indexX[s] = x;
								indexNumRes[s] = d;
								indexNumRes2[s] = i;
							}
						}
						
					}
				//	System.out.println("s, dif, indexY, indexX "+s+" "+difference+" "+indexY[s]+" "+indexX[s]);
					s++;
					//System.out.println("i, dif, indexY, indexX ");
				}
			}

/*			for (int i = 0; i < indexX.length; i++) {
				System.out.println("i, dif, indexY, indexX "+i+" "+indexY[i]+" "+indexX[i]);
			}*/
			try{
				File file = new File ("pics//graphemes//codebook//vysl.txt");
				FileWriter fw = new FileWriter(file);
				BufferedWriter bw = new BufferedWriter(fw);
				
				ArrayList result = new ArrayList();
			//	int[][] result = new int[som_width][som_height];
				int nerataj = 0;
				
				for (int i = 0; i < som_width; i++) {
					for (int j = 0; j < som_height; j++) {
						//boolean zero = true;
						int count = 0;
						int[] countNumRes = new int[numberResult];
						for (int k = 0; k < indexX.length; k++) {
							if ( (indexX[k] ==j) && (indexY[k] ==i) ) {
								//System.out.println("indexNumRes[k] "+indexNumRes[k]);
								//System.out.println("indexNumRes2[k] "+indexNumRes2[k]);
								//System.out.println("k "+graphemeName[indexNumRes[k]][indexNumRes2[k]]);
								bw.write(graphemeName[indexNumRes[k]][indexNumRes2[k]]+" ");
								//zero = false;
								count++;
								countNumRes[Integer.parseInt(graphemeName[indexNumRes[k]][indexNumRes2[k]].substring(0, 1))]++;
							}
						}
						if (count > 1) {
							//bw.write("\n");
							//System.out.println("dalsi");
							int numberOption = 0;
/*							if ((count % 2) == 0)
								numberOption = (count / numberResult);
							else*/
								numberOption = (count / numberResult) + 1;
							
							//System.out.println("numberOption "+numberOption);
							
							int percento = 0;
							if ((numberOption - 1) != 0) percento = 100 / (numberOption - 1);
							//System.out.println("percento "+percento);
							
							int[] groupPercent = new int[numberOption];
							for (int k = 0; k < numberOption; k++) {
								groupPercent[k] = (count - k) * (0 + k);
								//System.out.println("groupPercent[k] "+groupPercent[k]);
							}
							
							int vynasobim = 1;
							for (int k = 0; k < countNumRes.length; k++) {
								vynasobim = vynasobim * countNumRes[k]; 
							}
							//System.out.println("vynasobim "+vynasobim);
							
							int res = 0;
							for (int k = 0; k < groupPercent.length; k++) {
								if (vynasobim == groupPercent[k])
									res = percento * k;
							}
							for (int k = 0; k < count; k++) {
								result.add(res);
							}
							//System.out.println("res "+res);
							//System.out.println();
							
/*							if (count == 1)
								nerataj++;*/
						}
					}
				}		
				int sum = 0;
				//int countSum = 0;
				for (int i = 0; i < result.size(); i++) {
					//for (int j = 0; j < result[i].length; j++) {
						sum = sum + (Integer)(result.get(i));
						//countSum++;
					//}
				}
				//countSum = countSum - nerataj;
				//System.out.println("sum "+sum);
				//System.out.println("countGraphemeAll "+countGraphemeAll);
				//System.out.println("(sum/countGraphemeAll) "+(sum/countGraphemeAll));
				vysledok = ((double)(sum) / (double)(result.size()) );
				//System.out.println("(sum / result.size() ) "+vysledok);
				
				bw.close();
				fw.close();
				
			} catch (Exception e) {
		//		System.out.println("chyba v pisani "+e.getMessage());
			}
			
		}
/*		if (epoch == 200) {	
			
			for (int y = 0; y < weights.length; y++)
				for (int x = 0; x < weights[y].length; x++) {
					try{
						File file = new File ("D://_Docs//ROBOTA//WORKSPACE-ECLIPSE//adel//pics//graphemes//new//"+y+"a"+x+".txt");
					//	File file = new File ("pics\\graphemes\\new\\asd.txt");
						FileWriter fw = new FileWriter(file);
						BufferedWriter bw = new BufferedWriter(fw);
					//	System.out.println("weights[y][x].length "+weights[y][x].length);
						for (int w = 0; w < weights[y][x].length; w++) {
							if (((w % scale) == 0) && (w != 0))
								bw.newLine();
							
							bw.write(Double.toString(weights[y][x][w])+" ");
							if (weights[y][x][w] == 0)
								bw.write("0 ");
							else
								bw.write("1 ");
						}
						bw.close();
					} catch (Exception e) {
						System.out.println("chyba v pisani");
					}

				}
					//System.out.println();
					///System.out.println();
		}*/			

		if ((epoch % 100) == 0)
		//	System.out.println("epoch "+epoch);
		epoch++;
	}
	
	private double length(double[] A){
		double count = 0;
		for (int i = 0; i < A.length; i++) {
			count = count + A[i];
		}
	    return count;
	}
	
	private double[][] Normalise(double[][] A){
		for (int i = 0; i < A.length; i++) {
			double len = length(A[i]);
			if (len > 0) {
				for (int j = 0; j < A[i].length; j++) {
					A[i][j] = A[i][j] / len;
				}
			}
		}
		return A;
	}
	
	private void readGraphemes(){

		grapheme = new double[numberResult][][];
		graphemeName = new String[numberResult][];
	//	Arrays.fill(graphemeName[numberResult], "");
		
		for (int r = 0; r < numberResult; r++) {
			
			grapheme[r] = new double[countGrapheme[r]][scale * scale];
			graphemeName[r] = new String[countGrapheme[r]];
			Arrays.fill(graphemeName[r], "");
			
			int h = 0;
			int q = 0;
			int l = -1;
			for (int t = 0; t < number2[r]; t++) {
		//		System.out.println("number1[r][q] "+number1[r][q]);
				for (int k = 0; k < number1[r][q]; k++) {
					//for (int l = 0; l < number2; l++) {
				//		for (int k = 0; k < number1[q]; k++) {
						if (k == 0) l++;
			//			System.out.println("k "+k+", l "+l);
						try{
							FileReader fr = new FileReader("pics//graphemes//"+r+"//"+r+"a"+k+"a"+l+".txt");
							BufferedReader br = new BufferedReader(fr);
							int n = 0;
							for (int i = 0; i < scale; i++) {
								String line = br.readLine();
								for (int j = 0; j < scale; j++) {
									//System.out.println("h, n "+h+" "+n);
									if (h < grapheme[r].length) {
										grapheme[r][h][n] = Integer.parseInt(line.substring(0, line.indexOf(' ')));
										n++;
									}
									line = line.substring(line.indexOf(' ') + 1, line.length());
								}
							}
							br.close();
							fr.close();
			//				System.out.println("h "+h);
			//				System.out.println("graphemeName[r].length "+graphemeName[r].length);
							if (h < graphemeName[r].length) { //docasne riesenie
								graphemeName[r][h] =  graphemeName[r][h].concat(r+"a"+k+"a"+l+".txt");
			//					System.out.println("graphemeName[r][h] "+graphemeName[r][h]);
							}
							h++;
						}catch (Exception e) {
							System.out.println("chyba pri citani "+e.getMessage());
						}
					//}
				}
				q++;
			}
			
				//normalise vector
			grapheme[r] = Normalise(grapheme[r]);
/*				for (int i = 0; i < grapheme.length; i++) {
					for (int j = 0; j < grapheme[i].length; j++) {
						//System.out.println("grapheme[i][j] "+grapheme[i][j]);
					}
				}*/

		}

	}
	
	double vysledok = 0;
	double[][][] grapheme;//vstup
	String[][] graphemeName;//vstup
	int scale = 30; 
	int[][] number1;
	int[] number2;
	int[] countGrapheme;
	int countGraphemeAll;
	int numberResult;
	
	private SelfOrganisingMap som;
	private int som_width = 30;
	private int som_height = 30;
	private int num_inputs = scale * scale;//2;
	private int numberOfInput = 0;
	private int numResultGraph = 0;

	private double[] inputs = new double[num_inputs];
	private double[][] outputs = new double[som_width][som_height];
	private double[][][] weights = new double[som_width][som_height][num_inputs];

	private int end = 200;
	
	// 5000, 30 * 30,  1min 43 sek, 26% 2 rozne (sloboda1, unew)
//	 5000, 30 * 30,  1min 37 sek, 64% 2 rovnake (muller1, muller2)
	
//	 3000, 30 * 30,  1min 25 sek, 67% 2 rovnake (muller1, muller2)

	
//	 1000, 30 * 30,  1min 12 sek, 68% 2 rovnake (muller1, muller2)
	
//	 1000, 20 * 20,  38 sek, 73% 2 rovnake (muller1, muller2)	
	
//	 1000, 15 * 15,  26 sek, 69% 2 rovnake (muller1, muller2)	
	
//	 1000, 10 * 10,  17 sek, 83% 2 rovnake (muller1, muller2)	zleeee
	
//	 500, 15 * 15,  23 sek, 74% 2 rovnake (muller1, muller2)	
}
