package main;

import hypothesis_validation.HoG_Functions;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import parameters.detection_arguments;
import parameters.io_arguments;
import parameters.tracking_arguments;
import particlefiltering.particle;
import particlefiltering.particles;
import particlefiltering.pfTracking;
import preprocessing.Parser;
import preprocessing.Util;
import tracking.Atributes;
import tracking.Information;
import xml.BoxParameters;
import xml.Icdar;
import classification.SVM;
import classification.SVM_DATA;
import descriptors.HOG;
import descriptors.HoG;
import fr.lip6.classifier.SMOSVM;

public class ParticleFilter {	
	
	static double seconds = 0.0;
	
	public static void main(String[] args) {
				
		/*Reading tracking parameters*/
		
		String stracking_parameters = args[0];
		
		tracking_arguments tracking_parameters = new tracking_arguments(stracking_parameters);

		/*Reading the frames path*/
		
		String sframes_path = args[1];		
		
		/**/
		int frame_end = Integer.parseInt(args[2]);
		
		/**/
		String sout_path = args[3];

		/**/
		ArrayList<Atributes> list_text_objects = new ArrayList<Atributes>();
		
		/**/
		ArrayList<Information> text_info = new ArrayList<Information>();
		
		/*Particle Filter*/		
		ArrayList<particle[]> particles_list = new ArrayList<particle[]>();
		
		for (int iframe = 0; iframe <= frame_end; iframe++) {
			
			boolean end = false;
			if (iframe == frame_end) {
				end = true;
			}
			
			/*Creating sub-diretories (for each frame) to store the detection and tracking results*/
			File directory = new File (sout_path + String.format("%06d", iframe));
			directory.mkdir();

			/*Getting the image frame name*/
			String sframe = sframes_path + "PNG/" + String.format("%06d", iframe) + ".png";
			
			String xml_file_name = sframes_path + "XML/" + String.format("%06d", iframe) + ".xml";
			
			Evaluation in_xml = new Evaluation();

			List<Icdar> xml_text_object = in_xml.runExample(xml_file_name);
		
			/*Reading the image frames*/
			BufferedImage frame = null;
			
			try {				
				frame = ImageIO.read(new File(sframe));
			
				boolean added = Update_Object_List (iframe, list_text_objects, xml_text_object, frame, end, text_info);
				
				particles_list = PF (iframe, frame, list_text_objects, particles_list, added, sout_path, tracking_parameters); 				
			}
			catch (Exception e) {
				e.printStackTrace();
				System.exit(1);
			}			
		}	
		System.out.println("Tracking (time - seconds): " + seconds/(frame_end+1));
		//Print_Information (text_info); 
	}	
	
	public static boolean Update_Object_List (int frame, ArrayList<Atributes> list_text_objects, List<Icdar> xml_text_object, BufferedImage image, boolean end, ArrayList<Information> text_info) {
		
		boolean added = false;
		
		assert(xml_text_object.size() == 1);
		
		Icdar xml_text_list = xml_text_object.get(0);			
		
		/*Add object*/
		for (int i = 0; i < xml_text_list.getNboxes(); i++) {
			
			boolean exist = false;

			BoxParameters text = xml_text_list.getBox(i);
     		
    		for (int j = 0; j < list_text_objects.size(); j++) {
    		    
    			Atributes tmp = list_text_objects.get(j);
    			
    			if ( tmp.get_id() == text.getId() ) {
    				exist = true;
    			}    			
    		}      		
    		if (!exist) {
    			
    			//if (text.getId() == 2) {
    			
    			Atributes new_text = new Atributes();
    			new_text.set_x(text.getX());
    			new_text.set_y(text.getY());
    			new_text.set_width((int)text.getW());
    			new_text.set_height((int)text.getH());
    			new_text.set_weight (-Double.MIN_VALUE);
    			new_text.set_label(String.format("%05d", frame));//new_text.set_label(text.getText());
    			new_text.set_id(text.getId());
    			new_text.set_birth(frame);
    			new_text.set_fp(0);
    			new_text.image = image.getSubimage((int)text.getX(), (int)text.getY(), (int)text.getW(), (int)text.getH());
    			list_text_objects.add(new_text);
		
    			Information info = new Information();
    			info.set_birth(frame);    	
    			info.set_id(text.getId());
    			info.set_text(text.getText());
    			text_info.add(info); 
    			added = true;// }
    		}
		}
		
		for (int i = 0; i < list_text_objects.size(); i++) {
			
			boolean remove = true;
			
			Atributes tmp = list_text_objects.get(i);			
     		
    		for (int j = 0; j < xml_text_list.getNboxes(); j++) {    		    
    			BoxParameters text = xml_text_list.getBox(j);    		    			
    			if ( tmp.get_id() == text.getId() ) {
    				remove = false;
    			}    			
    		}    
    		if (remove || end) {
    			for (int t = text_info.size()-1; t >= 0; t--) {
    				Information info = text_info.get(t);
    				if (info.get_id() == tmp.get_id()) {
    					info.set_death(frame);
    					break;
    				}
    			}
    			if (remove) {
    			   list_text_objects.remove(i); 
        		   i--;
    			}
    		}
		}
		return added;
	}	
	
	public static void Print_Information (ArrayList<Information> text_info) {
		
		int number_of_ids = 0;
		for (int j = 0; j < text_info.size(); j++) {
			Information info = text_info.get(j);
			number_of_ids = Math.max(info.get_id(),number_of_ids);
		}
		
		for (int i = 0; i <= number_of_ids; i++) {	
			boolean print = false;
			for (int j = 0; j < text_info.size(); j++) {
				Information info = text_info.get(j);
				if (i == info.get_id()) {
					if (!print) {
					   System.err.printf("Text : %s ->  ", info.get_text());
					   print = true;
					}
					System.err.printf(" (%d,%d) ", info.get_birth(), info.get_death());
				}
			}
			System.err.printf("\n");
		}
	}
	
	
	static ArrayList<particle[]> PF ( 
			int iframe,
			BufferedImage image,
			ArrayList<Atributes> list_text_objects,
			ArrayList<particle[]> particles_list,
			boolean added,
			String sout_path,
			tracking_arguments tracking_parameters) 
			throws FileNotFoundException, ClassNotFoundException, IOException  
	{

		BufferedImage tmp = Util.imageScale (image, 1.0);
		
		ArrayList<String> hog_parameters = HoG_Functions.get_hog_parameters (tracking_parameters.hog_parameters_trained);
				
		SMOSVM<double[]> cls = null;
		try {
			ObjectInputStream obj = new ObjectInputStream(new FileInputStream(tracking_parameters.hog_obj));
			cls = (SMOSVM<double[]>) obj.readObject();
			obj.close();
		}
		catch (Exception e){
			e.printStackTrace();
		}

		long start = System.currentTimeMillis();

		pfTracking pf = new pfTracking();

		if (added) {
			particles_list.clear();
			particles_list = new ArrayList<particle[]>();			
			for (int i = 0; i < list_text_objects.size(); i++) {
				Atributes E = list_text_objects.get(i);
				pf.Initialization(E.image, (int)(E.get_x()), (int)(E.get_y()), E.get_width(), E.get_height(), particles_list, i, tracking_parameters);
			}
		}		
		pf.Tracking (image, particles_list, particles_list.size(), iframe, tracking_parameters);
		
		long stop = System.currentTimeMillis(); 
		seconds += ((stop-start)/(double)1000.0);
		
		boolean[] remove = new boolean[list_text_objects.size()];

		for (int i = 0; i < list_text_objects.size(); i++) { remove[i] = false; } 

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

			Atributes E = list_text_objects.get(i);

			double s = particles_list.get(i)[0].get_s();
			int w_r = Math.round((float)(particles_list.get(i)[0].get_y())); 
			int w_c = Math.round((float)(particles_list.get(i)[0].get_x())); 
			int w_w = Math.round((float)(particles_list.get(i)[0].get_width() * s)); 
			int w_h = Math.round((float)(particles_list.get(i)[0].get_height() * s)); 			
			int x0 = w_c - w_w / 2; int y0 = w_r - w_h / 2; int x1 = w_w; int y1 = w_h;

			if (  (w_c - w_w / 2 + w_w) > image.getWidth()  || (w_c - w_w / 2) < 0 ||
				  (w_r - w_h / 2 + w_h) > image.getHeight() || (w_r - w_h / 2) < 0 ) {
				/*Remove all elements that have coordinates outside the image frame*/
				remove[i] = true;
			}
			else {
				
				BufferedImage text_image = image.getSubimage(w_c - w_w / 2, w_r - w_h / 2, w_w, w_h);

				/*try {
					ImageIO.write(text_image, "png", new File(sout_path + String.format("%06d", iframe) + "/box_" + E.get_label()  + ".png"));
				}
				catch (Exception e) {
					e.printStackTrace();
				}*/
								
				particles P = new particles();
				
				/*for (int j = 1; j < tracking_parameters.number_of_particles; j++) {
				    P.display_particle2(tmp, particles_list.get(i)[j], i, E.get_label());
			    }*/
				P.display_particle(tmp, particles_list.get(i)[0], i, E.get_label());

				//if (tracking_parameters.similarity_option.equals("VALIDATION")) {
					double score = HoG_Functions.score (text_image, cls, hog_parameters);
					//System.out.printf("%d %f %f\n", iframe, score, particles_list.get(i)[0].get_weight());
				//}
					
				System.out.printf("%d %f %f %f\n", iframe, score, particles_list.get(i)[0].get_weight(), E.get_weight());
					
				if (E.get_weight() == -Double.MIN_VALUE) {
					E.set_weight(score);
				}
				else {
					E.set_weight((1.0 - tracking_parameters.rho)*E.get_weight() + (tracking_parameters.rho * score));
				}

				
				/*Updating text-object coordinates*/
				E.set_x(x0);
				E.set_y(y0);
				E.set_width(x1);
				E.set_height(y1);
				//E.image = image.getSubimage(w_c - w_w / 2, w_r - w_h / 2, w_w, w_h);
								
				if (E.get_weight() < 0.0) {
					E.set_fp(E.get_fp()+1);
					if (E.get_fp() >=  4) {
						list_text_objects.remove(i);
						particles_list.remove(i);
						i--;
						System.out.printf("removing text (score svm negative 4 frames consecutives) : %d\n", iframe);
					}
				}
				else {
					E.set_fp(0);
				}
			}
		}

		Icdar.toXML (String.format("%06d", iframe),  sout_path + String.format("%06d", iframe) + "/tracked.xml", image.getWidth(), image.getHeight(), list_text_objects); 

		try {
			ImageIO.write(tmp, "png", new File(sout_path + String.format("%06d", iframe) + "/tracking.png"));
			//ImageIO.write(image, "png", new File(sout_path + String.format("%06d", iframe) + "/originar.png"));
		}
		catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}		
		return particles_list;
	}	
}
