package xml;

import hypothesis_validation.HoG_Functions;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import javax.imageio.ImageIO;

import main.TextDetection;
import parameters.detection_arguments;
import parameters.io_arguments;
import particlefiltering.particle;
import particlefiltering.particles;
import particlefiltering.pfTracking;
import tracking.Atributes;
import xml.Icdar;
import association.HungarianAlgorithm;
import association.Probabilies;
import classification.SVM;
import classification.SVM_DATA;
import descriptors.HoG;
import fr.lip6.classifier.SMOSVM;

public class TextTracking {
	
	public static void Tracking ( 
			ArrayList<SVM> svm_descriptors, 
			ArrayList<SVM_DATA> svm_classifiers,
			ArrayList<Double> HoG_mean,
			ArrayList<Double> HoG_std,
			io_arguments io_parameters, 
			detection_arguments detection_parameters )  {

		ArrayList<Atributes> set_T = new ArrayList<Atributes>();

		ArrayList<particle[]> particles_list = new ArrayList<particle[]>();
		
		Atributes lala = new Atributes();
		
		
		set_T.clear();
		
		/*lala.set_x(225);
		lala.set_y(142);
		lala.set_width(115);
		lala.set_height(198);*/
		
		
		lala.set_x(58);
		lala.set_y(116);
		lala.set_width(25);
		lala.set_height(43);
		
		lala.set_weight(1.0);
		lala.set_label("a");
		set_T.add(lala);

		int label = 0;

		for (int iframe = io_parameters.get_bframe(); iframe <= io_parameters.get_eframe(); iframe++) {

			boolean detection = false;

			/*Creating sub-diretories (for each frame) to store the detection and tracking results*/
			File directory = new File (io_parameters.get_out_path() + String.format("%05d", iframe));
			directory.mkdir();

			/*Getting the image frame name*/
			String sframe = io_parameters.get_frames_path() + String.format("%05d", iframe) + "/frame.png";

			/*Reading the image frames*/
			BufferedImage frame = null, tmp = null;
			
			try {
				frame = ImageIO.read(new File(sframe));
				tmp = ImageIO.read(new File(sframe));
			}
			catch (Exception e) {
				e.printStackTrace();
				System.exit(1);
			}

			if (  ( (iframe % io_parameters.get_tracking_step() ) == 0) || ( iframe == io_parameters.get_bframe() )  ) {

				/*Text Detection*/
				detection = true;
				
				/*Creating the Detected Set*/
				if (false) {
				ArrayList<Atributes> set_D = new ArrayList<Atributes>();
				
				/*Performing Text Detection*/
				set_D = TextDetection.Detection (frame, svm_descriptors, svm_classifiers, HoG_mean, HoG_std, io_parameters, detection_parameters);

				/*Writing detection results*/
				write_set_regions (frame, set_D, io_parameters, false, iframe);
				
				//lala = set_D.get(2);

				particles_list.clear();

				boolean transpose = false; 

				/*-------------------------------------------*/

				/*Getting the size of both sets {set_D and set_T}*/ 
				int size_T = set_T.size();

				int size_D = set_D.size();

				if (size_T != 0) {

					/*Computing the likelihood probability matrix between the detected {set_D} and tracked {set_T} sets*/
					double[][] P = new double[size_T][size_D];

					for (int i = 0; i < size_T; i++) {

						Atributes Ti = set_T.get (i);

						for (int j = 0; j < size_D; j++) {

							Atributes Dj = set_D.get (j);

							Probabilies Pr = new Probabilies();

							/*Frobenius product between the probabilities*/
							P[i][j] = Pr.prob_size (Ti, Dj) * Pr.prob_pos (Ti, Dj) * Pr.prob_app (Ti, Dj); 
						}
					}

					/*-------------------------------------------*/

					/*Applying Hungarian algorithm, to create the list of best assignments*/
					HungarianAlgorithm HA = new HungarianAlgorithm();

					if (P.length > P[0].length) {
						P = HA.transpose(P);
						transpose = true;
					}

					int[][] A = new int[P.length][2];

					/*Getting the list of assignments*/
					A = HA.hgAlgorithm (P, "max");

					/*-------------------------------------------*/

					/*FALTA ELMINAR OS ASSIGNMENTS FEITOS ACIMA DE UM VALOR*/
					
					/*For those elements in {set_T} that have an association in {set_D} increase its weights*/
					for (int i = 0; i < A.length; i++) {
						System.err.printf("###################### A.LENGHT = %d\n", A.length);
						if (transpose) {
							Atributes Ti = set_T.get(A[i][0]);
							Ti.set_weight(1.0);
							
							Atributes Di = set_D.get(A[i][1]);
							Di.set_flag(true);
							
							System.err.printf("###################### Entrei AQUI\n");
							System.err.printf("###################### Entrei AQUI\n");
							System.err.printf("###################### Entrei AQUI\n");
							System.err.printf("###################### Entrei AQUI\n");
						}
						else {
							Atributes Ti = set_T.get(A[i][1]);
							Ti.set_weight(1.0);
							
							Atributes Di = set_D.get(A[i][0]);
							Di.set_flag(true);
							
							System.err.printf("###################### Entrei AQUI\n");
							System.err.printf("###################### Entrei AQUI\n");
							System.err.printf("###################### Entrei AQUI\n");
							System.err.printf("###################### Entrei AQUI\n");
						}
					}

					/*-------------------------------------------*/

					/*For those elements in {set_T} that have weight less than {kappa} remove them*/
					double kappa = 0.0;
					for (int i = 0; i < size_T; i++) {
						Atributes E = set_T.get(i);
						if (E.get_weight() < kappa) {
							set_T.remove(i);
						}
					} 
				}

				/*For those elements in {set_D} that do not have an association in {set_T} insert them*/
				for (int i = 0; i < size_D; i++) {
					
					Atributes E = set_D.get (i);
					
					if (!E.get_flag()) {
						/*Setting the weight of the new detected text region element to -INF*/
						E.set_weight (-Double.MIN_VALUE); ;
						
						/*Setting the label of the new detected text region element*/
						E.set_label(String.valueOf(label));
						
						/*Inserting the new detected text region element*/
						set_T.add(E);
					
						/*Updating the number of text region labels*/
						label++;
					}
				}
			}
			
			}
			
			
			/*Tracking with Particle Filters*/
			particles_list = PF (iframe, tmp, set_T, particles_list, HoG_mean, HoG_std, io_parameters, detection, detection_parameters); 
		}
	}
	
	static ArrayList<particle[]> PF ( 
			int iframe,
			BufferedImage image,
			ArrayList<Atributes> set_T,
			ArrayList<particle[]> particles_list,
			ArrayList<Double> hogmean, 
			ArrayList<Double> hogstd, 
			io_arguments io_parameters,
			boolean detection,
			detection_arguments detection_parameters)  
			{
		
		
		System.err.printf ("PF\n");
		
		/*HoG*/
		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();
    	}
		long start = System.currentTimeMillis();
		
		int number_of_particles = 100;

		//int number_of_elements = 0;

		double ft = 0.0, rho = 0.4;

		pfTracking pf = new pfTracking();

		//particles_list = new ArrayList<particle[]>();

		if (detection) {

			//particles_list = new ArrayList<particle[]>();
			
			System.err.printf("entrei aqui deteccao\n");
			
			for (int i = 0; i < set_T.size(); i++) {

				Atributes E = set_T.get(i);

				pf.Initialization(image, (int)(E.get_x()), (int)(E.get_y()), E.get_width(), E.get_height(), particles_list, i, number_of_particles);

				//number_of_elements++;
			}
		}

		/*System.err.printf("Number of elements : %d, particles_list size : %d\n", number_of_elements, particles_list.size());
		
		for (int i = 0; i < particles_list.size(); i++) {
			particle[] p = particles_list.get(i);
			for(int j = 0; j < number_of_particles; j++ ) {
				System.err.printf("particula %d, x: %d\n", j, p[j].get_x());
			}
		}*/
		
		pf.Tracking (image, particles_list, number_of_particles, particles_list.size(), iframe);

		System.err.printf ("list size : %d\n", set_T.size());
		
		for (int i = 0; i < set_T.size(); i++) {

			Atributes E = set_T.get(i);

			HoG dhog = new HoG();

			double p_x = particles_list.get(i)[0].get_x();

			double p_y = particles_list.get(i)[0].get_y();

			double p_s = particles_list.get(i)[0].get_s();

			int p_w = particles_list.get(i)[0].get_width();

			int p_h = particles_list.get(i)[0].get_height();

			int x0 = Math.round( (float)(p_x - 0.5 * p_s * p_w) );

			int y0 = Math.round( (float)(p_y - 0.5 * p_s * p_h) );

			int x1 = Math.round( (float)(p_s * p_w) );

			int y1 = Math.round( (float)(p_s * p_h) );
			
			if ((x0 + x1) > image.getWidth()) {
				x1 = image.getWidth() - x0 -1;
			}
			if ((y0 + y1) > image.getHeight()) {
				y1 = image.getHeight() - y0 -1;
			}

			if ( (x0 > 0) && (y0 > 0) &&  ( (x0 + x1) < image.getWidth() ) && ( (y0 + y1) < image.getHeight() )  ) {

				System.err.printf ("Gravei imagem\n");
				
				BufferedImage iBox = image.getSubimage(x0, y0, x1, y1);

				double v =  HoG_Functions.Get_HoG_Score (iBox, hogmean, hogstd, cls); 

				particles P = new particles();

				/*VERIFICAR ISSO ?????????????*/
				if (v >= 0) {
					//textzones tz = tzones.get(k);
					/*for (int j = 1; j < number_of_particles; j++) {
						P.display_particle(image, particles_list.get(i)[j], i, E.get_label());
					}*/
					P.display_particle3(image, particles_list.get(i)[0], i, E.get_label());
					//P.display_particle(image, particles_list.get(i)[0], i, E.get_label());
				}
				else {
					P.display_particle3(image, particles_list.get(i)[0], i, E.get_label());
					/*for (int j = 1; j < number_of_particles; j++) {
						P.display_particle2(image, particles_list.get(i)[j], i, E.get_label());
					}*/
					//textzones tz = tzones.get(k);
					//P.display_particle2(image, particles_list.get(i)[0], i, E.get_label());
				}

				if ( (E.get_weight() != -Double.MIN_VALUE) && (detection) ) {
					ft = (1.0 - rho)*E.get_weight() + (rho * v);	
				}
				else if (detection) {
					ft = (1.0 - rho)*v + (rho * v);
				}
				else {
					ft = (1.0 - rho)*ft + (rho * v);
				}
				
				System.err.printf ("end do Gravei imagem\n");

			}

			//if (frame == eframe) {

			//textzones tz = tzones.get(k);
			E.set_x(x0);
			E.set_y(y0);
			E.set_width(x1);
			E.set_height(y1);
			E.set_weight(ft);

			if (detection) {		
				if (x0 > 0 && y0 > 0 && (x0+x1) < image.getWidth() && (y0+y1) < image.getHeight()) {
					E.image = image.getSubimage(x0, y0, x1, y1);
				}

			}

		}

		Icdar.toXML (String.format("%06d", iframe) + ".xml",  io_parameters.get_out_path() + String.format("%05d", iframe) + "/out.tracked.xml", image.getWidth(), image.getHeight(), set_T, detection_parameters); 

		try {
			ImageIO.write(image, "png", new File(io_parameters.get_out_path() + String.format("%05d", iframe) + "/tracking.png"));
		}
		catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
			
		long stop = System.currentTimeMillis(); 
		System.out.println("Tracking : " + (stop-start)); 

		
		return particles_list;
	}
	
	
	static void write_set_regions (BufferedImage image, ArrayList<Atributes> set, io_arguments io_parameters, boolean option, int frame) {
		
		for (int i = 0; i < set.size(); i++) {
			
			Graphics2D g = image.createGraphics();
			
	    	g.setStroke(new BasicStroke(2.0f));
	    	
		    g.setColor(Color.yellow);
			
			Atributes A = set.get (i);
			
			int x = (int)(A.get_x()); 
		    int y = (int)(A.get_y());
		    int w = A.get_width(); 
		    int h = A.get_height();
		    
		    g.drawRect(x, y, w, h);
	    	    	
	    	g.dispose();
		}
		try {
			if (option) {
				ImageIO.write(image, "png", new File(io_parameters.get_out_image() + ".list.png"));
			}
			else {
				ImageIO.write(image, "png", new File(io_parameters.get_out_path() + String.format("%05d", frame) + "/detection.png"));
			}
		}
		catch (Exception e) {
			if (option) {
				System.err.printf("cannot write image %s\n", io_parameters.get_out_image());
			}
			else {
				System.err.printf("cannot write image %s\n", io_parameters.get_out_path() + String.format("%05d", frame) + "/detection.png");
			}
		} 
		
	}

}
