package main;

import hypothesis_validation.HoG_Functions;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import particlefiltering.observation;
import particlefiltering.pHistogram;

import descriptors.HoG;
import evaluation.Evaluate;
import fr.lip6.classifier.SMOSVM;
import xml.BoxParameters;
import xml.Icdar;


public class Evaluation {

	public List<Icdar> runExample (String XMLFileName) { 

		/*parse the XML file and get the document object*/
		Document doc = parseXMLFile(XMLFileName);

		/*get each image element and create a Icdar object*/
		List<Icdar> list = parseDocument(doc);

		return list;
	}

	private Document parseXMLFile (String XMLFileName) {
		
		Document doc = null;
		
		/*get the factory*/
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

		try {

			/*using factory get an instance of document builder*/
			DocumentBuilder db = dbf.newDocumentBuilder();

			/*parse using builder to get the document representation of the XML file*/
			doc = db.parse(XMLFileName);
		}
		
		catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}
		
		catch(SAXException se) {
			se.printStackTrace();
		}
		
		catch(IOException ioe) {
			ioe.printStackTrace();
		}
		return doc;
	}
	
	private List<Icdar> parseDocument(Document doc){
		
		List<Icdar> list = new ArrayList();;
		
		/*get the root elememt*/
		Element docEle = doc.getDocumentElement();

		/*get a nodelist of <image> elements*/
		NodeList nl = docEle.getElementsByTagName("image");
		
		if(nl != null && nl.getLength() > 0) {
			
			/*getting each image tag do*/
			for(int i = 0 ; i < nl.getLength();i++) {

				/*get the element*/
				Element elem = (Element)nl.item(i);
				
				/*get the image information element*/
				Icdar e = getInfo(elem);
				
				/*add it to list*/
				list.add(e);
			}
		}
		return list;
	}

	/*get each image register in the ICDAR 2003 format*/
	private Icdar getInfo (Element node) {

	    int width = 0, height = 0;
	    
	    LinkedList<BoxParameters> bParameters = new LinkedList<BoxParameters>();
		
		String imageName = getTextValue(node, "imageName");
		
		NodeList resolution = node.getElementsByTagName("resolution");
		
		for(int i = 0 ; i < resolution.getLength(); i++)
		{
			Element elem = (Element)resolution.item(i);
			
			/*getting the image width*/
			
			String x = elem.getAttribute("x");
			
			width = Integer.parseInt(x);
			
			/*getting the image height*/
			
			String y = elem.getAttribute("y");
			
			height = Integer.parseInt(y);
		}
				
		NodeList boxes = node.getElementsByTagName("taggedRectangle");
		
		NodeList tags = node.getElementsByTagName("tag");
		
		/*for each box in the image do*/
		for(int i = 0 ; i < boxes.getLength(); i++)
		{
			BoxParameters b = new BoxParameters ();
			
			Element elem = (Element)boxes.item(i);
			
			/*getting the beginnig of the box (x coordinate)*/
			
			String x = elem.getAttribute("x");
			
			b.setX (Double.parseDouble(x));
			
			/*getting the beginnig of the box (y coordinate)*/
			
			String y = elem.getAttribute("y");
			
			b.setY (Double.parseDouble(y));
			
			/*getting the box width*/
			
			String w = elem.getAttribute("width");
			
			b.setW (Double.parseDouble(w));
			
			/*getting the box height*/
			
			String h = elem.getAttribute("height");
						
			b.setH (Double.parseDouble(h));
			
			/*getting the svm score if it exist*/
			
			String score = elem.getAttribute("score");
						
			if (!score.isEmpty()) {
				b.setScore (Double.parseDouble(score));
			}
			else {
				b.setScore(-Double.MAX_VALUE);
			}
			
			String id = elem.getAttribute("id");
			
			b.setId (Integer.parseInt(id));
			
			/*getting the offset parameters of the box (inclination (italic))*/
			
			String offset = elem.getAttribute("offset");
			
			b.setOffset (Double.parseDouble(offset));
			
			/*getting the rotation value*/
			
			String rotation = elem.getAttribute("rotation");
			
			if (!rotation.isEmpty()) {
				b.setRotation (Double.parseDouble(rotation));
	        }
			else {
				b.setRotation (0.0);
			}
			
			/*getting the userName value*/
			
			String userName = elem.getAttribute("userName");
			
			if (!userName.isEmpty()) {
				b.setUserName (userName);
	        }
			else {
				b.setUserName ("");
			}
			
			String text = elem.getAttribute("text");
			
			if (!text.isEmpty()) {
				b.setText (text);
	        }
			else {
				b.setText("");
			}
			
			if (tags.getLength() > 0) {
				Element elem_tag = (Element)tags.item(i); 

				String tag = elem_tag.getTextContent();

				if (!tag.isEmpty()) {
					b.setTag(tag);
				}
				else {
					b.setTag ("");
				}
			}
						
			/*adding the box structure inside the list*/
			
			bParameters.add(b);
		}
		
		Icdar e = new Icdar (imageName, width, height, bParameters, boxes.getLength());

		return e;
	}
	
	private String getTextValue(Element ele, String tagName) {
		
		String textVal = null;
		
		NodeList nl = ele.getElementsByTagName(tagName);
		
		if(nl != null && nl.getLength() > 0) {
			Element el = (Element)nl.item(0);
			textVal = el.getFirstChild().getNodeValue();
		}

		return textVal;
	}

	private int getIntValue(Element ele, String tagName) {
		
		return Integer.parseInt(getTextValue(ele,tagName));
		
	}

	private void printData(List<Icdar> list){

		System.out.println("Processing " + list.size() + " images.");
		
		for(int i = 0; i < list.size(); i++) {
			Icdar e = list.get(i);
			e.print();
		}
	}
	
	static public double Match (Icdar ref, Icdar got, double sigmaThreshold, double piThreshold) {

		double[][] sigma = new double[ref.getNboxes()][got.getNboxes()];
		
		double[][] pi = new double[ref.getNboxes()][got.getNboxes()];
		
        double sum = 0.0;
        // if the truly image has no rectangles, then
        // score 1.0 for saying so, and score 0.0 otherwise

        if (ref.getNboxes() == 0) {
            if (got.getNboxes() == 0) {
                return 1.0;
            } else {
                return 0.0;
            }
        }

        // the strategy here is to find the best match for each text rectangle
        // .. which means just finding the best got score for each ref
        // and then simply averaging over all of them

        for (int i = 0; i < ref.getNboxes(); i++) {
        	
            BoxParameters refRec = ref.getBox(i);
                     
            int rx1 = (int) refRec.getX();
	    	
	    	int ry1 = (int) refRec.getY();
            
            int rx2 = (int) (rx1 + refRec.getW());
	    	
	    	int ry2 = (int) (ry1 + refRec.getH());
	    	
	      	Evaluate eref = new Evaluate (rx1, ry1, rx2, ry2);
            
            for (int j = 0; j < got.getNboxes(); j++) {
            	
            	BoxParameters gotRec = got.getBox(j);
            	
            	int gx1 = (int) gotRec.getX();
    	    	
    	    	int gy1 = (int) gotRec.getY();
                
                int gx2 = (int) (gx1 + gotRec.getW());
    	    	
    	    	int gy2 = (int) (gy1 + gotRec.getH());
                
                sigma[i][j] = eref.WolfSigma(gx1, gy1, gx2, gy2);    
                
                pi[i][j] = eref.WolfPi(gx1, gy1, gx2, gy2);
            }
        }
        
        /*Match*/
        for (int i = 0; i < ref.getNboxes(); i++) {
        	int matches = 0;
        	for (int j = 0; j < got.getNboxes(); j++) {
        		//System.out.println("sigma["+i+"]"+"["+j+"] = " + sigma[i][j]);
        		//System.out.println("pi   ["+i+"]"+"["+j+"] = " + pi[i][j]);
        		if ( (sigma[i][j] > sigmaThreshold) && (pi[i][j] > piThreshold) ) {
        			matches++;
        		}
        	}
        	if (matches == 0) {
        		sum += 0.0;
        	}
        	else if (matches == 1) {
        		sum += 1.0;
        	}
        	else {
        		sum += 0.8;
        	}
        
        }
        
        
        return sum / (ref.getNboxes());
    }
	
		
	static public double imageScore (Icdar ref, Icdar got) {

        double points = 0.0;
        // if the truly image has no rectangles, then
        // score 1.0 for saying so, and score 0.0 otherwise

        if (ref.getNboxes() == 0) {
            if (got.getNboxes() == 0) {
                return 1.0;
            } else {
                return 0.0;
            }
        }

        // the strategy here is to find the best match for each text rectangle
        // .. which means just finding the best got score for each ref
        // and then simply averaging over all of them

        for (int i = 0; i < ref.getNboxes(); i++) {
        	
            double bestMatch = 0.0;
            
            BoxParameters refRec = ref.getBox(i);
                     
            int rx1 = (int) refRec.getX();
	    	
	    	int ry1 = (int) refRec.getY();
            
            int rx2 = (int) (rx1 + refRec.getW());
	    	
	    	int ry2 = (int) (ry1 + refRec.getH());
	    	
	      	Evaluate eref = new Evaluate (rx1, ry1, rx2, ry2);
            
            for (int j = 0; j < got.getNboxes(); j++) {
            	
            	BoxParameters gotRec = got.getBox(j);
            	
            	int gx1 = (int) gotRec.getX();
    	    	
    	    	int gy1 = (int) gotRec.getY();
                
                int gx2 = (int) (gx1 + gotRec.getW());
    	    	
    	    	int gy2 = (int) (gy1 + gotRec.getH());
                
                double thisMatch = eref.matchQuality(gx1, gy1, gx2, gy2);
                
        
                if (thisMatch > bestMatch) {
                    bestMatch = thisMatch;
                }
            }
            //System.out.println("Best match: " + bestMatch);
            points += bestMatch;
            //System.out.println("Best match: " + bestMatch + ", Sum_match: " + points);
        }
        //System.out.println("Sum math: " + points);
        //System.out.println("Number of boxes: " + ref.getNboxes());
        return points / (ref.getNboxes());
    }

    static public double recall(Icdar ref, Icdar est) {
        return imageScore (ref , est);
        //return Match (ref, est, 0.8, 0.4);
    }

    static public double precision(Icdar ref, Icdar est) {
        return imageScore (est , ref);
        //return Match (est, ref, 0.8, 0.4);
    }

    static private void evaluate (List<Icdar> groundTruth, List<Icdar> estimates) throws Exception{

    	//System.err.println("Estimative size : " + estimates.size());
    	
		for(int i = 0; i < estimates.size(); i++) {
			
			Icdar e = estimates.get(i);
			
			String ename = e.getImageName();
			
			String estr = ename.substring(ename.lastIndexOf("/")+1, ename.lastIndexOf("."));
			
			//System.err.println("Image : " + estr);
									
			for(int j = 0; j < groundTruth.size(); j++) {
				
				Icdar g = groundTruth.get(j);
				
				String gname = g.getImageName();
				
				String gstr = gname.substring(gname.lastIndexOf("/")+1, gname.lastIndexOf("."));
						
				/*check that the image names are equal*/
	            if(estr.equals(gstr)) {
			
	            	double p = precision (g, e);
            
	            	double r = recall (g, e);
	            	
	            	double alpha = 0.5;
	            	
	            	double f = 1.0 / ((alpha * (1.0 / p)) + ((1-alpha) * (1.0 / r)) );
	            	
	            	System.err.println(p + " " + r + " " + f);
	  
	            	
	            }
	            /*else {
	            	System.err.println("Name mismatch: " + gstr + " != " + estr);
	            }*/
			}
		}
    }
    
    static private void break_groundtruth (List<Icdar> groundTruth, String path) throws Exception{

    	System.err.println("Groundtruth size : " + groundTruth.size());
    	
		for(int i = 0; i < groundTruth.size(); i++) {
			
			Icdar e = groundTruth.get(i);
			
			String ename = e.getImageName();
			
			String estr = null;
			if ( (ename.lastIndexOf(".") != -1)){
			    estr = ename.substring(ename.lastIndexOf("/")+1, ename.lastIndexOf("."));
			}
			else {
				estr = ename;
			}
			
			try {
				
				FileOutputStream file = new FileOutputStream(path + estr + ".xml"); 

				PrintStream out = new PrintStream(file);

				out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

				out.println("<tagset>");

				out.println("<image>");

				out.println("<imageName>" + estr+ "</imageName>");

				out.println("<resolution x=\"" + e.getWidth() + "\" y=\"" + e.getHeight() + "\"/>");
				
				if (e.getNboxes() <= 0) {
					out.println("<taggedRectangles />");
				}
				else {
					/*out.println("<taggedRectangles>");
					for (int j = 0; j < e.getNboxes(); j++) {
						
						BoxParameters box = e.getBox(j);
						
						if (box.getX() < 0) {
							box.setX(0.0);
						}
						if (box.getY() < 0) {
							box.setY(0.0);
						}
						
						out.println("<taggedRectangle x=\"" + box.getX() + "\" y=\"" + box.getY() + "\" width=\"" + box.getW() + "\" height=\"" + box.getH() + "\" text=\"" + box.getText() + "\" id=\"" + j + "\" rotation=\"0.0\"" + " offset=\"" + box.getOffset() + "\"/>");
					}
					out.println("</taggedRectangles>"); */
					
					int size = 0;
					out.println("<taggedRectangles>");
					for (int j = 0; j < (e.getNboxes()+size); j++) {
						
						BoxParameters box = null;
						for (int k = 0; k < e.getNboxes(); k++) {
							box = e.getBox(k);
							if (j == box.getId()) {
								break;
							}
						}
						
						if (box.getId() == j) {
							if (box.getX() < 0) {
								box.setX(0.0);
							}
							if (box.getY() < 0) {
								box.setY(0.0);
							}

							out.println("<taggedRectangle x=\"" + box.getX() + "\" y=\"" + box.getY() + "\" width=\"" + box.getW() + "\" height=\"" + box.getH() + "\" text=\"" + box.getText() + "\" id=\"" + box.getId() + "\" rotation=\"0.0\"" + " offset=\"" + box.getOffset() + "\"/>");
						}
						else {
							size++;
						}
					}
					out.println("</taggedRectangles>");
					
					
					
				}
				out.println("</image>");
				out.println("</tagset>");
				System.err.println("writing XML file : " + path + estr + ".xml");
				out.close();
			}
			catch (IOException exception) {
				System.err.println ("Error to write XML file\n");
				exception.printStackTrace();
			}			
		}
    }
    
    
    static private void Statistics (List<Icdar> groundTruth, String image_path, String output_path) throws Exception{

    	ArrayList<Integer> X = new ArrayList<Integer>();
    	ArrayList<Integer> Y = new ArrayList<Integer>();
    	ArrayList<Integer> W = new ArrayList<Integer>();
    	ArrayList<Integer> H = new ArrayList<Integer>();
    	ArrayList<pHistogram> G = new ArrayList<pHistogram>();

		for(int i = 0; i < groundTruth.size(); i++) {
			
			Icdar e = groundTruth.get(i);
			
			String ename = e.getImageName();
			
			//String estr = ename.substring(1, ename.lastIndexOf("."));
			
			System.err.printf("Reading image: %s\n", image_path + ename + ".png");
			
			String image_name = image_path + ename + ".png";
			
			BufferedImage in_image = ImageIO.read(new File(image_name));
			
			for (int j = 0; j < e.getNboxes(); j++) {
				BoxParameters box = e.getBox(j);

    			int x = (int) box.getX();
    			int y = (int) box.getY();
    			int w = (int) box.getW();
    			int h = (int) box.getH();
    			
    			BufferedImage sub_image = in_image.getSubimage(x, y, w, h);
    			
    			/*Computing the appearance statistics*/
    			observation obs = new observation();
    			pHistogram histo = new pHistogram();
    			HoG hog = new HoG();
    			double[] hog_desc = hog.HoGFixedNumberOfCells (sub_image, 4, 4, 2);
    			histo.alloc_vector(hog_desc.length);
    			for (int k = 0; k < hog_desc.length; k++) {
    			  histo.set_data(k, hog_desc[k]);
    			}
    			obs.normalize_histogram(histo);
    			
    			
    			//System.out.printf("%d %d %d %d %s %s - %s\n", x, y, w, h, ename, image_name, output_path + estr + "_" + String.format("%04d", j) + ".png");
    			
    			if (j == 0) {
    				
    			  X.add(x);
    			  Y.add(y);
    			  W.add(w);
    			  H.add(h);
    			  G.add(histo);
    			  
    			  /*Writing annotated sub-images to verify the groundtruth*/
    			  try {
    				String outname = output_path + ename + "_" + String.format("%04d", j) + ".png";
    	    		ImageIO.write(sub_image, "png", new File(outname)); 
    	    	  }
    	    	  catch (Exception e1) {
    	    		System.err.println("error: fail to save " + image_name + " image");
    	    	  }
    			}
  			}
		}
		
		/*Linear extrapolation of data information*/
		for (int i = 2; i < G.size(); i++) {
			
			/*X - Center*/
			double x = X.get(i) + W.get(i)/2.0;
			double x1 = X.get(i-1) + W.get(i-1)/2.0;
			double x2 = X.get(i-2) + W.get(i-2)/2.0;
			double pred_x = 2*x1 - x2;
			double diff_x = x - pred_x;
			
			/*Y - Center*/
			double y = Y.get(i) + H.get(i)/2.0;
			double y1 = Y.get(i-1) + H.get(i-1)/2.0;
			double y2 = Y.get(i-2) + H.get(i-2)/2.0;
			double pred_y = 2*y1 - y2;
			double diff_y = y - pred_y;
			
			/*Height*/
			int h  = H.get(i);
			int h1 = H.get(i-1);
			int h2 = H.get(i-2);
			int pred_h = 2*h1 - h2;
			int diff_h = h - pred_h;
			
			/*Width*/
			int w  = W.get(i);
			int w1 = W.get(i-1);
			int w2 = W.get(i-2);
			int pred_w = 2*w1 - w2;
			int diff_w = w - pred_w;
			
			/*Appearance*/
			pHistogram hog1 = G.get(i);
			pHistogram hog2 = G.get(i-1);
			observation obs = new observation();
			double d_sq = obs.histo_dist_sq (hog1, hog2);
			
			/*Plotting*/
			System.out.println(i + " " + 
					x + " " + pred_x + " " + diff_x + " " + 
					y + " " + pred_y + " " + diff_y + " " + 
					h + " " + pred_h + " " + diff_h + " " + 
					w + " " + pred_w + " " + diff_w + " " + 
					d_sq);
		}
		
    }
    
    static private void NewInformation (List<Icdar> groundTruth, String output_path) throws Exception{

		for(int i = 0; i < groundTruth.size(); i++) {
						
			Icdar e = groundTruth.get(i);
			
			String ename = e.getImageName();
			
			String estr = ename.substring(1, ename.lastIndexOf("."));
				
			FileOutputStream out = new FileOutputStream(estr+".xml");; 

			PrintStream ps = new PrintStream(out);

			System.err.printf("Writing file : %s\n", e.getImageName());

			ps.println("<image>");
			
			ps.println("<imageName>" + estr + "</imageName>");

			ps.println("<resolution x=\"" + e.getWidth() + "\" y=\"" + e.getHeight() + "\" />");

			ps.println("<taggedRectangles>");
			
			for (int j = 0; j < e.getNboxes(); j++) {
				
				BoxParameters box = e.getBox(j);

    			int x = (int) box.getX();
    			int y = (int) box.getY();
    			int w = (int) box.getW();
    			int h = (int) box.getH();

    			
    			/*if (j < 100) {
    				if (j == 0)
    					ps.println("<taggedRectangle x=\"" + (x+2) + "\" y=\"" + (y+1) + "\" width=\"" + (w-1) + "\" height=\"" + (h-2) + "\" id=\"0" + "\" word=\"Bistro" + "\" offset=\"0.0\" />");
    				else
    					ps.println("<taggedRectangle x=\"" + (x+2) + "\" y=\"" + (y+1) + "\" width=\"" + (w-1) + "\" height=\"" + (h-2) + "\" id=\"1" + "\" word=\"Romain" + "\" offset=\"0.0\" />");
    			}
    			else {*/
    				if (j == 0)
    					ps.println("<taggedRectangle x=\"" + x + "\" y=\"" + y + "\" width=\"" + w + "\" height=\"" + h + "\" id=\"0" + "\" word=\"Bistro" + "\" offset=\"0.0\" />");
    				else
    					ps.println("<taggedRectangle x=\"" + x + "\" y=\"" + y + "\" width=\"" + w + "\" height=\"" + h + "\" id=\"1" + "\" word=\"Romain" + "\" offset=\"0.0\" />");
    			//}

  			}
			ps.println("</taggedRectangles>");
			ps.println("</image>");
			ps.close();
		}
    }
    
    
    static void Dispose_Regions (List<Icdar> estimates, BufferedImage image, String image_name, boolean write_text) {

    	Graphics2D g1 = image.createGraphics();
    	g1.setStroke(new BasicStroke(2.0f));
    	g1.setColor(Color.black);
    	
    	Graphics2D g2 = image.createGraphics();
    	g2.setStroke(new BasicStroke(2.0f));
    	g2.setColor(Color.white);

      	assert(estimates.size() == 1);

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

    		Icdar e = estimates.get(i);

    		for (int j = 0; j < e.getNboxes(); j++) {

    			BoxParameters box = e.getBox(j);
    			
    			int x1 = (int) (box.getX()-1);
    			int y1 = (int) (box.getY()-1);
    			int x2 = (int) (x1 + box.getW()+2);
    			int y2 = (int) (y1 + box.getH()+2);
    			
    			int x3 = (int) (box.getX()-3);
    			int y3 = (int) (box.getY()-3);
    			int x4 = (int) (x3 + box.getW()+6);
    			int y4 = (int) (y3 + box.getH()+6);
    		    
    			int c_x = (x1+x2)/2;
    			int c_y = (y1+y2)/2;
    			
    			double angle = Math.toRadians(box.getRotation());
    			
    			Polygon pA = new Polygon();
    			pA.addPoint((int)(x1 + box.getOffset()/2), y1); 
    			pA.addPoint((int)(x2 + box.getOffset()/2), y1); 
    			pA.addPoint((int)(x2 - box.getOffset()/2), y2); 
    			pA.addPoint((int)(x1 - box.getOffset()/2), y2);
    			
    			Polygon pB = new Polygon();
    			pB.addPoint((int)(x3 + box.getOffset()/2), y3); 
    			pB.addPoint((int)(x4 + box.getOffset()/2), y3); 
    			pB.addPoint((int)(x4 - box.getOffset()/2), y4); 
    			pB.addPoint((int)(x3 - box.getOffset()/2), y4);

    			Polygon pC = rotate (pA, angle, c_x, c_y);
    			Polygon pD = rotate (pB, angle, c_x, c_y);

    			g1.drawPolygon(pC);
    			g2.drawPolygon(pD);

    			if (write_text) {
    				Font big = new Font("SansSerif", Font.BOLD, 16);
    				g1.setFont(big);
    				g1.setFont(big);
    				g1.drawString(box.getText(), x3, y3);
    				//g1.drawString(box.getText(), x3, y2+18);
    			}
    		}
    	}

    	g1.dispose();
    	g2.dispose();

    	try {
    		ImageIO.write(image, "png", new File(image_name)); 
    	}
    	catch (Exception e1) {
    		System.err.println("error: fail to save " + image_name + " image");
    	}
    }

    /** Shape objects are easy to rotate, but Polygons are
     * harder because they are constrained to int coordinates. */
    public static Polygon rotate(Polygon p, double angle, double x, double y) {
    	if (angle == 0) return p;
    	AffineTransform rotation = AffineTransform.getRotateInstance(angle, x, y);
    	PathIterator pit = p.getPathIterator(rotation);
    	float[] a = new float[6]; // as per PathIterator.currentSegment() spec
    	Polygon rp = new Polygon();
    	int ty;
    	do {
    		ty = pit.currentSegment(a);
    		if (ty != PathIterator.SEG_CLOSE)
    			rp.addPoint(Math.round(a[0]), Math.round(a[1]));
    		pit.next();
    	} while (ty!=PathIterator.SEG_CLOSE && !pit.isDone());
    	return rp;
    }
    
    static void Cut_Regions (List<Icdar> estimates, BufferedImage image, String image_name) {

    	assert(estimates.size() == 1);
   	
    	for(int i = 0; i < estimates.size(); i++) {

    		Icdar e = estimates.get(i);

    		for (int j = 0; j < e.getNboxes(); j++) {

    			BoxParameters box = e.getBox(j);

    			int x = (int) box.getX();

    			int y = (int) box.getY();

    			int w = (int) box.getW();

    			int h = (int) box.getH();
    			
    			if (x == 0) {x = 1;}
    			if (y == 0) {y = 1;}
    			if (w == image.getWidth()) {x = image.getWidth()-1;}
    			if (h == image.getHeight()) {y = image.getHeight()-1;}    
    			if ((x + w) >= image.getWidth()) { 	w = w - ((x + w) - image.getWidth()); }
    			if ((y + h) >= image.getHeight()) { h = h - ((y + h) - image.getHeight());}
    			
    			BufferedImage region = image.getSubimage(x, y, w, h); 
   			
    			try {
    				String s = String.format("%04d", box.getId());
    				ImageIO.write(region, "png", new File(image_name +"box_"+s+".png"));
    			}
    			catch (Exception e1) {
    				System.err.println("cannot store trainning image");
    			} 
    		}
    	}
    }
    
    static void Cut_Groundtruth (List<Icdar> estimates, String image_path, String out_path) throws IOException {
   	
    	int k = 0;
    	
    	for(int i = 0; i < estimates.size(); i++) {

    		Icdar e = estimates.get(i);
    		
    		BufferedImage image = ImageIO.read(new File(image_path + e.getImageName()));
    		
    		//System.out.printf("%s\n", image_path + e.getImageName());
    		
    		for (int j = 0; j < e.getNboxes(); j++) {

    			BoxParameters box = e.getBox(j);

    			int x = (int) box.getX();

    			int y = (int) box.getY();

    			int w = (int) box.getW();

    			int h = (int) box.getH();
    			
    			//System.out.printf("%d %d %d %d\n", x, y, w, h);
    			
    			if ( (x < 0) || (y < 0) || (x >= image.getWidth()) || (y >= image.getHeight()) || ((x + w) >= image.getWidth()) || ((y + h) >= image.getHeight()) ) {
    				continue;
    			}
    			
    			BufferedImage region = image.getSubimage(x, y, w, h); 
   			
    			try {
    				String s = String.format("%04d", k);
    				ImageIO.write(region, "png", new File(out_path + "box_" + s + ".png"));
    			}
    			catch (Exception e1) {
    				System.err.println("cannot store trainning image");
    			} 
    			
    			k++;
    		}
    	}
    }

    
    static void Cut_Regions_HoG ( 
    		List<Icdar> estimates, 
    		BufferedImage image, 
    		String image_name, 
    		String HoG_Norm, 
    		String HoG_Obj,
    		String dir_pos,
    		String dir_neg) {

    	assert(estimates.size() == 1);
    	
    	ArrayList<Double> mean = new ArrayList<Double>();
		
		ArrayList<Double> deviation = new ArrayList<Double>();
		
		HoG_Functions.read_hog_vectors (mean, deviation, HoG_Norm);
		
		SMOSVM<double[]> cls = null;
		try {
    		ObjectInputStream obj = new ObjectInputStream(new FileInputStream(HoG_Obj));
    	    cls = (SMOSVM<double[]>) obj.readObject();
    	    obj.close();
    	}
    	catch (Exception e){
    		e.printStackTrace();
    	}
   	
    	for(int i = 0; i < estimates.size(); i++) {

    		Icdar e = estimates.get(i);

    		for (int j = 0; j < e.getNboxes(); j++) {

    			BoxParameters box = e.getBox(j);

    			int x = (int) box.getX();

    			int y = (int) box.getY();

    			int w = (int) box.getW();

    			int h = (int) box.getH();
    			
    			BufferedImage region = image.getSubimage(x, y, w, h); 
    			
    			double v = HoG_Functions.Get_HoG_Score (region, mean, deviation, cls, null);

    			String outfile = null;
    			
    			String s = String.format("%04d", j);
    			
    			if (v >= 0) {
    				outfile = dir_pos + image_name + "box_" + s + ".png";
    			}
    			else {
    				outfile = dir_neg + image_name + "box_" + s + ".png";
    			}
    			
    			try {
    				ImageIO.write(region, "png", new File(outfile));
    			}
    			catch (Exception e1) {
    				System.err.println("unable to write the image");
    			} 
    		}
    	}
    }
    
	public static void main(String[] args) throws Exception{ 
		
		
		String xml_file_name = args[0];
		
		Evaluation in_xml = new Evaluation();
		
		List<Icdar> estimates = in_xml.runExample(xml_file_name);
		
		String option = args[1];
		
		if (option.compareTo("-cut_regions") == 0) {
			
			System.err.println("Extracting XML regions from image");
			
			String image_name = args[2];
			
			BufferedImage in_image = ImageIO.read(new File(image_name));
			
			String out_name = args[3];
			
			Cut_Regions (estimates, in_image, out_name);
	
		}
		if (option.compareTo("-cut_groundtruth") == 0) {
			
			System.err.println("Extracting image regions done in a XML groundtruth file");
			
			String image_path = args[2];
			
			String out_name = args[3];
			
			Cut_Groundtruth (estimates, image_path, out_name);
	
		}
		else if (option.compareTo("-cut_hog") == 0) {
			
			System.err.println("Extracting XML regions from image");
			
			String image_name = args[2];
			
			BufferedImage in_image = ImageIO.read(new File(image_name));
			
			String out_name = args[3];
			
			String HoG_Norm = args[4];
			
			String HoG_Obj = args[5];
			
			String dir_pos = args[6];
			
			String dir_neg = args[7];
			
			Cut_Regions_HoG (estimates, in_image, out_name, HoG_Norm, HoG_Obj, dir_pos, dir_neg);
	
		}
		else if (option.compareTo("-show_regions") == 0) {
			
			System.err.println("Drawing XML regions from image");
			
			String image_name = args[2];
			
			BufferedImage in_image = ImageIO.read(new File(image_name));
			
			String out_name = args[3];
			
			Dispose_Regions (estimates, in_image, out_name + ".regions.png", false);
			
			Dispose_Regions (estimates, in_image, out_name + ".text.png", true);
		}
		else if (option.compareTo("-evaluate") == 0) {
			
			System.err.println("Evaluating XML estimative");
			
			String groundtruth_xml_file_name = args[2];
			
			Evaluation groundtruth_xml = new Evaluation();
			
			List<Icdar> groundtruth = groundtruth_xml.runExample(groundtruth_xml_file_name);
			
			evaluate (groundtruth, estimates);
			
		}
		else if (option.compareTo("-break_groundtruth") == 0) {
			
			String groundtruth_xml_file_name = args[0];
			
			String path = args[2];
			
			Evaluation groundtruth_xml = new Evaluation();
			
			List<Icdar> groundtruth = groundtruth_xml.runExample(groundtruth_xml_file_name);
			
			break_groundtruth (groundtruth, path);
			
		}
		else if (option.compareTo("-statistics") == 0) {
			
			/*The groundtruth is in estimates*/
			String images_path = args[2];
			
			String output_path = args[3];
			
			//NewInformation (estimates, output_path);
			
			Statistics (estimates, images_path, output_path);
		}
		else {
			System.err.println("No option found");
		}
	}
}

    
    
    

