package segmentation;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;

import javax.imageio.ImageIO;

import preprocessing.Util;
	
public class Regions {

	final public int NOLEVEL = -1;
	
	private int x_min;
    private int y_min;
    
	private int x_max;
    private int y_max;

    private int xg;
    private int yg;
    
    private int low_valued_neighbour;
    private int high_valued_neighbour;
    
    private int surface;
    
    private double dec;
    
    private int level; /*Level of the pyramid where the box region was found or NOLEVEL*/
    
    private double perimeter;
    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;
    private int h;
    private int w;
    
    
    public Regions (){
    	this.x_min = 0;
    	this.y_min = 0;
    	this.x_max = 0;
    	this.y_max = 0;
    	this.xg = 0;
    	this.yg = 0;
    	this.low_valued_neighbour = 0;
    	this.high_valued_neighbour = 0;
    	//this.perimeter = 0;
    	this.surface = 0;
    	this.dec = 0.0;
    	this.level = NOLEVEL;
    }

    
    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 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 void setMoyenneComp (double moyenne_comp) {
    	this.moyenne_comp = moyenne_comp;
    }
    
    public void setMoyenneSurf (double moyenne_surf ) {
    	this.moyenne_surf = moyenne_surf ;
    }
    
    public void setMoyennePerim (double moyenne_perim ) {
    	this.moyenne_perim = moyenne_perim ;
    }
    
    public void setMoyenneEpaisMax (double moyenne_epais_max) {
    	this.moyenne_epais_max = moyenne_epais_max;
    }
    
    public void setMoyenneSurfConv (double moyenne_surf_surfconv) {
    	this.moyenne_surf_surfconv = moyenne_surf_surfconv;
    }
    
    public void setVarianceSurfConv (double variance_surf_surfconv ) {
    	this.variance_surf_surfconv = variance_surf_surfconv ;
    } 
      
    
    public void setXmin (int x_min) {
    	this.x_min = x_min;
    }
    
    public int getXmin () {
    	return this.x_min;
    }
    
    public void setYmin (int y_min) {
    	this.y_min = y_min;
    }
    
    public int getYmin () {
    	return this.y_min;
    }
    
    public void setLevel (int level) {
    	this.level = level;
    }
    
    public int getLevel () {
    	return this.level;
    }
    
    public void setXmax (int x_max) {
    	this.x_max = x_max;
    }
    
    public int getXmax () {
    	return this.x_max;
    }
    
    public void setYmax (int y_max) {
    	this.y_max = y_max;
    }
    
    public int getYmax () {
    	return this.y_max;
    }
    
    public void setPerimeter (double perimeter) {
    	this.perimeter = perimeter;
    }
    
    public double getPerimeter () {
    	return this.perimeter;
    }
    
     
    public void setLowValueNeighbour (int low_valued_neighbour) {
    	this.low_valued_neighbour = low_valued_neighbour;
    }
    
    public int getLowValuedNeighbour () {
    	return this.low_valued_neighbour;
    }
    
    public void setHighValueNeighbour (int high_valued_neighbour) {
    	this.high_valued_neighbour = high_valued_neighbour;
    }
    
    public int getHighValuedNeighbour () {
    	return this.high_valued_neighbour;
    }
     
    public int getXg () {
    	return this.xg;
    }
    
    public void setXg (int xg) {
    	this.xg = xg;
    }
    
    public int getYg () {
    	return this.yg;
    }
    
    public void setYg (int yg) {
    	this.yg = yg;
    }
        
    public int getSurface () {
    	return this.surface;
    }
    
    public void setSurface (int surface) {
    	this.surface = surface;
    }
        
    public void setDec (double dec) {
    	this.dec = dec;
    }
    
    public double getDec () {
    	return this.dec;
    }
    
    public void add_point_to_region (int x, int y) {
        this.x_min = Math.min (this.x_min, x);
    	this.x_max = Math.max (this.x_max, x);
        this.y_min = Math.min (this.y_min, y);
        this.y_max = Math.max (this.y_max, y);
        this.xg += x;
        this.yg += y;
        this.surface++;
    }
    

    public static void rescale_size (Regions reg, int scale_old, int scale_new) 
	{
    	assert(scale_old >= scale_new);
    	
    	int mag = (int) Math.pow(2,scale_old-scale_new);
    	
    	reg.setXmin(reg.getXmin()*mag);
    	reg.setYmin(reg.getYmin()*mag);
    	reg.setXmax((reg.getXmax()+1)*mag-1);
    	reg.setYmax((reg.getYmax()+1)*mag-1);
    	
    	reg.setXg(reg.getXg()*mag);
    	reg.setYg(reg.getYg()*mag);
    	
    	//reg.setPerimeter(reg.getPerimeter()*mag);
    	
    	reg.setSurface(reg.getSurface()*(mag*mag));
    	
    	
    	reg.setDec(reg.getDec());
    	reg.setLowValueNeighbour(reg.getLowValuedNeighbour());
    	reg.setHighValueNeighbour(reg.getHighValuedNeighbour());
	}
         
    /*Assuming that two boxes overlap, returns {true} iff the box {regi} is more likely to be letter than
     * box {regj}. Assumes that {dec} fields have been set. */
    public static boolean dominates (Regions regi, Regions regj) {
    	return (regi.getDec() < regj.getDec());
    }
    
    /*Returns the area of intersection of two bounding boxes, divided by the area of the smallest box.*/
    public static double overlap (Regions regi, Regions regj) {
    	int regi_xmin = regi.getXmin ();
    	int regi_xmax = regi.getXmax ();
    	int regi_ymin = regi.getYmin ();
    	int regi_ymax = regi.getYmax ();
    	
    	int regj_xmin = regj.getXmin ();
    	int regj_xmax = regj.getXmax (); 
    	int regj_ymin = regj.getYmin ();
    	int regj_ymax = regj.getYmax ();
    	
    	int ov_xmin = Math.max(regi_xmin, regj_xmin);
    	int ov_xmax = Math.min(regi_xmax, regj_xmax);
    	int ov_ymin = Math.max(regi_ymin, regj_ymin);
    	int ov_ymax = Math.min(regi_ymax, regj_ymax);
    	
    	if (ov_xmin > ov_xmax || ov_ymin > ov_ymax) return 0;
    	
    	int regi_area =  (regi_xmax - regi_xmin + 1)*(regi_ymax - regi_ymin + 1);
    	int regj_area =  (regj_xmax - regj_xmin + 1)*(regj_ymax - regj_ymin + 1);
    	int ov_area =  (ov_xmax - ov_xmin + 1)*(ov_ymax - ov_ymin + 1);
    	int min_area = Math.min (regi_area, regj_area);
    	return ((double)ov_area)/((double)min_area);
    }
    
    
    
    public static void show_list (ArrayList<Regions> L, BufferedImage img, String image_name) {
    	
    	BufferedImage outimg = Util.imageScale (img, 1.0);
    	
    	Graphics2D g = outimg.createGraphics();
		
    	g.setStroke(new BasicStroke(1.0f));
    	
    	g.setColor(Color.red);
    	
    	for (int l = 0; l < L.size(); l++) {
    		Regions r = L.get(l);
    		
    		//divided by 2 because the boxes are relative to the bicubic intepolated image
    		int x = r.getXmin()/2; 
    		int y = r.getYmin()/2;
    		int w = (r.getXmax() - r.getXmin() + 1)/2;
    		int h = (r.getYmax() - r.getYmin() + 1)/2;
    		
    		g.drawRect(x, y, w, h);
    	   		
    		//System.err.printf("Drawing reg[%d] = [%d,%d] x  [%d,%d] \n", l, x, y, w, h);

    	} 
    	
    	g.dispose();
    	
    	try {
			ImageIO.write(outimg, "png", new File(image_name));
    	}
		catch (Exception e) {
			System.err.printf("cannot write image %s\n", image_name);
		}
    }
    
    public static void redefine_regions (ArrayList<Regions> L) {
    	
   	
    	for (int l = 0; l < L.size(); l++) {
    		Regions r = L.get(l);
    		
    		//divided by 2 because the boxes are relative to the bicubic intepolated image
    		r.setXmin((int)(r.getXmin()/2)); 
    		r.setYmin((int)(r.getYmin()/2)); 
    		r.setXmax((int)(r.getXmax()/2+1)); 
    		r.setYmax((int)(r.getYmax()/2+1)); 
    		
    		r.setXg((int)(r.getXg()/2)); 
    		r.setYg((int)(r.getYg()/2)); 
    		r.setH((int)(r.getH()*2)); 
    		r.setW((int)(r.getW()*2));
    		r.setSurface(r.getH()*r.getW());
    	} 

    }
    
     
    
}
