package regrouping;

import java.awt.image.BufferedImage;
import descriptors.Shape;
import parameters.detection_arguments;
import preprocessing.Util;
import segmentation.Labels;
import segmentation.Regions;

public class Box {
	
	private int cx;
    private int cy;
    
    private double valid;
    
    private int pyr_level;
    
    private int h;
    private int w;
    
    private boolean flag;
    
    private double dec;
    private int x_min;
    private int x_max;
    private int y_min;
    private int y_max;
    private int count;

    private double moyenne_comp;
    private double moyenne_surf;
    private double moyenne_perim;
    private double moyenne_epais_max;
    private double moyenne_surf_surfconv;
    private double variance_surf_surfconv;
    
    public int getCount () {
    	return this.count;
    }
    
    public void setValid (double valid) {
    	this.valid = valid;
    }
    
    public double getValid () {
    	return this.valid;
    }
    
    public void set_flag (boolean flag) {
		this.flag = flag;
	}
	
	public boolean get_flag () {
		return flag;
	}
    
    public double getMoyenneComp () {
    	return this.moyenne_comp;
    }
    
    public double getMoyenneSurf () {
    	return this.moyenne_surf;
    }
    
    public double getMoyennePerim () {
    	return this.moyenne_perim;
    }
    
    public double getMoyenneEpaisMax () {
    	return this.moyenne_epais_max;
    }
    
    public double getMoyenneSurfConv () {
    	return this.moyenne_surf_surfconv;
    }
    
    public double getVarianceSurfConv () {
    	return this.variance_surf_surfconv;
    }
    
    public int getH () {
    	return this.h;
    }
    
    public void setH (int h) {
    	this.h = h;
    }
    
    public int getW () {
    	return this.w;
    }
    
    public void setW (int w) {
    	this.w = w;
    }
    
    public int getCx () {
    	return this.cx;
    }
    
    public int getCy () {
    	return this.cy;
    }
    
    public int getXMin () {
    	return this.x_min;
    }
    
    public void setXMin (int x_min) {
    	this.x_min = x_min;
    }
    
    public int getXMax () {
    	return this.x_max;
    }
    
    public void setXMax (int x_max) {
    	this.x_max = x_max;
    }
    
    public int getYMin () {
    	return this.y_min;
    }
    
    public void setYMin (int y_min) {
    	this.y_min = y_min;
    }
    
    public int getYMax () {
    	return this.y_max;
    }
    
    public void setYMax (int y_max) {
    	this.y_max = y_max;
    }
    
    public double getDec () {
    	return this.dec;
    }
    
    public int getPyramidLevel () {
    	return this.pyr_level;
    }
    
    public void setPyramidLevel (int pyr_level) {
    	this.pyr_level = pyr_level;
    }
    

    public void Box_Dump () {
    	System.err.println ("Box < " + this.x_min + " " + this.y_min + " " + this.x_max + " " + this.y_max + " >" );
    	//System.err.println ("Count : " + this.count);
    	System.err.println ("H : " + this.h + " W : " + this.w);
    	//System.out.println ("e : " + (this.moyenne_epais_max/(double)this.count));
    	//System.err.println ("moyenne_surf  : " + moyenne_surf);
    	//System.err.println ("moyenne_perim  : " + moyenne_perim);
    	//System.err.println ("moyenne_comp  : " + moyenne_comp);
    	//System.err.println ("moyenne_epais_max  : " + moyenne_epais_max);
    	//System.err.println ("moyenne_surf_surfconv : " + moyenne_surf_surfconv);
    	//System.err.println ("variance_surf_surfconv : " + variance_surf_surfconv);
    }
    
    public Box (Labels lab_contour, Regions reg, int num_reg)
    {
    	Shape d = new Shape();
    	BufferedImage motif = extract_region (lab_contour, reg, num_reg);
    	BufferedImage env_c = d.env_conv(motif);

    	x_min = reg.getXmin ();
    	x_max = reg.getXmax ();
		y_min = reg.getYmin ();
		y_max = reg.getYmax ();
    	
    	cx = (x_max + x_min)/2;
    	cy = (y_max + y_min)/2;
    	h = y_max - y_min + 1;
    	w = x_max - x_min + 1;

    	dec = reg.getDec();
    	
    	pyr_level = -1;

    	count = 1;

    	moyenne_surf = reg.getSurface();
    	moyenne_perim = d.perim(motif);
    	moyenne_comp = moyenne_surf/(double)moyenne_perim/(double)moyenne_perim;
    	moyenne_epais_max = d.epaisseur(motif);
    	moyenne_surf_surfconv = moyenne_surf/d.surface(env_c);
    	variance_surf_surfconv = moyenne_surf_surfconv*moyenne_surf_surfconv;
    	
    	reg.setH(h);
    	reg.setW(w);
    	reg.setPerimeter(moyenne_perim); 
    	reg.setMoyenneComp(moyenne_comp);
    	reg.setMoyenneEpaisMax(moyenne_epais_max);
    	reg.setMoyenneSurfConv(moyenne_surf_surfconv);
    	reg.setVarianceSurfConv(variance_surf_surfconv );
    }
    
    public Box (Regions reg, int num_reg)
    {
     	x_min = reg.getXmin ();
    	x_max = reg.getXmax ();
		y_min = reg.getYmin ();
		y_max = reg.getYmax ();
    	
    	cx = (x_max + x_min)/2;
    	cy = (y_max + y_min)/2;
    	h = y_max - y_min + 1;
    	w = x_max - x_min + 1;

    	dec = reg.getDec();
    	
    	pyr_level = -1;

    	count = 1;

    	moyenne_surf = reg.getSurface();
    	moyenne_perim = reg.getPerimeter();
    	moyenne_comp = reg.getMoyenneComp();
    	moyenne_epais_max = reg.getMoyenneEpaisMax();
    	moyenne_surf_surfconv = reg.getMoyenneSurfConv();
    	variance_surf_surfconv = reg.getVarianceSurfConv();
   	
    } 
    
  
    public Box() {
    	x_min = -1;
    	x_max = -1;
		y_min = -1;
		y_max = -1;
    	cx = -1;
    	cy = -1;
    	h = -1;
    	w = -1;
    	dec = -1;
    	pyr_level = -1;
    	count = Integer.MAX_VALUE;
    	moyenne_surf = -1;
    	moyenne_perim = -1;
    	moyenne_comp = -1;
    	moyenne_epais_max = -1;
    	moyenne_surf_surfconv = -1;
    	variance_surf_surfconv = -1;
    }

	public boolean Compatible (Box ibox, detection_arguments detection_parameters)
    {
    	int h_min = Math.min (this.h, ibox.getH());

    	double deltaH = this.h - ibox.getH();
    	    	
    	if (deltaH < 0) deltaH *= -1;
    	if (deltaH/h_min >= detection_parameters.Get_S1()) {
    		return false;
    	}

    	double Cy = this.cy - ibox.getCy();
   	
    	if (Cy<0) Cy*=-1;
    	
    	if (Cy/h_min >= detection_parameters.Get_S2()) {
    		return false;
    	}

    	double d1 = this.x_min - ibox.getXMax();
    	
    	double d2 = ibox.getXMin() - this.x_max;
    	
    	double d = Math.max(d1,d2);
    	
    	if (d<0) {
    		return true;
    	}
    	if (d/h_min >= detection_parameters.Get_S3()) {
    		return false;
    	}

    	return true; 
    }
    
	boolean EncompassORIG (Box box)
	{
		///if (Main.ICDAR) {
			return false;
		//}
    	//else { 
		
		//double factor = 1.0;  
		/*if (this.x_min > (box.getXMax())) return false;
		if (box.getXMin() > (this.x_max)) return false;

		if (this.y_min > (box.getYMax())) return false;
		if (box.getYMin() > (this.y_max)) return false; 

		return true;*/ 
		//}
	}
	
	boolean Encompass (Box box)
	{
		//return false;
		/*int x1 = (int)(1.1 * this.x_min)/2;
		int y1 = (int)(1.1 * this.y_min)/2;
		int x2 = (int)(0.9 * this.x_max)/2;
		int y2 = (int)(0.9 * this.y_max)/2;
		
		int x3 = (int)(1.1 * box.getXMin())/2;
		int y3 = (int)(1.1 * box.getYMin())/2;
		int x4 = (int)(0.9 * box.getXMax())/2;
		int y4 = (int)(0.9 * box.getYMax())/2;*/
		
		
		int x1 = this.x_min;
		int y1 = this.y_min;
		int x2 = this.x_max;
		int y2 = this.y_max;
		
		int x3 = box.getXMin();
		int y3 = box.getYMin();
		int x4 = box.getXMax();
		int y4 = box.getYMax();

	    int xMin = Math.max(x1, x3);
        int xMax = Math.min(x2, x4);
        int yMin = Math.max(y1, y3);
        int yMax = Math.min(y2, y4);


        double areaA = (x2 - x1) * (y2 - y1);
        
        double areaB = (x4 - x3) * (y4 - y3);

		
		/*if (x1 > x4) return false;
		if (y3 > x2) return false;

		if (y1 > y4) return false;
		if (y3 > y2) return false; */
		
	    // find area of this
	    // zero if they do not overlap
        double overlap;
        
	    if ((yMin > yMax) || (xMin > xMax))
	       overlap = 0.0;
	    else {
	    	overlap = (xMax - xMin) * (yMax - yMin);
	    }
		
		if ( ((overlap/areaA) < 0.7) && ((overlap/areaB) < 0.7) ) return false;
		
		
		
		
		
		//System.err.printf("x1 : %d, y1 : %d, x2 : %d, y2 : %d\n", x1, y1, x2, y2);
		//System.err.printf("x3 : %d, y3 : %d, x4 : %d, y4 : %d\n", x3, y3, x4, y4);
		
		
		
		return true; 
		//}
	}
        

    public void Fusion (Box ibox) {
    	
    	this.x_min = Math.min(this.x_min, ibox.getXMin());
    	this.x_max = Math.max(this.x_max, ibox.getXMax());
    	this.y_min = Math.min(this.y_min, ibox.getYMin());
    	this.y_max = Math.max(this.y_max, ibox.getYMax());

    	this.cx=(this.x_max+this.x_min)/2;
    	this.cy=(this.y_max+this.y_min)/2;
    	this.h=this.y_max-this.y_min+1;
    	this.w=this.x_max-this.x_min+1;
  
    	this.moyenne_comp += ibox.getMoyenneComp();
    	this.moyenne_surf += ibox.getMoyenneSurf();
    	this.moyenne_perim += ibox.getMoyennePerim();
    	this.moyenne_epais_max += ibox.getMoyenneEpaisMax();
    	this.moyenne_surf_surfconv += ibox.getMoyenneSurfConv();
    	this.variance_surf_surfconv += ibox.getVarianceSurfConv();

    	this.count += ibox.getCount();
    }
    
    public BufferedImage extract_region (Labels lab_contour, Regions reg, int num_reg)
    {
    	int regx_min = reg.getXmin ();
    	int regx_max = reg.getXmax ();
    	int regy_min = reg.getYmin ();
    	int regy_max = reg.getYmax ();

    	int width  = regx_max - regx_min + 1;
    	int height = regy_max - regy_min + 1;

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

    	int x, y, offset_src, offset_dest = 0;

    	for(y = regy_min, offset_src = lab_contour.getWidth() * regy_min + regx_min; y <= regy_max; offset_src = lab_contour.getWidth() * (++y) + regx_min) {
    		for(x = regx_min; x <= regx_max; x++,offset_src++) {
    			if (lab_contour.getValue(offset_src) == num_reg) {
    				outarray[offset_dest++]=255;
    			}
    			else {
    				outarray[offset_dest++]=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);
        return outimg;
    }
  
}