package hypothesis_validation;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import javax.imageio.ImageIO;

import descriptors.HOG;
import descriptors.HoG;
import descriptors.hog;
import fr.lip6.classifier.SMOSVM;
import parameters.detection_arguments;
import preprocessing.Parser;
import preprocessing.Util;
import regrouping.Box;
import regrouping.Groupment;
import tracking.Atributes;

public class HoG_Functions {
	
	
	public static ArrayList<Atributes> HoG_Classification (
			BufferedImage image, 
			LinkedList<regrouping.Box> list,
			ArrayList<Double> hogmean,
			ArrayList<Double> hogstd,
			detection_arguments detection_parameters,
			String image_name)  {

		ArrayList<Atributes> set_D = new ArrayList<Atributes>();
		
		SMOSVM<double[]> cls = null;
		try {
    		ObjectInputStream obj = new ObjectInputStream(new FileInputStream(detection_parameters.hog));
    	    cls = (SMOSVM<double[]>) obj.readObject();
    	    obj.close();
    	}
    	catch (Exception e){
    		e.printStackTrace();
    	}
		
		for (int i = 0; i < list.size(); i++) { 			

			Box box = list.get(i);

			/*TO VERIFY*/
			int margin = 1;//(int)(0.5*(box.getYMax() - box.getYMin() + 1)*1.0/detection_parameters.Get_New_Resized_Height() + 0.5);

			System.err.printf("HoG Margin : %d\n", margin);

			if (  (box.getDec() > 0) && (box.getCount() < detection_parameters.Get_Minimum_Grouping_Set()) ) {
				continue;
			}
			
			BufferedImage iBox = Util.getSubImage (image, box.getXMin()/2-margin, box.getYMin()/2-margin, box.getXMax()/2+margin, box.getYMax()/2+margin);

			double v;
			
			if (detection_parameters.use_hog) {
			   v = Get_HoG_Score (iBox, hogmean, hogstd, cls, detection_parameters);
			}
			else {
		       v = 1.0;
			}
			
			if ((v >= 0)) 
			{
				box.setValid (-1.0); 

				/*copying the detected regions*/

				int x = box.getXMin()/2; 

				int y = box.getYMin()/2;

				int w = (box.getXMax()-box.getXMin())/2;

				int h = (box.getYMax()-box.getYMin())/2;

				Atributes new_box = new Atributes();

				/*Adicionar uma borda de -1 e +1 sobre essa area - CUIDADO*/

				new_box.set_x (x);

				new_box.set_y (y);

				new_box.set_width (w);

				new_box.set_height (h);
				
				new_box.set_number_of_characters(box.getCount());

				new_box.set_flag (false);
				
				new_box.set_fp (0);

				//new_box.set_weight (box.getDec()); //Ver isso melhor depois o PESO
				new_box.set_weight (-Double.MIN_VALUE);// -> COMENTAR ISSO PARA O TRACKING
				
				new_box.image = iBox;

				set_D.add(new_box);

				//System.err.println("AQUI NAS CAIXAS MEU");

				//System.err.printf("A ind: %d, x : %d, y : %d, w :%d, h :%d\n", i, x, y, w, h);
				
				/*try {
					ImageIO.write(iBox, "png", new File("./positives/"+image_name+String.format("%03d", i)+".png"));
					//ImageIO.write(Original, "png", new File(out_path + String.format("%05d", iframe) + "/detection.png"));
				}
				catch (Exception e) {
					System.err.println("cannot store image");
				}*/

			}
			else 
			{ 
				/*try {
					ImageIO.write(iBox, "png", new File("./negatives/"+image_name+String.format("%03d", i)+".png"));
					//ImageIO.write(Original, "png", new File(out_path + String.format("%05d", iframe) + "/detection.png"));
				}
				catch (Exception e) {
					System.err.println("cannot store image");
				}*/ 
				box.setValid (1.0);
			}
		}
		
		/*BufferedImage output = Util.imageScale (image, 1.0);
		
		Util.write_boxes (output, list, "./hog/"+image_name);  

		long stop = System.currentTimeMillis(); 
		//System.out.println("Segmentation : " + (stop-start)); 
		
		Groupment.Dispose_Small_Regions_Agroupments (output, list, detection_parameters);
			
		if (detection_parameters.write_image) {
			
			try {
				ImageIO.write(output, "png", new File("testando.png"));
				//ImageIO.write(Original, "png", new File(out_path + String.format("%05d", iframe) + "/detection.png"));
			}
			catch (Exception e) {
				System.err.println("cannot store image");
			} 
		} */
		
		System.err.printf("O TAMANHO DO CONJUNTO SET_D EH: %d\n", set_D.size()); 
		
		
		return set_D;
	}
		
	public static int read_hog_vectors ( ArrayList<Double> mean, ArrayList<Double> std, String hog_file)
	{
		int hog_size = -1;
		
		try {
			Parser obj = new Parser();
						
			LineNumberReader file = new LineNumberReader(new FileReader(hog_file));
			
			hog_size = Integer.parseInt(obj.getLineParameter (file, "\n", 0)); 
			
			for(int i = 0; i < hog_size; i++) {
				String[] s = obj.getTokens (file, "\n");
				mean.add( Double.parseDouble(s[0]));
			}
			for(int i = 0; i < hog_size; i++) {
				String[] s = obj.getTokens (file, "\n");
				std.add(Double.parseDouble(s[0]));
			}

			file.close();
		}
		catch (IOException e) {
			System.err.println("exception: failed to read hog files!");
			e.printStackTrace();
		}
		return hog_size;
	}
	
    
	public static double Get_HoG_Score (
			BufferedImage image, 
			ArrayList<Double> mean, 
			ArrayList<Double> std, 
			SMOSVM<double[]> cls,
			detection_arguments detection_parameters) 
    {		
		HOG hog_object = new HOG();
		
		//System.err.printf("cells x : %d, cells y : %d\n", detection_parameters.number_of_cells_x, detection_parameters.number_of_cells_y);
		
		double[] hog_descriptor = hog_object.hog ( 
				image, 
				detection_parameters.rwt, 
				detection_parameters.gauss_norm_weight,
				detection_parameters.number_of_cells_x, 
				detection_parameters.number_of_cells_y, 
				detection_parameters.bins_per_cell,
				detection_parameters.new_height,
				detection_parameters.normalize_image, 
				detection_parameters.option,
				detection_parameters.normalize_histogram_L1,
				detection_parameters.use_interval ); 
        

    	if (hog_descriptor == null) {
    		System.exit(1);
    		//return -Double.MAX_VALUE;
    	}
    	/*for(int x = 0; x < hog_descriptor.length; x++) {
    		hog_descriptor[x] = (hog_descriptor[x]-mean.get(x))/std.get(x);
    	}*/
    	return cls.valueOf(hog_descriptor); 
    }
	
	public static double[] get_descriptor (
			BufferedImage image, 
			ArrayList<String> list ) 
    {	
		double rwt = Double.parseDouble(list.get(0));
		boolean gauss_norm_weight = Boolean.parseBoolean(list.get(1));
		int number_of_cells_x = Integer.parseInt(list.get(2)); 
		int number_of_cells_y = Integer.parseInt(list.get(3)); 
		int bins_per_cell = Integer.parseInt(list.get(4));
		int new_height = Integer.parseInt(list.get(5));
		boolean normalize_image = Boolean.parseBoolean(list.get(6));
		int option = Integer.parseInt(list.get(7));
		boolean normalize_histogram_L1 = Boolean.parseBoolean(list.get(8));
		boolean use_interval = Boolean.parseBoolean(list.get(9));
		HOG hog = new HOG();
	
		double[] descriptor = hog.hog ( 
				image, 
				rwt, 
				gauss_norm_weight,
                number_of_cells_x, 
                number_of_cells_y, 
                bins_per_cell,
                new_height,
                normalize_image, 
                option,
                normalize_histogram_L1,
                use_interval ); 

    	return descriptor;
    }
	
	public static double score (
			BufferedImage image, 
			SMOSVM<double[]> cls,
			ArrayList<String> list ) 
    {	
		double rwt = Double.parseDouble(list.get(0));
		boolean gauss_norm_weight = Boolean.parseBoolean(list.get(1));
		int number_of_cells_x = Integer.parseInt(list.get(2)); 
		int number_of_cells_y = Integer.parseInt(list.get(3)); 
		int bins_per_cell = Integer.parseInt(list.get(4));
		int new_height = Integer.parseInt(list.get(5));
		boolean normalize_image = Boolean.parseBoolean(list.get(6));
		int option = Integer.parseInt(list.get(7));
		boolean normalize_histogram_L1 = Boolean.parseBoolean(list.get(8));
		boolean use_interval = Boolean.parseBoolean(list.get(9));
		HOG hog = new HOG();
	
		double[] descriptor = hog.hog ( 
				image, 
				rwt, 
				gauss_norm_weight,
                number_of_cells_x, 
                number_of_cells_y, 
                bins_per_cell,
                new_height,
                normalize_image, 
                option,
                normalize_histogram_L1,
                use_interval ); 

    	return cls.valueOf (descriptor); 
    }
	
	public static ArrayList<String> get_hog_parameters (String hog_parameters) {
		Parser parser = new Parser();
		BufferedReader arguments = parser.Open_File_Stream (hog_parameters);
		ArrayList<String> list = new ArrayList<String>();
		String[] s = null;
		do {
			s = parser.Get_Stream_Tokens (arguments, " ");
			if (s == null) { break; }
			list.add(s[0]);
		} while (s != null); 
		parser.Close_File_Stream (arguments, hog_parameters);
		return list;
	}

}
