package representation;

import java.awt.Color;
import java.awt.event.ActionListener;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;

import GUI.FileChooser;
import GUI.internalFrame;
import GUI.mainWindow;

import ij.ImagePlus;
import ij.gui.NewImage;
import ij.process.ImageProcessor;
import java.util.List;

import com.sun.org.apache.bcel.internal.generic.Select;

import GUI.Result;

import histogram.VerticalHistogram;

public class SlantVertiPro {
	
	ImagePlus imp, imp2;
	ImageProcessor ip, nip;	
	int numberResult;
	private VerticalHistogram vertHist;
	final int numberSlant = 21;//41;
	ImageProcessor[][] imagePro;
	ImagePlus[][] imagePlus;
	ImagePlus impSlant;
	ImageProcessor nipSlant;
	boolean draw;
	boolean setSelected;


	class horRunLength{
		int r; //the row of horizontal run
		int c1, c2; //first and last columns of the run
		int len; //lenght of the run
		int traced; //tracing indicator
		ArrayList above, below, right;
	}	
	
	class slopes{
		int x1,x2,y1,y2;
		double angle;
		double multi;
		double prepona;
	}
	
	private boolean areRunsNeighbours(horRunLength above, horRunLength below){
		if (above.c2 < below.c1) return false;
		if (above.c1 > below.c2) return false;
		return true;
	}
	
	class contours{
		ArrayList con;
	}
	
	public SlantVertiPro(ImagePlus imp, ImageProcessor ip, int numberResult, boolean draw, boolean setSelected) {
		this.imp = imp;
		this.ip = ip;
		this.numberResult = numberResult;
		this.draw = draw;
		this.setSelected = setSelected;
		
		int color = ((Color.red.getRed() & 0xff) << 16) + ((0 & 0xff) << 8) + (0 & 0xff); //red color
		
		ArrayList redJ = new ArrayList();
			redJ.add(0);
			for (int j = 0; j < ip.getHeight(); j++) {			
				if (ip.getPixel(0, j) == color) {
					redJ.add(j);
				}
			}
			
		imagePro = new ImageProcessor[redJ.size() - 1][numberSlant];
		imagePlus = new ImagePlus[redJ.size() - 1][numberSlant];
		int[] maxI = new int[redJ.size() - 1];
	//	double[] slant = {-1.0, -0.95, -0.9, -0.85, -0.8, -0.75, -0.7, -0.65, -0.6, -0.55, -0.5, -0.45, -0.4, -0.35, -0.3, -0.25, -0.2, -0.15, -0.1, -0.05,  0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0};
	//TOTO JE TO SPRAVNE	
		double[] slant = {-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
		//double[] slant = {-1.0, -0.8, -0.6,  -0.4,  -0.2,  0.0,  0.2,  0.4,  0.6,  0.8,  1.0};
		//double[] slant = {-0.9,  -0.6,  -0.3,  0.0,  0.3,  0.6,  0.9};

		
		for (int k = 0; k < redJ.size()-1; k++) {
		//for (int k = 0; k < 1; k++) {
		
			int[][] hist = new int[numberSlant][];
			ArrayList list = new ArrayList();
			
			for (int i = 0; i < slant.length; i++) {
				list = setArrays( (Integer)(redJ.get(k))+1, (Integer)(redJ.get(k+1))-1 );
				hist[i] = run(slant[i], k,  i, (Integer)(redJ.get(k))+1, (Integer)(redJ.get(k+1))-1, list);
			}
			
			for (int i = 0; i < hist.length; i++) {
				Arrays.sort(hist[i]);
			}
			double[] histAver = new double[numberSlant];
			for (int i = 0; i < histAver.length; i++) {
				int count = 0;
				for (int j = hist[i].length - 10; j < hist[i].length; j++) {
					histAver[i] = histAver[i] + (double)(hist[i][j]);
					count++;
				}
				histAver[i] = histAver[i] /  count;
			}
			
			double max = 0;
			for (int i = 0; i < histAver.length; i++) {
				if (max < histAver[i]) {
					max = histAver[i];
					maxI[k] = i;
				}
			}
			
		//	System.out.println("slant "+slant[])
			
/*			mainWindow.intFrame[FileChooser.number] = new internalFrame("Smoothing", imagePlus[k][maxI[k]], FileChooser.number, numberResult, 1, true);
			try {
				mainWindow.intFrame[FileChooser.number].setSelected(true);
			} catch(Exception e){
				System.out.println("Chyba");
			}	
			++FileChooser.number;*/
		}
		double[] slantResult = new double[maxI.length];
		for (int i = 0; i < slantResult.length; i++) {
			slantResult[i] = slant[maxI[i]];
		}
		
		Result.setSlant(slantResult, numberResult);
		
		impSlant = NewImage.createRGBImage ("Horizontal Run Length", ip.getWidth(), ip.getHeight(), 1, NewImage.FILL_WHITE);
		nipSlant = impSlant.getProcessor();
		
		for (int i = 0; i < maxI.length; i++) {
			for (int j = 0; j < imagePro[i][maxI[i]].getWidth(); j++) {
				for (int k = 0; k < imagePro[i][maxI[i]].getHeight(); k++) {
					if (imagePro[i][maxI[i]].getPixelValue(j, k) != 255)
						nipSlant.putPixelValue(j, k + (Integer)(redJ.get(i)), imagePro[i][maxI[i]].getPixelValue(j, k));
				}
			}
		}
		
		nipSlant.setColor(color);
		for (int i = 1; i < redJ.size(); i++) {
			nipSlant.drawLine(0, (Integer)(redJ.get(i)), ip.getWidth(), (Integer)(redJ.get(i)));
		}
		
		if (draw) {
			mainWindow.intFrameArrayList.add(new internalFrame("Slant correction", impSlant, FileChooser.number, numberResult, 1, true));
			try {
				//mainWindow.intFrame[FileChooser.number].setSelected(true);
				((internalFrame)(mainWindow.intFrameArrayList.get(FileChooser.number))).setSelected(setSelected);
			} catch(Exception e){
				System.out.println("Chyba");
			}	
			++FileChooser.number;
		}
		
	}
	
	
	public ImagePlus getImg(){
		return impSlant;
	}
	
	public ImageProcessor getIp(){
		return nipSlant;
	}	
	
	public int[] setHistogram(ImageProcessor ip){

		int[] hist = new int[ip.getWidth()];
		Arrays.fill(hist, 0);
		for (int i = 0; i < ip.getWidth(); i++) {
			for (int j = 0; j < ip.getHeight(); j++) {
				if (ip.getPixelValue(i, j) == 0)
					hist[i] = hist[i] + 1;
			}
		}
		return hist;
	}
	
	private ArrayList setArrays(int start, int end){
		//	System.out.println("start "+start);
		//	System.out.println("end "+end);
			ArrayList list2 = new ArrayList();
			
			int i = 0;
			int j = start;
			while (j<end) {
				if (j > 1000)
					System.out.println("ZASEKAVAM SA??slant1");
				i = 0;
				while (i<ip.getWidth()){
					if (i > 1000)
						System.out.println("ZASEKAVAM SA??slant2");
					if (ip.getPixelValue(i, j) == 0) {
						if  ((i == 0) || ( (i != 0) && (ip.getPixelValue(i-1, j) == 255) )) {
							horRunLength hrl = new horRunLength();
							hrl.r = j;
							hrl.c1 = i;
							while (ip.getPixelValue(i, j) == 0) {
								if (i > 1000)
									System.out.println("ZASEKAVAM SA??slant3");
								i++;
							}
							hrl.c2 = i-1;
							hrl.len = hrl.c2 - hrl.c1 + 1;
							hrl.above = new ArrayList();
							hrl.below = new ArrayList();
							hrl.right = new ArrayList();
							for (int k = 0; k < list2.size(); k++) {
								horRunLength hrl2 = ((horRunLength)(list2.get(k)));
								if ( ((hrl2.r + 1) == hrl.r) && (areRunsNeighbours(hrl2, hrl)) ){
									hrl.above.add(k);
									hrl2.below.add(list2.size());
								}
								if ((k == list2.size() -1) && (hrl2.r == hrl.r))
									hrl2.right.add(list2.size());
							}
							list2.add(hrl);
						}
							
					}
					i++;
				}
				j++;
			}
			
			return list2;
	}
	
	public int[] run(double averageSlope, int line, int image, int start, int end, ArrayList list2){
		
/*		ImagePlus imp2 = NewImage.createRGBImage ("Horizontal Run Length", ip.getWidth(), ip.getHeight(), 1, NewImage.FILL_WHITE);
		ImageProcessor nip = imp2.getProcessor();
		
		Random random = new Random();
		Color randomColor = Color.getHSBColor( random.nextFloat(), 1.0F, 1.0F );

		for (i = 0; i < list.size(); i++) {
			horRunLength hrl = ((horRunLength)(list.get(i)));
			randomColor = Color.getHSBColor( random.nextFloat(), 1.0F, 1.0F );

			int color = ((randomColor.getRed() & 0xff) << 16) + ((randomColor.getGreen() & 0xff) << 8) + (randomColor.getBlue() & 0xff);

			for (int k = 0; k < hrl.len; k++) {
				nip.putPixel(hrl.c1 + k, hrl.r, color);
			}
		}*/
////////////////////////////	
		horRunLength hrl = new horRunLength();
		
		//SHIFTING
		int shift = 0;
		
		ImagePlus imp4 = NewImage.createByteImage ("Horizontal Run Length", ip.getWidth(), end-start, 1, NewImage.FILL_WHITE);
		ImageProcessor nip3 = imp4.getProcessor();
		
		int maxShift = 0;
		for (int i = 0; i < list2.size(); i++) {
			hrl = ((horRunLength)(list2.get(i)));
			shift = (int)(hrl.r * Math.tan(averageSlope));
			if (Math.abs(shift) > Math.abs(maxShift))
				maxShift = shift;
			//System.out.println("shift "+shift);
			hrl.c1 = hrl.c1 + shift;
			hrl.c2 = hrl.c2 + shift;
		}

		//System.out.println("maxshift "+maxShift);
		
/*		for (i = 0; i < list.size(); i++) {
			horRunLength hrl = ((horRunLength)(list.get(i)));
			hrl.c1 = hrl.c1 - maxShift;
			hrl.c2 = hrl.c2 - maxShift;
		}*/
		
		for (int i = 0; i < list2.size(); i++) {
			hrl = ((horRunLength)(list2.get(i)));
			for (int k = 0; k < hrl.len; k++) {
				nip3.putPixelValue(hrl.c1 + k - maxShift, hrl.r-start, 0);
			}
		}
	
		
/*		mainWindow.intFrame[FileChooser.number] = new internalFrame("Slant-angle Correction", imp4, FileChooser.number, numberResult, 1, true);
		try {
			mainWindow.intFrame[FileChooser.number].setSelected(true);
		} catch(Exception e){
			System.out.println("Chyba");
		}	
		++FileChooser.number;*/
		
		ImagePlus imp5 = NewImage.createByteImage ("Horizontal Run Length", ip.getWidth(), end - start, 1, NewImage.FILL_WHITE);
		ImageProcessor nip4 = imp5.getProcessor();
		
		for (int i = 0; i < list2.size(); i++) {
			hrl = ((horRunLength)(list2.get(i)));
			int originc1 = hrl.c1;
			if ((!hrl.above.isEmpty()) && (!hrl.below.isEmpty())) {
				hrl.c1 = ( ((horRunLength)(list2.get((Integer)(hrl.above.get(0))))).c1 +
						+ ((horRunLength)(list2.get((Integer)(hrl.below.get(0))))).c1 ) /2;
			} else if ((hrl.above.isEmpty()) && (!hrl.below.isEmpty())) {
				hrl.c1 = ((horRunLength)(list2.get((Integer)(hrl.below.get(0))))).c1;
			}  else if ((!hrl.above.isEmpty()) && (hrl.below.isEmpty())) {
				hrl.c1 = ((horRunLength)(list2.get((Integer)(hrl.above.get(0))))).c1;
			}

			if (Math.abs(originc1 - hrl.c1) >= 2) {
				int min = originc1;
				int max = originc1;
				if ((!hrl.above.isEmpty()) && (!hrl.below.isEmpty())) {
					min = Math.min(((horRunLength)(list2.get((Integer)(hrl.above.get(0))))).c1,  ((horRunLength)(list2.get((Integer)(hrl.below.get(0))))).c1);
					max = Math.max(((horRunLength)(list2.get((Integer)(hrl.above.get(0))))).c1,  ((horRunLength)(list2.get((Integer)(hrl.below.get(0))))).c1);
				} else if ((hrl.above.isEmpty()) && (!hrl.below.isEmpty())) {
					min = ((horRunLength)(list2.get((Integer)(hrl.below.get(0))))).c1;
					max = ((horRunLength)(list2.get((Integer)(hrl.below.get(0))))).c1;
				}  else if ((!hrl.above.isEmpty()) && (hrl.below.isEmpty())) {
					min = ((horRunLength)(list2.get((Integer)(hrl.above.get(0))))).c1;
					max = ((horRunLength)(list2.get((Integer)(hrl.above.get(0))))).c1;
				}
				int minimum = min;
				for (int k = min; k <= max; k++) {
					if (Math.abs(originc1 - k) < minimum)
						minimum = k;
				}
				if (minimum >= 2)
					hrl.c1 = originc1;
				else 
					hrl.c1 = minimum;
			}
			
			
			int originc2 = hrl.c2;
	//		System.out.println("originc2 "+originc2);
			if ((!hrl.above.isEmpty()) && (!hrl.below.isEmpty())) {
				hrl.c2 = ( ((horRunLength)(list2.get((Integer)(hrl.above.get(hrl.above.size() - 1))))).c2 +
						+ ((horRunLength)(list2.get((Integer)(hrl.below.get(hrl.below.size() - 1))))).c2 ) /2;
			} else if ((hrl.above.isEmpty()) && (!hrl.below.isEmpty())) {
				hrl.c2 = ((horRunLength)(list2.get((Integer)(hrl.below.get(hrl.below.size() - 1))))).c2;
			}  else if ((!hrl.above.isEmpty()) && (hrl.below.isEmpty())) {
				hrl.c2 = ((horRunLength)(list2.get((Integer)(hrl.above.get(hrl.above.size() - 1))))).c2;
			}

			if (Math.abs(originc2 - hrl.c2) >= 2) {
				int min = originc2;
				int max = originc2;
				if ((!hrl.above.isEmpty()) && (!hrl.below.isEmpty())) {
					min = Math.min(((horRunLength)(list2.get((Integer)(hrl.above.get(hrl.above.size() - 1))))).c2,  ((horRunLength)(list2.get((Integer)(hrl.below.get(hrl.below.size() - 1))))).c2);
					max = Math.max(((horRunLength)(list2.get((Integer)(hrl.above.get(hrl.above.size() - 1))))).c2,  ((horRunLength)(list2.get((Integer)(hrl.below.get(hrl.below.size() - 1))))).c2);
				} else if ((hrl.above.isEmpty()) && (!hrl.below.isEmpty())) {
					min = ((horRunLength)(list2.get((Integer)(hrl.below.get(hrl.below.size() - 1))))).c2;
					max = ((horRunLength)(list2.get((Integer)(hrl.below.get(hrl.below.size() - 1))))).c2;
				}  else if ((!hrl.above.isEmpty()) && (hrl.below.isEmpty())) {
					min = ((horRunLength)(list2.get((Integer)(hrl.above.get(hrl.above.size() - 1))))).c2;
					max = ((horRunLength)(list2.get((Integer)(hrl.above.get(hrl.above.size() - 1))))).c2;
				}
				int minimum = min;
				for (int k = min; k <= max; k++) {
					if (Math.abs(originc2 - k) < minimum)
						minimum = k;
				}
				if (minimum >= 2)
					hrl.c2 = originc2;
				else 
					hrl.c2 = minimum;
			}
			hrl.len = hrl.c2 - hrl.c1 +1;
			
			for (int k = 0; k < hrl.len; k++) {
				nip4.putPixelValue(hrl.c1+k, hrl.r - start, 0);
			}
		}
		
		
		imagePro[line][image] = nip3;
		imagePlus[line][image] = imp4;
		
		////////////
		//vykreslovanie VPP
		//vertHist = new VerticalHistogram(imp4, nip3, FileChooser.number, numberResult); 	
		///////////
		
		int[] hist = setHistogram(nip3);
		
		return hist;
//////////////////////////////		
	}
	
	protected void finalize() throws Throwable {
	    try {
	        //close();        // close open files
	    } finally {
	        super.finalize();
	        System.out.println("slant has been finalized.");
	    }
	}	
}

