import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

public class BenUtil {

	public static double Levy(double a){
		if(a<=0){
			a=1;
		}
		Random random = new Random();
		double z = random.nextGaussian();
		z=1/(z*z);
		z=z*a;
		return z;
	}
	
	public static int modulo(int a, int b) throws IllegalArgumentException{
		if(b==0){
			throw new IllegalArgumentException("Nicht durch 0 dividieren");
		}
		b=Math.abs(b);
		int c = (int) Math.floor(a/b);
		a = a - c*b;
		if(a<0){
			a=a+b;
		}
		return a;
	}
	
	public static void LevyTest(double a){
		double[] list = new double[100];
		int kl=100000;
		for(int i=0;i<kl;i++){
			double l = BenUtil.Levy(a);
			if((int) l<100){
				list[(int) l]++;
			}
		}
		for(int i=0;i<100;i++){
			if((list[i]/kl)<0.001){
				list[i]=0;
			}
		}
		System.out.print("l={");
		for(int i=0;i<99;i++){
			System.out.print(list[i]/kl+",");
		}
		System.out.println(list[99]/kl+"};");
	}
	
	public static void Jumptest(int k){
		Board copy = new Board(Levy.size1,Levy.size1);
		copy.clear();
		for(int i=0;i<Levy.size2;i++){
			for(int j=0;j<Levy.size2;j++){
				copy.setInput(i, j, 3);
			}
		}
		copy.setInput(1, 1, 10);
		//copy.setInput(100, 99, 10);
		//copy.setInput(100, 100, 2);
		copy.input2board();
		
		Walk tet = new Walk(copy);
		tet.setPosition(25, 25);
		for(int i=0;i<k;i++){
			tet.setPosition(100, 100);
			tet.jump(1);
		}

		Board boo = new Board(tet.getLevycount());
		boo.input2board();
		
		boo.plot(10, 10);
		boo.plot(1.8,"blac", "Levy-Walk", Levy.data.size()[0]*Paint.pixel+30, 10);
		boo.plot(1.8,"black", "Levy-Walk black", 2*Levy.data.size()[0]*Paint.pixel+30, 10);
	}
	
	public static void mtest(String s) throws IOException{
		String Pfad = "C:\\Users\\a0504312cs\\Desktop\\Ergebnisse\\";
		Pfad = "C:\\Users\\a0504312cs\\Desktop\\";
		Pfad = s;
		
 		Levy.jump = 300000;
		for(int i=0;i<12;i++){
			Levy.jump=(Levy.jump+50000);
			System.out.println("Jump = "+Levy.jump+"; ");
			for(int j=0;j<3;j++){
				Levy.data.file2board(Pfad+"data.txt");
				Levy.ideal.file2board(Pfad+"ideal.txt");
				
				BenUtil.letitrun();
				
				Levy.cluster.board2file(Pfad+"clu"+i+"-"+j+".txt");
				double a = Levy.ideal.normmutinf(Levy.cluster, Levy.data);
				System.out.print(a+"; ");
				
			}
			System.out.println();
		}
	}
	
	public static void allezusammen(String s) throws IOException{
		
		String Pfad = s;

		int lang = 24;
		int over80 = (int) Math.floor((lang*0.8));
		int over20 = (int) Math.ceil((lang*0.2));

		int size1 = Levy.size1;
		int size2 = Levy.size2;
		//Levy.ideal.file2board(Pfad+"ideal.txt");
		//Levy.data.file2board(Pfad+"data.txt");
		
		Board[] Sammlung = new Board[lang];
		Board temp = new Board(size1,size2);
		
		for(int i=0;i<Sammlung.length;i++){
			Sammlung[i] = new Board(size1,size2);
			Sammlung[i].file2board(Pfad+"clu"+i+".txt");
			Sammlung[i].reducecolour();
			Sammlung[i].input2board();
			//Sammlung[i].plot("colour","colour",10, 10);
		}
		
		double mutinf = 0;
		for(int i=0;i<Sammlung.length;i++){
			System.out.printf("%.3f", Sammlung[i].normmutinf(Levy.ideal,Levy.data));
			System.out.print(", ");
		}	
		
		temp.clear();
		for(int k=0;k<Sammlung.length;k++){
			int m=0;
			for(int i=0;i<size1;i++){
				for(int j=0;j<size2;j++){
					if(Sammlung[k].getInput(i, j)!=0){
						m = temp.getInput(i, j);
						temp.setInput(i, j, m+1);
					}
				}
			}
		}
		temp.input2board();
		//temp.plot(10, 10);
		
		Board Bover80 = new Board(size1,size2);
		for(int i=0;i<size1;i++){
			for(int j=0;j<size2;j++){
				if(temp.getInput(i, j)<over80){
					Bover80.setInput(i, j, 0);
				} else {
					Bover80.setInput(i, j, 1);
				}
			}
		}
		Bover80.input2board();
		Bover80.plot("colour", "b80", 10, 10);
		
		Board Bover20 = new Board(size1,size2);
		for(int i=0;i<size1;i++){
			for(int j=0;j<size2;j++){
				if(temp.getInput(i, j)<over20){
					Bover20.setInput(i, j, 0);
				} else {
					Bover20.setInput(i, j, 1);
				}
			}
		}
		Bover20.input2board();
		Bover20.plot("colour", "b20", 10, 10);
		
		temp.clear();
		Levy.cluster.clear();
		Levy.colour = 1;
		for(int i=0;i<size1;i++){
			for(int j=0;j<size2;j++){
				
				if(Bover80.getInput(i, j)!=0){
					for(int k=0;k<Sammlung.length;k++){
					int hier = Sammlung[k].getInput(i, j);
						for(int m=0;m<size1;m++){
							for(int n=0;n<size2;n++){
								if(Sammlung[k].getInput(m,n)==hier){
									int te = temp.getInput(m, n);
									te++;
									temp.setInput(m, n, te);
								}
							}
						}
					}
					Board sam = new Board(size1,size2);
					sam.copy(temp);
					//sam.plot("colhour", "cluster", 600, 10);
					for(int m=0;m<size1;m++){
						for(int n=0;n<size2;n++){
							if(temp.getInput(m, n)>over20){
								Levy.cluster.setInput(m, n, Levy.colour);
								Bover80.setInput(m, n, 0);
							}
						}
					}
					sam.copy(temp);
					//sam.plot("colhour", "cluster", 600, 600);
					Levy.colour++;
					//System.out.println(Levy.colour);
					temp.clear();
				}
			}
		}		
		Levy.cluster.delete(Bover20);
		Levy.cluster.joinclusterparts();
		Levy.cluster.plot("colour", "cluster", 10, 10);
		System.out.println();
	
		System.out.println(Levy.cluster.normmutinf(Levy.ideal,Levy.data));
	}
	
	public static void weird(Board data){
		int size1 = data.size()[0];
		int size2 = data.size()[1];
		int half = (int) (size2/2);
		Random rand = new Random();
		Random ra = new Random();
		for(int i=0;i<300000;i++){
			int k = rand.nextInt(size1);
			int l = rand.nextInt(half);
			data.inputPlus(l+half, k);
		}
		for(int i=0;i<100000;i++){
			int k = rand.nextInt(size1);
			double l = ra.nextGaussian();
			if(l<0){
				data.inputPlus((int)(l*10+half), k);
			}
		}
		data.input2board();
		//data.plot(10, 10);
	}
	
	public static void weird2(Board data,int rad){
		int size1 = data.size()[0];
		int size2 = data.size()[1];
		int half = (int) (size2/2);
		Random rand = new Random();
		Random ra = new Random();
		/*for(int i=0;i<(rad/5);i++){
			int k = rand.nextInt(size2);
			int l = rand.nextInt(50);
			data.inputPlus(l, k);
		}
		for(int i=0;i<(int)(rad/5);i++){
			int k = rand.nextInt(size2);
			double l = ra.nextGaussian();
			
			if(l>0){
				if((int)(l*20+50)>0 && (int)(l*20+50)<size1){
					data.inputPlus((int)(l*20+50), k);	
				}
			}
		}*/
		for(int i=0;i<(int)(5*rad);i++){
			double l = ra.nextGaussian();
			double k = ra.nextGaussian();
			l=95*l;
			k=60*k;
			l=0.877*l+0.479*k;
			k=0.877*k-0.479*l;
			l=l+75;
			k=k+75;
			if((int)(l)>0 && (int)(l)<size1 && (int)(k)<size2 && (int)(k)>0){
				data.inputPlus((int)(l), (int)(k));	
			}
		}
		
		
		data.input2board();
		//data.plot(10, 10);
	}
	
	public static void makeCluster(){
		
		double mult=1;
		int rand = 10;
		rand = (int)(rand*Levy.size1*Levy.size1);
		
		//Levy.data.lopsidednoise((int) (rand/10));
		//Levy.data.middlesmoothnoise((int) (3*rand*mult));

		Levy.data.random(rand);
		Levy.data.TripleGauss(115, 60, 122, 54,130, 60, 3, (int) (8000*mult));
		Levy.data.Gauss(13, 15, 2, 2, (int) (2000));
		Levy.data.Gauss(105, 125, 1, 1, (int) (500));

		Position a = new Position(50,110);
		Position b = new Position(30,110);
		Levy.data.cCluster(b, 3, (int) (8000*mult));
		Levy.data.Gugel(50, 50, 8, 3, 10000);
		//Levy.data.cCluster(c, d, 1.5, 5000);

		//maindata
		/*BenUtil.weird2(Levy.data, (int) (rand*mult*1.5));
		Levy.data.random((int) (2.6*rand*mult));
		Levy.data.Gauss(13, 15, 2, 2, (int) (2000*mult));
		Levy.data.Gauss(125, 85, 1, 1, (int) (500*mult));
		Levy.data.Gauss(50, 70, 1, 1, (int) (500*mult));
		Levy.data.Gauss(130, 130, 2, 3, (int) (2500*mult));
		Levy.data.Gauss(15, 125, 2, 2, (int) (1200*mult));*/
		
		
		//against dbscan
		//BenUtil.weird(Levy.data);
	}
	
	public static void letitrun() throws IOException{
		
		Levy.cluster.clear();
		
		int connections = Board.connections;
		int stop = 100;
		int jump = Levy.jump;
		Levy.colour=1;
		
		Board sicherung = new Board(Levy.size1,Levy.size2);
		sicherung.copy(Levy.data);
		sicherung.input2board();
		
		for(int i=1;i<6;i++){
			
			int j = Levy.cluster.positivPositions();
			Levy.data.searchanddestroy(jump, connections, stop, Levy.colour);
			if(j+Levy.ignoreab>Levy.cluster.positivPositions()){
				i++;
			} 
			Levy.colour++;
			i--;
			if(Levy.plot>=0){
				System.out.println(i);
			}
		}

		Levy.cluster.joinclusterparts();
		Levy.cluster.joinclusterparts();
		
		String s=""+connections;
		if(Levy.plot==1){
			Levy.cluster.plot("colour", s, 10, 10);
			Levy.ideal.plot("colour", "jo", 400, 10);
		}
		//Levy.cluster.board2file(Pfad+"clus"+zähler+".txt");
		
		Levy.data.copy(sicherung);
		double mutinf = Levy.ideal.normmutinf(Levy.cluster, Levy.data);
		System.out.println(connections+": "+mutinf);
		
	}
	
	public static double NMI(String s, String t) throws IOException{
		double nmi=0;
		ArrayList<double[]> dat1 = BenUtil.NMIread(s);
		ArrayList<double[]> dat2 = BenUtil.NMIread(t);

		int[][] schnitt = BenUtil.schnitt(dat1, dat2);
		int i = schnitt.length;
		int j = schnitt[0].length;
		int N = dat1.size();
				
		int[] clust1 = new int[i];
		int[] clust2 = new int[j];
		for(int ki=0;ki<i;ki++){
			int a = 0;
			for(int kj=0;kj<j;kj++){
				a=a+schnitt[ki][kj];
			}
			clust1[ki]=a;
		}
		for(int kj=0;kj<j;kj++){
			int a = 0;
			for(int ki=0;ki<i;ki++){
				a=a+schnitt[ki][kj];
			}
			clust2[kj]=a;
		}
		double ent1 = 0;
		for(int k=0;k<clust1.length;k++){
			double pi=clust1[k];
			pi=pi/N;
			if(pi>0){
				ent1=ent1-pi*Math.log(pi);
			}
		}
		double ent2 = 0;
		for(int k=0;k<clust2.length;k++){
			double pi=clust2[k];
			pi=pi/N;
			if(pi>0){
				ent2=ent2-pi*Math.log(pi);
			}
		}
		double pi=0; double p2=0; double p3=0;
		for(int k1=0;k1<i;k1++){
			for(int k2=0;k2<j;k2++){
				if(schnitt[k1][k2]>0 && clust1[k1]>0 &&clust2[k2]>0){
					//pi=0; p2=0; p3=0;
					pi=(schnitt[k1][k2]);
					p2=clust1[k1];
					p3=clust2[k2];
					pi=(pi/N)*Math.log(((N*pi)/(p2*p3)));
					//System.out.println(pi);
				}
				nmi=nmi+pi;
			}
		}

		nmi=nmi/ent1/ent2;
		System.out.println(nmi);
		return nmi;
	}
	
	public static int[][] schnitt(ArrayList<double[]> dat1,ArrayList<double[]> dat2){
		int i = 0;
		int j = 0;
		int dim = dat1.get(0).length;
		for(int k=0;k<dat1.size();k++){
			if(i<dat1.get(k)[dim-1]){
				i = (int) dat1.get(k)[dim-1];
			}
			if(j<dat2.get(k)[dim-1]){
				j = (int) dat2.get(k)[dim-1];
			}
		}
		
		int[][] schnitt = new int[i+1][j+1];

		int lang = dat2.size();
		while(lang>0){
			double [] test = dat2.get(0);
			for(int k=0;k<dat1.size();k++){
				double[] comp = dat1.get(k);
				for(int l=0;l<comp.length;){
					if(test[l]==comp[l]){
						l++;
						if(l==(dim-1)){
							schnitt[(int) test[dim-1]][(int) comp[dim-1]]++;
							dat2.remove(0);
							l=comp.length;
							k=dat1.size();
						}	
					}else{
						l=test.length;
					}
				}
			}
			lang=dat2.size();
		}
		
		return schnitt;
	}
	
	public static ArrayList<double[]> NMIread(String s) throws IOException{
		ArrayList<double[]> dat = new ArrayList<double[]>();
		FileReader fr = new FileReader(s);
	    BufferedReader br = new BufferedReader(fr);
	    
	    String input = br.readLine();
		int dim = 0;
		String xa="";
		
		while(input.contains("@DATA")==false){
			input = br.readLine();
			if(input.contains("@ATTRIBUTE")==true){
				dim++;
			}
		}
		input=br.readLine();
		
		while (input != null){
			double[] ada = new double[dim];
			for(int i=0;i<dim-1;i++){
				xa = input.substring(0,input.indexOf(","));
			    input = input.substring(input.indexOf(",")+1,(input.length()));
			    double a = Double.parseDouble(xa);
			    ada[i]=a;
			}
			double ads = Double.parseDouble(input.substring(5, input.length())); 
			ada[dim-1] = ads;
			dat.add(ada);
		    input = br.readLine();
		}
		br.close();
		return dat;
	}
	
	public static void jutland(String s, String t) throws IOException{
		ArrayList<double[]> dat = new ArrayList<double[]>();
		dat = BenUtil.NMIread(s);
		double[][] data = new double[dat.size()][2];
		
		for(int i=0;i<dat.size();i++){
			data[i][0]=dat.get(i)[1];
			data[i][1]=dat.get(i)[2];
		}
		FileWriter fw = new FileWriter(t);
        BufferedWriter bw = new BufferedWriter(fw);
        bw.write("@DATA");
        bw.newLine();
        for(int i=0;i<data.length;i++){
        	bw.write(data[i][0]+","+data[i][1]);
            bw.newLine();
        }
        bw.close();
	}	
		
	public static void jut(String s, Board jut) throws IOException{
		ArrayList<double[]> dat = new ArrayList<double[]>();
		dat = BenUtil.NMIread(s);
		int size1 = jut.size()[0];
		int size2 = jut.size()[1];
		double [] x1 = new double[dat.size()];
		double [] x2 = new double[dat.size()];
		double[][] data = new double[dat.size()][2];
		double min1=dat.get(0)[1];
		double min2=dat.get(0)[2];
		double max1=dat.get(0)[1];
		double max2=dat.get(0)[2];
		for(int i=0;i<dat.size();i++){
			x1[i]=dat.get(i)[1];
			if(min1>dat.get(i)[1]){
				min1=dat.get(i)[1];
			}
			if(max1<dat.get(i)[1]){
				max1=dat.get(i)[1];
			}
			x2[i]=dat.get(i)[2];
			if(min2>dat.get(i)[2]){
				min2=dat.get(i)[2];
			}
			if(max2<dat.get(i)[2]){
				max2=dat.get(i)[2];
			}
		}
		for(int i=0;i<dat.size();i++){
			data[i][0]=(x1[i]-min1)*size1/(max1-min1);
			data[i][1]=(x2[i]-min2)*size2/(max2-min2);
		}
		for(int i=0;i<data.length;i++){
			if(0<data[i][0] && data[i][0]<size1 && 0<data[i][1] &&data[i][1]<size2){
				jut.inputPlus((int) (data[i][0]), (int) (size2-data[i][1]));
			}
		}
		jut.input2board();
	}
	
	public static Board longlat(String pfad) throws IOException{
		
		Board temp = new Board(360,180);
		FileReader fr = new FileReader(pfad);
	    BufferedReader br = new BufferedReader(fr);
	    String input = br.readLine();
	    while(input!=null){
	    	input=input.replaceAll(" ", "");
	    	int x = Integer.parseInt(input.substring(0, input.indexOf(",")));
	    	input=input.substring(input.indexOf(",")+1,input.length());
	    	int y = Integer.parseInt(input.substring(0, input.indexOf(",")));
	    	input=input.substring(input.indexOf(",")+1,input.length());
	    	double vol = Double.parseDouble(input);

	    	temp.setInput((x-1), (y-1), (int) vol);

	    	
	    	input=br.readLine();
	    }
        br.close();
        fr.close();
        return temp;
	}
	
	public static Board scale(Board temp) {
		Board data = new Board(90,90);
		for(int i=0;i<data.size()[0];i++){
			for(int j=0;j<data.size()[1];j++){
					int m1= temp.getInput((2*i)  , 2*j); 
					int m2= temp.getInput((2*i+1), 2*j); 
					int m3= temp.getInput((2*i+2), 2*j); 
					int m4= temp.getInput((2*i+3), 2*j); 
					int m=(m1+m2+m3+m4);
					data.setInput(i, j, m);
			}
		}
		data.input2board();
		return data;
	}
	
	public static void matlablist(String Pfad, Board cluster) throws IOException {
		ArrayList<int[]> dat = new ArrayList<int[]>();
		FileReader fr = new FileReader(Pfad+"againstdb.arff");
	    BufferedReader br = new BufferedReader(fr);
	    String input = br.readLine();
	    double x=0;
		double y=0;
		String xa="";
		String ya="";
		String cla="";
		while(input.contains("@DATA")==false){
			input = br.readLine();
		}
		input=br.readLine();
		while (input != null){
			xa = input.substring(0,input.indexOf(","));
		    ya = input.substring(input.indexOf(",")+1,(input.length()));
		    cla = ya.substring(ya.indexOf(",")+1,ya.length());
		    ya = ya.substring(0,ya.indexOf(","));
		    x = Double.parseDouble(xa);
		    y = Double.parseDouble(ya);
	   		int i = (int) x;
	   		int j = (int) y;
	   		int k = Integer.parseInt(cla.substring(5, cla.length())); 
	   		int[] ado = new int[2];
	   		ado[0]=(k+1);
	   		ado[1]=(cluster.getInput(i, j)+1);
	   		dat.add(ado);
		    input = br.readLine();
		}
		br.close();
		
		FileWriter fw = new FileWriter(Pfad+"res1.txt");
        BufferedWriter bw = new BufferedWriter(fw);
		for(int i=0;i<dat.size();i++){
			bw.write(dat.get(i)[0]+"");
	        bw.newLine();
		}
		bw.close();
		
		FileWriter fw2 = new FileWriter(Pfad+"res2.txt");
        BufferedWriter bw2 = new BufferedWriter(fw2);
		for(int i=0;i<dat.size();i++){
			bw2.write(dat.get(i)[1]+"");
	        bw2.newLine();
		}
		bw2.close();
	
	}

	public static void matlabami(Board data, Board ideal, Board cluster, String Pfad) throws IOException {
		FileWriter fw = new FileWriter(Pfad+"zahl.txt");
        BufferedWriter bw = new BufferedWriter(fw);
        int counter=0;
	    for(int i=0;i<ideal.size()[0];i++){
	    	for(int j=0;j<ideal.size()[1];j++){
	    		 
	    	 for(int k=0;k<data.getInput(i, j);k++){
	    		  counter++;
		    		bw.write(counter+","+(ideal.getInput(i, j)+1)+","+(cluster.getInput(i, j)+1));
		    		//System.out.println(counter+": "+(ideal.getInput(i, j)+1)+","+(cluster.getInput(i, j)+1));
		    		bw.flush();
		            bw.newLine();
	    	}
	    	}
	    }

	}	

}