package descriptors;

import java.awt.image.BufferedImage;
import java.util.Arrays;

import preprocessing.Util;
import segmentation.Labels;
import segmentation.Regions;

public class Polar {
	
	final double M_PI = 3.14159265358979323846;
	
	int barycenter_x;
	
	int barycenter_y;
	
	public void computeGravityCenter (BufferedImage image)
	{
		int i=0;
		int width = image.getWidth();
		int height = image.getHeight();
		int[] array = Util.getImageArray (image);

//		System.out.println("w : "+width+" h : "+height);
//		System.out.println(Arrays.toString(array));
		
		int surface=0;
	    barycenter_x=0;
	    barycenter_y=0;
	    for(int y=0;y<height;y++)
	        for(int x=0;x<width;x++)
	        {
	            if (array[i++]!=0) {
	            	barycenter_x+=x;
	            	barycenter_y+=y;
	                surface++;
	            }
	        }
	    barycenter_x/=surface;
	    barycenter_y/=surface;
	}
	
	public int matrix_size1 (int ANGLE, int RAYON) {
		
		int size = 0;
		double pas_angulaire=( M_PI*2.0 / ANGLE ); 
		for(int r=0;r<RAYON;r++) {
			for(double theta=0;theta<(2.0*M_PI-0.00001);theta+=pas_angulaire) {
				size++;
			}
		}
		return size;
	}

	public void cos_sin_matrices1 (int ANGLE, int RAYON, double[] sin, double[] cos) {
		int i = 0;
		double pas_angulaire=( M_PI*2.0 / ANGLE ); 
		for(int r=0;r<RAYON;r++) {
			for(double theta=0;theta<(2.0*M_PI-0.00001);theta+=pas_angulaire) {
				cos[i] = Math.cos(theta);
				sin[i] = Math.sin(theta);
				i++;
			}
		}
	}
	
	
	public BufferedImage Compute_Polar_Image (Labels lab, Regions[] regions, int studied_region, int ANGLE, int RAYON)
	{
		int size_polar = 0;
		int bclX, bclY;
		int l;
		int d_max=0;
		double pas_angulaire;
		double pas_largeur;
		double r_pol;
		int r;
		double theta;
		Regions reg = regions[studied_region];

		int width = lab.getWidth();

		BufferedImage outimg = new BufferedImage(ANGLE, RAYON, BufferedImage.TYPE_INT_ARGB);

		int[] outarray = new int[ANGLE*RAYON];

		int x_min = reg.getXmin ();
		int x_max = reg.getXmax ();
		int y_min = reg.getYmin ();
		int y_max = reg.getYmax ();

		int xg = reg.getXg();
		int yg = reg.getYg();

		//if (studied_region == 100)
		//   System.out.println("Rayon : " +  RAYON + " Angle : " + ANGLE + " x_min : " + x_min + " x_max : " + x_max + " y_min : " + y_min+ " y_max : " + y_max);
		
		for(bclY = y_min; bclY <= y_max; bclY++)
			for(bclX = x_min; bclX <= x_max; bclX++) {
				if (lab.getValue(bclX + bclY*width) == studied_region) {
					int distance=(int)(Math.ceil(Math.sqrt( (bclX-xg)*(bclX-xg)+(bclY-yg)*(bclY-yg) ) ) ) ;
					d_max=(distance>d_max)?distance:d_max;
				}
			}
		//if (studied_region == 100)
		//	System.out.println("D_max : " +  d_max);
		
		pas_angulaire=( M_PI*2.0 / ANGLE ); //1.0/(double)RAYON;
		//if (studied_region == 100)
		//   System.out.println("pas_ang : " + pas_angulaire);
		pas_largeur=(double)d_max/(double)RAYON;
		//if (studied_region == 100)
		//   System.out.println("pas_largeur : " + pas_largeur + " dmax : " + d_max);
		r_pol=0;l=0;
		for(r=0;r<RAYON;r++) {
			for(theta=0;theta<(2.0*M_PI-0.00001);theta+=pas_angulaire) {
				double r1 = r_pol*Math.cos(theta);
				if ((int)Math.round(r1 - 0.00001) != (int)Math.round(r1 + 0.00001)) {
					r1 = r1 - 0.00001;
				}
				double r2 = r_pol*Math.sin(theta);
				if ((int)Math.round(r2 - 0.00001) != (int)Math.round(r2 + 0.00001)) {
					r2 = r2 - 0.00001;
				}
				size_polar++;
				
				int X=xg+(int)Math.round(r1);
				int Y=yg+(int)Math.round(r2);
				/*if (studied_region == 100) {
				    System.out.println("theta : " + theta + " X : " + X + " Y : " + Y + " cos : " + Math.cos(theta) + " sen : " + Math.sin(theta));
				    System.out.println("rpol : " + r_pol + " pol*cos " + r_pol*Math.cos(theta) + " pol*sin " + r_pol*Math.sin(theta));
				    System.out.println("xg : " + xg + " yg : " + yg + " v0 : " + Math.round(r_pol*Math.cos(theta)) + " v1 : " + (int)Math.round(r_pol*Math.cos(theta)));
				    System.out.println("xg : " + xg + " yg : " + yg + " v0 : " + Math.round(r_pol*Math.cos(theta)) + " v1 : " + Math.round((float)(r_pol*Math.cos(theta))));
				    System.out.println("xg : " + xg + " yg : " + yg + " v2 : " + Math.round(r_pol*Math.sin(theta)) + " v3 : " + (int)Math.round(r_pol*Math.sin(theta)));
				}*/
				if (X > x_max || X < x_min) {
					/*if (studied_region == 100) {
						System.out.println("pixel : " + l + " vale : 0");
					}*/
					outarray[l++]=0;
					continue;	
				}
				if (Y > y_max || Y < y_min) {
					/*if (studied_region == 100) {
						System.out.println("pixel : " + l + " vale : 0");
					}*/
					outarray[l++]=0;
					continue;
				}
				if (lab.getValue(X + Y * width) == studied_region) {
					/*if (studied_region == 100) {
						System.out.println("pixel : " + l + " vale : 255 " + " labval : " + lab.getValue(X + Y * width) + " X : " + X + " Y : " + Y + " w : " + width);
					}*/
					outarray[l++]=255;
				} else {
					/*if (studied_region == 100) {
						System.out.println("pixel : " + l + " vale : 0 " + " labval : " + lab.getValue(X + Y * width) + " X : " + X + " Y : " + Y + " w : " + width);
					}*/
					outarray[l++]=0;
				}
			}
			r_pol+=pas_largeur;
		}
		/*if (studied_region == 100)
		   for(r = 0;r < (ANGLE *RAYON);r++) {
			   System.out.println("pos : " + r + " pixel : " + outarray[r] + " R_pol : " + r_pol);
		   } */
		//System.err.printf("O tamanho do polar size eh %d\n", size_polar);
		int startX = 0; int startY = 0;
		Util.greyToColorImage (outarray, ANGLE, RAYON);
		outimg.setRGB(startX, startY, ANGLE, RAYON, outarray, 0, ANGLE);
		return outimg;
	}
	
	
	
	
	public BufferedImage Compute_Polar_Image (BufferedImage image, int ANGLE, int RAYON)
	{
		int bclX, bclY;
		int l;
		int d_max=0;
		double pas_angulaire;
		double pas_largeur;
		double r_pol;
		int r;
		double theta;

		int width = image.getWidth();
		int height = image.getHeight();

		BufferedImage outimg = new BufferedImage(ANGLE, RAYON, BufferedImage.TYPE_INT_RGB);

		int[] outarray = new int[ANGLE*RAYON];
		
		int[] array = Util.getImageArray (image);
		//if (studied_region == 100)
		//   System.out.println("Rayon : " +  RAYON + " Angle : " + ANGLE + " x_min : " + x_min + " x_max : " + x_max + " y_min : " + y_min+ " y_max : " + y_max);
		
		for(bclY = 0; bclY < height; bclY++)
			for(bclX = 0; bclX < width; bclX++) {
				if (array[bclX+bclY*width]!=0) {
					int distance=(int)(Math.ceil(Math.sqrt( (bclX-barycenter_x)*(bclX-barycenter_x)+(bclY-barycenter_y)*(bclY-barycenter_y) ) ) ) ;
					d_max=(distance>d_max)?distance:d_max;
				}
			}
		//if (studied_region == 100)
		//	System.out.println("D_max : " +  d_max);
		
		pas_angulaire=( M_PI*2.0 / ANGLE ); //1.0/(double)RAYON;
		//if (studied_region == 100)
		//   System.out.println("pas_ang : " + pas_angulaire);
		pas_largeur=(double)d_max/(double)RAYON;
		//if (studied_region == 100)
		//   System.out.println("pas_largeur : " + pas_largeur + " dmax : " + d_max);
		r_pol=0;l=0;
		for(r=0;r<RAYON;r++) {
			for(theta=0;theta<(2.0*M_PI-0.00001);theta+=pas_angulaire) {
				double r1 = r_pol*Math.cos(theta);
				if ((int)Math.round(r1 - 0.00001) != (int)Math.round(r1 + 0.00001)) {
					r1 = r1 - 0.00001;
				}
				double r2 = r_pol*Math.sin(theta);
				if ((int)Math.round(r2 - 0.00001) != (int)Math.round(r2 + 0.00001)) {
					r2 = r2 - 0.00001;
				}
				
				int X=barycenter_x+(int)Math.round(r1);
				int Y=barycenter_y+(int)Math.round(r2);
				/*if (studied_region == 100) {
				    System.out.println("theta : " + theta + " X : " + X + " Y : " + Y + " cos : " + Math.cos(theta) + " sen : " + Math.sin(theta));
				    System.out.println("rpol : " + r_pol + " pol*cos " + r_pol*Math.cos(theta) + " pol*sin " + r_pol*Math.sin(theta));
				    System.out.println("xg : " + xg + " yg : " + yg + " v0 : " + Math.round(r_pol*Math.cos(theta)) + " v1 : " + (int)Math.round(r_pol*Math.cos(theta)));
				    System.out.println("xg : " + xg + " yg : " + yg + " v0 : " + Math.round(r_pol*Math.cos(theta)) + " v1 : " + Math.round((float)(r_pol*Math.cos(theta))));
				    System.out.println("xg : " + xg + " yg : " + yg + " v2 : " + Math.round(r_pol*Math.sin(theta)) + " v3 : " + (int)Math.round(r_pol*Math.sin(theta)));
				}*/
				if (X >= width || X<0) {
					/*if (studied_region == 100) {
						System.out.println("pixel : " + l + " vale : 0");
					}*/
					outarray[l++]=0;
					continue;	
				}
				if (Y >= height || Y < 0) {
					/*if (studied_region == 100) {
						System.out.println("pixel : " + l + " vale : 0");
					}*/
					outarray[l++]=0;
					continue;
				}
				if (array[X + Y * width] != 0	) {
					/*if (studied_region == 100) {
						System.out.println("pixel : " + l + " vale : 255 " + " labval : " + lab.getValue(X + Y * width) + " X : " + X + " Y : " + Y + " w : " + width);
					}*/
					outarray[l++]=255;
				} else {
					/*if (studied_region == 100) {
						System.out.println("pixel : " + l + " vale : 0 " + " labval : " + lab.getValue(X + Y * width) + " X : " + X + " Y : " + Y + " w : " + width);
					}*/
					outarray[l++]=0;
				}
			}
			r_pol+=pas_largeur;
		}
		/*if (studied_region == 100)
		   for(r = 0;r < (ANGLE *RAYON);r++) {
			   System.out.println("pos : " + r + " pixel : " + outarray[r] + " R_pol : " + r_pol);
		   } */
		
		int startX = 0; int startY = 0;
		Util.greyToColorImage (outarray, ANGLE, RAYON);
		outimg.setRGB(startX, startY, ANGLE, RAYON, outarray, 0, ANGLE);
		return outimg;
	}

	public int matrix_size2 (int ANGLE) {
		int size = 0;
		for(int u=-ANGLE/2+1,i=0;i<ANGLE;i++,u++) {
			for(int k=0;k<ANGLE;k++) {
				size++;
			}
		}
		return size;
	}
	
	public void cos_sin_matrices2 (int ANGLE, double[] sin, double[] cos) {
		int indice = 0;
		for(int u=-ANGLE/2+1,i=0;i<ANGLE;i++,u++) {
			for(int k=0;k<ANGLE;k++) {
				cos[indice]=Math.cos((-2*M_PI*u*k)/ANGLE);
				sin[indice]=Math.sin((-2*M_PI*u*k)/ANGLE);
				indice++;
			}
		}
	}

	public int[] Compute_TF_Image (int[] inarray, double[] sin2, double[] cos2, int ANGLE, int RAYON)
	{
		int width = ANGLE;
		int height = RAYON;

		int[] outarray = new int[width*height];

		int i,j,k;
		int offset, offsetY;
		int u;
		for(j = 0, offset = 0, offsetY = 0; j < RAYON; j++, offsetY += width) {
			int indice = 0;
			for(u=-ANGLE/2+1,i=0;i<ANGLE;i++,u++) {
				double d1 = 0.0, d2 = 0.0;
				for(k=0;k<ANGLE;k++) {
					d1+=inarray[offsetY+k]*cos2[indice];
					d2+=inarray[offsetY+k]*sin2[indice];
					indice++;
				}

				d1 /= (double)ANGLE;
				d2 /= (double)ANGLE; 
				
				double r1 = Math.sqrt(d1*d1+d2*d2);

				outarray[offset] = (int)(Math.round(r1));
				offset++;
			}
		}
		return outarray;
	}

	public int[] Compute_Polar_Image (Labels lab, Regions[] regions, double[] cos, double[] sin, int studied_region, int ANGLE, int RAYON)
	{
		int size_polar = 0;
		int bclX, bclY;
		int l;
		int d_max=0;
		double pas_angulaire;
		double pas_largeur;
		double r_pol;
		int r;
		double theta;
		Regions reg = regions[studied_region];
		int i = 0;

		int width = lab.getWidth();

		int[] outarray = new int[ANGLE*RAYON];

		int x_min = reg.getXmin ();
		int x_max = reg.getXmax ();
		int y_min = reg.getYmin ();
		int y_max = reg.getYmax ();

		int xg = reg.getXg();
		int yg = reg.getYg();

		for(bclY = y_min; bclY <= y_max; bclY++)
			for(bclX = x_min; bclX <= x_max; bclX++) {
				if (lab.getValue(bclX + bclY*width) == studied_region) {
					int distance=(int)(Math.ceil(Math.sqrt( (bclX-xg)*(bclX-xg)+(bclY-yg)*(bclY-yg) ) ) ) ;
					d_max=(distance>d_max)?distance:d_max;
				}
			}
		
		pas_angulaire=( M_PI*2.0 / ANGLE ); 

		pas_largeur=(double)d_max/(double)RAYON;

		r_pol=0;l=0;
		for(r=0;r<RAYON;r++) {
			for(theta=0;theta<(2.0*M_PI-0.00001);theta+=pas_angulaire) {
				
				double r1 = r_pol*cos[i];

				double r2 = r_pol*sin[i];

				size_polar++;
				i++;
				
				int X=xg+(int)Math.round(r1);
				int Y=yg+(int)Math.round(r2);

				if (X > x_max || X < x_min || Y > y_max || Y < y_min) {
					outarray[l++]=0;
					continue;	
				}

				if (lab.getValue(X + Y * width) == studied_region) {
					outarray[l++]=255;
				} else {
					outarray[l++]=0;
				}
			}
			r_pol+=pas_largeur;
		}

		return outarray;
	}
	
	
	public BufferedImage Compute_TF_Image (BufferedImage inimg, int ANGLE, int RAYON)
	{
		int width = ANGLE;
		int height = RAYON;

		int[] inarray = Util.getImageArray(inimg);
		
		BufferedImage outimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		
		int[] outarray = new int[width*height];

		//System.out.println("Rayon : " +  RAYON + " Angle : " + ANGLE);
		
		int i,j,k;
		int offset, offsetY;
		int u;
		for(j = 0, offset = 0, offsetY = 0; j < RAYON; j++, offsetY += width) {
			for(u=-ANGLE/2+1,i=0;i<ANGLE;i++,u++) {
				double d1 = 0.0, d2 = 0.0;
				for(k=0;k<ANGLE;k++) {
					d1+=inarray[offsetY+k]*Math.cos((-2*M_PI*u*k)/ANGLE);
					d2+=inarray[offsetY+k]*Math.sin((-2*M_PI*u*k)/ANGLE);
					//if (k == 0 || k == (ANGLE - 1))
					//  System.out.println(" d1 : " + d1 + " inarray : " + inarray[offsetY+k] + " offset : " + offsetY+k + " cos : " + Math.cos(-2*Math.PI*u*k/ANGLE));
				}
				//d1 = (d1/(double)(ANGLE));
				//d2 = (d2/(double)(ANGLE));
				d1 /= (double)ANGLE;
				d2 /= (double)ANGLE; //CUIDADO VERIFICAR ISSO;
				
				double r1 = Math.sqrt(d1*d1+d2*d2);
				if ((int)Math.round(r1 - 0.00001) != (int)Math.round(r1 + 0.00001)) {
					r1 = r1 - 0.00001;
				}
				//outarray[offset] = (int)(Math.round(Math.sqrt(d1*d1+d2*d2))); //NAO DAH O MESMO RESULTADO
				outarray[offset] = (int)(Math.round(r1));
				//outarray[offset] = (int)(Math.sqrt(Math.round(d1*d1+d2*d2)));
		
				//outarray[offset] = (int)(Math.round(Math.sqrt(d1*d1+d2*d2)));
				//System.out.println("j: " + j + " offset : " + offset + " outarray : " + outarray[offset] + " d1 : " + d1 + " d2 : " + d2);
				//System.out.println("round : " + Math.round(Math.sqrt(d1*d1+d2*d2)) + " sqrt : " + Math.sqrt(d1*d1+d2*d2));
				offset++;
			}
		}
		int startX = 0; int startY = 0;
		Util.greyToColorImage (outarray, width, height);
		outimg.setRGB(startX, startY, width, height, outarray, 0, width);
		return outimg;
	}
	
	

}
