package descriptors;

import java.awt.image.BufferedImage;

import preprocessing.Util;

import segmentation.Labels;
import segmentation.Regions;

public class Fourier {
	
	private final int MAX_FOUR_PILE = 50000;
	
	int size;
	
	int fourier_p_pile = 0;
	
	int px[] = { 0, 1,  1, 1, 0, -1, -1, -1};
	int py[] = {-1, -1, 0, 1, 1, 1,  0,  -1};
	
	int[] vectX;
    double[] fourX;
    int[] vectY;
    double[] fourY;
    
    int[] fourier_pileX = new int[MAX_FOUR_PILE];
    int[] fourier_pileY = new int[MAX_FOUR_PILE];

    public double getX (int pos) {
    	return fourX[pos];
    }
    
    public double getY (int pos) {
    	return fourY[pos];
    }
	
	public void fourier_fibd_contour(Labels img, Regions[] regions, int studied_region) {

		fourier_p_pile = 0;

		int x,y, x_test, y_test;
		int startX = 0, startY = 0;
		int old, curr, p;
		
		Regions reg = regions[studied_region];
		
		int x_min = reg.getXmin ();
		int x_max = reg.getXmax ();
		int y_min = reg.getYmin ();
		int y_max = reg.getYmax ();
		
		/*System.out.println("region : " + studied_region);
		System.out.println("x_min : " + x_min + " x_max : " + x_max);
		System.out.println("y_min : " + y_min + " y_max : " + y_max);*/
		
		int width = img.getWidth();
		int height = img.getHeight();

		for(y = y_min; y <= y_max; y++)
			for(x = x_min; x <= x_max;x++)
				if (img.getValue(x + y * width) == studied_region) {
					startX = x;
					startY = y;
					y = height;
					break;
				}
		x=startX;
		y=startY;
		//System.out.println("startX : " + startX + " startY : " + startY);
		old=0;
		do {
	
			fourier_pileX[fourier_p_pile] = x;
			fourier_pileY[fourier_p_pile] = y;
			fourier_p_pile++;
			//System.out.println("size : " + fourier_p_pile);
			for(curr=0, p=(old+1)%8;curr<8;curr++, p++) {
				p=p%8;
				x_test=x+px[p];
				y_test=y+py[p];
				if (x_test<0) continue;
				if (y_test<0) continue;
				if (x_test >= width) continue;
				if (y_test >= height) continue;
				if (img.getValue(x_test+y_test*width) == studied_region) {
					old=p+4;
					x=x_test;
					y=y_test;
					break;
				}
			}
		} while(x!=startX || y!=startY);
		
		/*for (int j = 0; j < fourier_p_pile; j++) {
			System.out.println("ind : " + j + " pile x : " + fourier_pileX[j] + ", pile y : " + fourier_pileY[j]);
		}*/
	}
	
	public void fourier_fibd_contour(BufferedImage image) {

		fourier_p_pile = 0;

		int x,y, x_test, y_test;
		int startX = 0, startY = 0;
		int old, curr, p;
		
		int[] array = Util.getImageArray (image);
		
		int width = image.getWidth();
		int height = image.getHeight();

		for(y = 0; y < height; y++)
			for(x = 0; x < width;x++)
				if (array[x + y * width] == 255) {
					startX = x;
					startY = y;
					y = height;
					break;
				}
		x=startX;
		y=startY;
		//System.out.println("startX : " + startX + " startY : " + startY);
		old=0;
		do {
	
			fourier_pileX[fourier_p_pile] = x;
			fourier_pileY[fourier_p_pile] = y;
			fourier_p_pile++;
			//System.out.println("size : " + fourier_p_pile);
			for(curr=0, p=(old+1)%8;curr<8;curr++, p++) {
				p=p%8;
				x_test=x+px[p];
				y_test=y+py[p];
				if (x_test<0) continue;
				if (y_test<0) continue;
				if (x_test >= width) continue;
				if (y_test >= height) continue;
				if (array[x_test+y_test*width] == 255) {
					old=p+4;
					x=x_test;
					y=y_test;
					break;
				}
			}
		} while(x!=startX || y!=startY);
		
		/*for (int j = 0; j < fourier_p_pile; j++) {
			System.out.println("ind : " + j + " pile x : " + fourier_pileX[j] + ", pile y : " + fourier_pileY[j]);
		}*/
	}

	public void Discretize (int size)
	{
	        int i;
	        
	    	this.size = size;
			
			vectX = new int[size];
			fourX = new double[size];
			
			vectY = new int[size];
			fourY = new double[size];
	        
	        double pas=((double)(fourier_p_pile)/(double)(this.size));
	        //System.out.println("Pas : " + pas + " fourier_p_pile : " + fourier_p_pile + " size : " + size);
	        for(i = 0; i < size;i++)
	        {
	             vectX[i] = fourier_pileX[(int)(Math.round(i*pas))];
	             vectY[i] = fourier_pileY[(int)(Math.round(i*pas))];
	        }
	}
	
	/*public int Compute_TF_Image ()
	{
	    int i,k;
	    int u;
	    int centre = size/2;
	    for(u = -size/2+1,i=0;i<size;i++,u++) {
	        double d1=0,d2=0;
	        for(k=0;k<size;k++) {
	                d1+=vectX[k]*Math.cos(-2*Math.PI*u*k/size);
	                d2+=vectX[k]*Math.sin(-2*Math.PI*u*k/size);
	                //System.out.println(d1);
	                //System.out.println(d2);
	                //System.out.println(i + " = " + fourX[i] + " vectX : " + vectX[k] + " conta : " + Math.cos(-2*Math.PI*u*k/size));
	        }
	        d1/=size;
	        d2/=size;
	        fourX[i]=Math.sqrt(d1*d1+d2*d2);
	        //System.out.println(i + " = " + fourX[i] + " vectX : " + vectX[k] + " conta : " + Math.cos(-2*Math.PI*u*k/size));
	    }
	    for(u=-size/2+1,i=0;i<size;i++,u++) {
	        double d1=0,d2=0;
	        if (u==0) centre=i;
	        for(k=0;k<size;k++) {
	                d1+=vectY[k]*Math.cos(-2*Math.PI*u*k/size);
	                d2+=vectY[k]*Math.sin(-2*Math.PI*u*k/size);
	        }
	        d1/=size;
	        d2/=size;
	        fourY[i]=Math.sqrt(d1*d1+d2*d2);
	    }
	    for (i=0;i<size;i++) {
	    	//X
		    if(fourX[centre+1] >= 1e-6)
		    	fourX[i]/=fourX[centre+1];
	        if(Double.isNaN(fourX[i]))
	        {
	        	System.err.println("Warning : centerX "+(i+1)+" is 0");
	        	fourX[i] = 0;
	        }
	        //Y
		    if(fourY[centre+1] >= 1e-6)
		    	fourY[i]/=fourY[centre+1];
	        if(Double.isNaN(fourY[i]))
	        {
	        	System.err.println("Warning : centerY "+(i+1)+" is 0");
	        	fourY[i] = 0;
	        }
	        //System.out.println(fourX[i]);
	    }

	    return centre;
	} */
	
	public int matrix_size (int fourier_size) {
		int size = 0;
		for(int u = -fourier_size/2 + 1, i=0; i < fourier_size; i++,u++) {
			for(int k=0;k<fourier_size;k++) {
				size++;
			}
		}
		return size;
	}
	
	
	public void cos_sin_matrices (double[] sin, double[] cos, int fourier_size) {
		int indice = 0;
		for(int u = -fourier_size/2 + 1, i=0; i < fourier_size; i++,u++) {
			for(int k=0;k<fourier_size;k++) {
				double angle = -2*Math.PI*u*k/fourier_size;
				cos[indice] = Math.cos(angle);
				sin[indice] = Math.sin(angle);
				indice++;
			}
		}
	}
	
	
	public int Compute_TF_Image () 
	{

	    int centre = size/2;
	    
	    for(int u = -size/2 + 1, i=0; i < size; i++,u++) {
	    	double d1 = 0, d2 = 0, d3 = 0, d4 = 0;
	    	for(int k=0;k<size;k++) {
	    		if (u==0) centre=i;
	    		double angle = -2*Math.PI*u*k/size;
	    		double cos = Math.cos(angle);
	    		double sin = Math.sin(angle);
	    		d1+=vectX[k]*cos; d2+=vectX[k]*sin;
	    		d3+=vectY[k]*cos; d4+=vectY[k]*sin;
	    	}
	    	d1/=size; d2/=size; d3/=size; d4/=size;
	    	fourX[i]=Math.sqrt(d1*d1+d2*d2);
	    	fourY[i]=Math.sqrt(d3*d3+d4*d4);
	    }
	    

	    for (int i = 0; i < size; i++) {

		    if(fourX[centre+1] >= 1e-6)
		    	fourX[i] /= fourX[centre+1];
	        if(Double.isNaN(fourX[i])) {
	        	System.err.println("Warning : centerX "+(i+1)+" is 0");
	        	fourX[i] = 0;
	        }

		    if(fourY[centre+1] >= 1e-6)
		    	fourY[i] /= fourY[centre+1];
	        if(Double.isNaN(fourY[i])) {
	        	System.err.println("Warning : centerY "+(i+1)+" is 0");
	        	fourY[i] = 0;
	        }
	    }

	    return centre;
	} 
	
	public int Compute_TF_Image (double[] sin, double[] cos) 
	{

	    int centre = size/2;
	    
	    int indice = 0;
	    
	    for(int u = -size/2 + 1, i=0; i < size; i++,u++) {
	    	double d1 = 0, d2 = 0, d3 = 0, d4 = 0;
	    	for(int k=0;k<size;k++) {
	    		if (u==0) centre=i;
	    		d1+=vectX[k]*cos[indice]; d2+=vectX[k]*sin[indice];
	    		d3+=vectY[k]*cos[indice]; d4+=vectY[k]*sin[indice];
	    		indice++;
	    	}
	    	d1/=size; d2/=size; d3/=size; d4/=size;
	    	fourX[i]=Math.sqrt(d1*d1+d2*d2);
	    	fourY[i]=Math.sqrt(d3*d3+d4*d4);
	    }
	    

	    for (int i = 0; i < size; i++) {

		    if(fourX[centre+1] >= 1e-6)
		    	fourX[i] /= fourX[centre+1];
	        if(Double.isNaN(fourX[i])) {
	        	System.err.println("Warning : centerX "+(i+1)+" is 0");
	        	fourX[i] = 0;
	        }

		    if(fourY[centre+1] >= 1e-6)
		    	fourY[i] /= fourY[centre+1];
	        if(Double.isNaN(fourY[i])) {
	        	System.err.println("Warning : centerY "+(i+1)+" is 0");
	        	fourY[i] = 0;
	        }
	    }

	    return centre;
	} 
	
	
	

}
