package descriptors;

import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;

import preprocessing.Util;
import regrouping.PointList;

public class Shape {
	
	private int x_min;
	private int x_max;
	private int y_min_left;
	private int y_max_left;
	private int y_min_right;
	private int y_max_right;

   void left_bounds (BufferedImage image)
    {
    	int w = image.getWidth(null);

    	int h = image.getHeight(null);	

    	int[] array = Util.getImageArray(image);

    	int offset=0;
    	x_min = -1;

    	for(int i=0;i < w;offset=++i) {
    		for(int j=0;j< h;j++,offset+=w) {
    			if (array[offset]==255) {
    				if (x_min == -1) {
    					x_min = i;
    					y_max_left = y_min_left = j;

    				} else {
    					y_max_left = j;	
    				}
    			}
    		}
    		if (x_min !=-1) break;
    	}
    }

    void right_bounds(BufferedImage inimg)
    {
    	int width  = inimg.getWidth(null);

    	int height = inimg.getHeight(null);	

    	int[] inarray = Util.getImageArray(inimg);
    	int i;
    	int offset;
    	
    	x_max = -1;
   
    	for(offset=i=width-1;i>=0;offset = --i) {
    		for(int j = 0;j<height;j++,offset+=width) {
    			if (inarray[offset]==255) {
    				if (x_max == -1) {
    					x_max = i;
    					y_max_right = y_min_right = j;
    				} else {
    					y_max_right = j;
    				}
    				
    			}
    		}
    		if (x_max !=-1) break;
    	}
    }

	
	
	/*Convex HULL*/
    public BufferedImage env_conv (BufferedImage inimg)
    {
    	//Util.writePGMImage(inimg, "env_conv_in"+inimg.getHeight()+inimg.getWidth()+".pgm");
    	
    	int width  = inimg.getWidth(null);

    	int height = inimg.getHeight(null);	

    	int[] inarray = Util.getImageArray(inimg);
    	
    	int[] outarray = new int[width*height];
    	
    	int l = width*height;
    	
    	
    
    	int y1, y2;
    	int i,j;
  	
    	PointList pl = new PointList(width);
    	PointList pr = new PointList(width);
    	
    	for (i = 0; i < l; i++) {
    		outarray[i] = 0;
    	}
    	
    	BufferedImage outimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    	int startX = 0; int startY = 0;
	    Util.greyToColorImage (outarray, width, height);
	    outimg.setRGB(startX, startY, width, height, outarray, 0, width);

    	left_bounds(inimg);
    	
        Util.drawLine (outimg, x_min, y_min_left, x_min, y_max_left);
    	
    	right_bounds(inimg);
    	 	    
    	Util.drawLine (outimg, x_max, y_min_right, x_max, y_max_right);
    		
    	outarray = Util.getImageArray(outimg);
    	
    	pl.push_haut (x_min, y_min_left);
    	
    	pl.push_bas (x_min, y_max_left);
         	
    	y1=y_min_left-1;
        y2=y_max_left+1;
    	for(i=x_min+1;i<=x_max;i++) {
    		for(j=0;j<=y1;j++)
    			if (inarray[i+j*width]==255) {
    				pl.push_haut(i, j);
    				y1=j-1;
    				break;
    			}
    		for(j=height-1;j>=y2;j--)
    			if (inarray[i+j*width]==255) {
    				pl.push_bas(i, j);
    				y2=j+1;
    				break;
    			}
    	}
//    	DataBuffer d = outimg.getRaster().getDataBuffer();
    	for(i=0;i< pl.getNbPointHaut();i++) {
    		outarray[pl.getXHaut(i) + pl.getYHaut(i)*width]=255;
//    		d.setElem(pl.getXHaut(i) + pl.getYHaut(i)*width, 255 + 255 << 8 + 255 << 16 );
    	}
    	for(i=0;i<pl.getNbPointBas();i++) {
    		outarray[pl.getXBas(i) + pl.getYBas(i)*width]=255;
    	}
    	
    	
	    pr.push_haut (x_max, y_min_right);
    	
    	pr.push_bas (x_max, y_max_right);

    	y1=y_min_right-1;
        y2=y_max_right+1;

    	for(i=x_max-1;i>=x_min;i--) {
    		for(j=0;j<=y1;j++)
    			if (inarray[i+j*width]==255) {
    				pr.push_haut(i, j);
    				y1=j-1;
    				break;
    			}
    		for(j=height-1;j>=y2;j--)
    			if (inarray[i+j*width]==255) {
    				pr.push_bas(i, j);
    				y2=j+1;
    				break;
    			}
    	}


    	for(i=0;i<pr.getNbPointHaut();i++) {
    		outarray[pr.getXHaut(i) + pr.getYHaut(i)*width]=255;
    	}
    	for(i=0;i<pr.getNbPointBas();i++) {
    		outarray[pr.getXBas(i)+pr.getYBas(i)*width]=255;
    	}

   	    Util.greyToColorImage (outarray, width, height);
	    outimg.setRGB(startX, startY, width, height, outarray, 0, width);
        	
    	Util.drawLine (outimg, pl.getXHaut(pl.getNbPointHaut() - 1), pl.getYHaut(pl.getNbPointHaut() - 1), pr.getXHaut(pr.getNbPointHaut() - 1), pl.getYHaut(pl.getNbPointHaut() - 1));
    	Util.drawLine (outimg, pl.getXBas(pl.getNbPointBas() - 1), pl.getYBas(pl.getNbPointBas() - 1), pr.getXBas(pr.getNbPointBas() - 1), pl.getYBas(pl.getNbPointBas() - 1));

    	pl.parcours_left(outimg);
    	pr.parcours_right(outimg);

    	fill_in(outimg);

    	//Util.writePGMImage(outimg, "env_conv_out"+outimg.getHeight()+outimg.getWidth()+".pgm");
    	
        return outimg;
    }
    
    public int perim (BufferedImage inimg)
    {
    	int x, y;
    	int perim=0;
    	int offset;
    	int offset_1, offset_2;

    	int width  = inimg.getWidth(null);

    	int height = inimg.getHeight(null);	
    	
       	int[] inarray = Util.getImageArray(inimg);

    	for(y=1,offset=width+1;y<height-1;y++, offset+=2)
    		for(x=1;x<width-1;x++,offset++) {
    			//printf("%d ", offset);
    			if(inarray[offset]==255) {
    				if (inarray[offset-1]==0 || inarray[offset+1]==0 || inarray[offset-width]==0 || inarray[offset+width]==0) perim++;
    			}
    		}
    	for(offset_1=1, offset_2=(height-1)*width+1;  offset_1<width-1;  offset_1++, offset_2++) {
    		if(inarray[offset_1]==255) {
    			if (inarray[offset_1-1]==0 || inarray[offset_1+1]==0 || inarray[offset_1+width]==0) perim++;
    		}
    		if(inarray[offset_2]==255) {
    			if (inarray[offset_2-1]==0 || inarray[offset_2+1]==0 || inarray[offset_2-width]==0) perim++;
    		}
    	}
    	for(offset_1=width, offset_2=2*width-1;offset_1<width*(height-1);offset_1+=width, offset_2+=width) {
    		if(inarray[offset_1]==255) {
    			if (inarray[offset_1+1]==0 || inarray[offset_1-width]==0 || inarray[offset_1+width]==0) perim++;
    		}
    		if(inarray[offset_2]==255) {
    			if (inarray[offset_2-1]==0 || inarray[offset_2-width]==0 || inarray[offset_2+width]==0) perim++;
    		}
    	}
    	if (inarray[0]==255) {if (inarray[1]==0 || inarray[width]==0) perim++;}
    	if (inarray[width-1]==255) {if (inarray[width-2]==0 || inarray[2*width-1]==0) perim++;}
    	if (inarray[(height-1)*width]==255) {if (inarray[(height-2)*width]==0 || inarray[(height-1)*width+1]==0) perim++;}
    	if (inarray[height*width-1]==255) {if (inarray[(height-1)*width-1]==0 || inarray[height*width-2]==0) perim++;}
    	return perim;
    }

    public int surface(BufferedImage inimg)
    {
    	int offset;
    	int surface=0;
    	
    	int width  = inimg.getWidth(null);

    	int height = inimg.getHeight(null);	
    	
    	int l=width*height;
    	
    	int[] inarray = Util.getImageArray(inimg);
    	for(offset=0;offset<l;) {
    		if (inarray[offset++]==255) surface++;
    	}
    	return surface;
    }
    
    //public int thickness (BufferedImage inimg)
    public int epaisseur (BufferedImage inimg)
    {    	
    	int widthSRC  = inimg.getWidth(null);

    	int heightSRC = inimg.getHeight(null);	

    	int widthDEST  = inimg.getWidth(null);

    	int heightDEST = inimg.getHeight(null);
    	
    	int[] inarray = Util.getImageArray(inimg);

     	int[][] img_tmp = new int[2][widthSRC*heightSRC];
    	int[] outarray = new int[widthSRC*heightSRC];
    	
    	int has_change;
    	int i,j;
    	int tmp_src=0;
    	int tmp_dest=1;
    	int ite;
    	int nb_point_squel;
    	int offset_img1, offset_img2, offset_val1, offset_val2;
    	int max;
        	
    	for (i = 0; i < (widthSRC*heightSRC); i++) {
    		outarray[i] = 0;
    	}
    	
    	for (i = 0; i < (widthSRC*heightSRC); i++) {
    		img_tmp[tmp_src][i] = inarray[i];
    	}
    	
    	int[] val = new int[widthSRC*heightSRC];
    	
       	offset_img1=offset_val1=0;
    	offset_img2=widthSRC*(heightSRC-1);
    	offset_val2=widthSRC*(heightSRC-1);
    	for(i=0;i<widthSRC;i++, offset_img1++, offset_img2++, offset_val1++, offset_val2++) {
    		if (inarray[offset_img1] == 0) { //Mudei
    			val[offset_val1]=1;
    		}
    		if (inarray[offset_img2] == 0) { //Mudei
    			val[offset_val2]=1;
    		}
    		img_tmp[tmp_dest][offset_img1]=img_tmp[tmp_dest][offset_img2]= 0;
    	}
    	offset_img1=offset_val1=0;
    	offset_img2=widthSRC-1;
    	offset_val2=widthSRC-1;
    	for(j=0;j<heightSRC;j++, offset_img1+=widthSRC, offset_img2+=widthSRC, offset_val1+=widthSRC, offset_val2+=widthSRC) {
    		if (inarray[offset_img1] == 0) { //Mudei
    			val[offset_val1]=1;
    		}
    		if (inarray[offset_img2] == 0) { //Mudei
    			val[offset_val2]=1;
    		}
    		img_tmp[tmp_dest][offset_img1]=img_tmp[tmp_dest][offset_img2]=0;
    	}
    	has_change=2;

    	ite=1;
    	do {
    		has_change--;
    		for(j=1;j<heightSRC-1;j++)
    			for(i=1;i<widthSRC-1;i++) {
    				int offset=i+j*widthDEST;
    				if (img_tmp[tmp_src][offset] == 0) { //Mudei
    					img_tmp[tmp_dest][offset]=0;
    					continue;
    				}
    				if (!((img_tmp[tmp_src][offset-1] > 0) && (img_tmp[tmp_src][offset+1] > 0) && (img_tmp[tmp_src][offset+widthDEST] > 0) && (img_tmp[tmp_src][offset-widthDEST] > 0) )) {
    					val[offset]=ite;
    					img_tmp[tmp_dest][offset]=0;
    					has_change=1;
    				} else img_tmp[tmp_dest][offset]=1;
    			}
    		tmp_dest=tmp_dest^1;
    		tmp_src=tmp_src^1;
    		ite++;
    	} while(has_change > 0); //Mudei aqui
    	tmp_dest=tmp_dest^1;
    	tmp_src=tmp_src^1;

    	nb_point_squel=0;
    	for(i=widthDEST;i<widthDEST*(heightDEST-1);i++) {
    		if ( val[i] > val[i-widthDEST] && val[i]>val[i+widthDEST] ) {
    			nb_point_squel++;
    		    outarray[i]=255;
    		}
    	}
    	
    	for(i=widthDEST;i<widthDEST*(heightDEST-2);i++) {
    		if (val[i]>val[i-widthDEST] && val[i]==val[i+widthDEST] && val[i]>val[i+2*widthDEST]) {
    			nb_point_squel++;
    			outarray[i]=255;
    		}
    	}
    	for (i=1;i<widthDEST-1;i++) {
    		for(j=/*widthDEST+*/i;j<widthDEST*(heightDEST/*-1*/);j+=widthDEST)
    			
    			if (val[j]>val[j-1] && val[j]>val[j+1]) {
    				nb_point_squel++;
    				outarray[j]=255;
    			}
    	}
    	for (i=1;i<widthDEST-2;i++) {
    		for(j=i;j<widthDEST*heightDEST;j+=widthDEST)
    			if (val[j]>val[j-1] && val[j]==val[j+1] && val[j]>val[j+2]) {
    				nb_point_squel++;
    				outarray[j]=255;
    			}
    	}

    	max=0;
    	for(i=0;i<widthDEST*heightDEST;i++) {
    		//System.out.println("Eppaisser -> ind : " + i + " val : " + val[i] + " img_dest : " + outarray[i] + " max = " +  max);
    		if ((outarray[i] > 0) && val[i]>max) {
    			//System.out.println("Entrei aqui no EPAISSER : " + i + " val : " + val[i]);
    			max=val[i]; //Mudei
    		}
    	}

    	return 2*max;
    }

    void fill_in(BufferedImage inimg)
    {

    	int width  = inimg.getWidth(null);

    	int height = inimg.getHeight(null);	

    	int[] inarray = Util.getImageArray(inimg);

    	int i,j,k;
    	for(j=0;j<height;j++) {
    		int offset_min=-1, offset_max = 0;
    		int offset=j*width;
    		for(i=0;i<width;i++, offset++) {
    			if (inarray[offset]==255) {
    				offset_min=offset;
    				break;
    			}
    		}
    		if (offset_min==-1) continue;
    		offset=(j+1)*width-1;
    		for(i=width-1;i>=0;i--, offset--) {
    			if (inarray[offset]==255) {
    				offset_max=offset;
    				break;
    			}
    		}
    		for(k=offset_min+1;k<offset_max;k++) inarray[k]=255;
    	}
    	int startX = 0; int startY = 0;
    	Util.greyToColorImage (inarray, width, height);
    	inimg.setRGB(startX, startY, width, height, inarray, 0, width);
    }
    

}
