package cz.vutbr.feec.utko.objectTracking.example;

import org.opencv.features2d.Features2d;

import java.awt.Graphics;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.text.AttributeSet.FontAttribute;
import javax.swing.text.StyleConstants.FontConstants;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfInt;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.features2d.DescriptorExtractor;
import org.opencv.features2d.DescriptorMatcher;
import org.opencv.features2d.FeatureDetector;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
//import org.opencv.videoio.VideoCapture;
import org.opencv.highgui.VideoCapture;


import cz.vutbr.feec.utko.objectTracking.helpers.ImageFunctions;
import javafx.scene.text.Font;

// Funkcna verzia
 /**
 * 
 * @author Martin Rajnoha Táto trieda reprezentuje priklad detekcii tvari a
 *         vykreslovania danych detekcii do videa.
 */
public class HumanDetector {
	public static void main(String[] args) {
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // tento riadok musi byt
														// aby sa spravne
														// nacitali dll ka

		
		VideoCapture camera = new VideoCapture();
		camera.open("data/test_video.avi");// nacitanie
		//camera.open(0);
		int framecounter = 0;																// videa
		Mat frame = new Mat();
		JFrame jframe = new JFrame("MyTitle");
		jframe.setSize(1280, 720); // zatial je tu napevno nastavena velkost
									// framu
		jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JLabel vidpanel = new JLabel();
		jframe.setContentPane(vidpanel);
		jframe.setVisible(true);

		// jeden z opencv detektorov
		
		CascadeClassifier detector = new CascadeClassifier("data/opencv_detectors/haarcascades/haarcascade_frontalface_alt.xml");
		Point rectPoint1 = new Point();
		Point rectPoint2 = new Point();
		List<Template> listOfTemplates = new ArrayList<Template>();
		
		String newLine = System.getProperty("line.separator");
		PrintWriter writer;


		
		camera.isOpened();
		int oclusionHandler=0;	//adaptívnosť
		while (true) {
			// nacitava frame po frame	
			if (camera.read(frame)) {
				MatOfRect detections = new MatOfRect(); 
				detector.detectMultiScale(frame, detections);
			framecounter++;
			if (framecounter>65) {
				framecounter++;
				framecounter--;
			}
			
			System.out.println("Frame: "+framecounter);

				// Nastavenie haar
														// detektora
				/*int minNeighbors = 3;
				Size minSize = new Size(30, 30);
				Size maxSize = new Size(200, 200);
				int flags = 5;
				detector.detectMultiScale(frame, detections, 1.1, minNeighbors, flags, minSize, maxSize);*/ // detekcia
																											// objektov
				/**
				 * TODO nasledujuci riadok je najdolezitejsi - to je zoznam
				 * detekcii pre dany frame. S tym je potreba pracovat
				 */
				List<Template> removeList= new ArrayList<Template>();
				List<Rect> rectList = detections.toList();
				List<Template> detectionList= new ArrayList<Template>();
				for (Rect rect : rectList) {
					detectionList.add(new Template(frame, rect));
				}
				if (listOfTemplates.size()==0) {
					for (Template template : detectionList) {
						listOfTemplates.add(template);
					}	
				}
				double[][] assignmentArray=new double[detectionList.size()][listOfTemplates.size()];
				for (double[] ds : assignmentArray) {
					Arrays.fill(ds, 0);
				}
				
//				TemplateMatcher TMatcher= new TemplateMatcher();
//				if (listOfTemplates.size()==0) {
//					for (Template template : detectionList) {
//						listOfTemplates.add(template);
//					}	
//				}
//				TMatcher.match(listOfTemplates, detectionList, frame); //DETEKCIA POMCOU TEMPLATE
//				for (Template template : listOfTemplates) {
//					if (template.IdOfTemplateMatcher!=200) {
//						listOfTemplates.set(listOfTemplates.indexOf(template), detectionList.get(template.IdOfTemplateMatcher));
//					}
//					
//				}
//				IMatcher CMatcher=new ContourMatcher(); //DETEKCIA POMOCOU KONTÚR
//				if (listOfTemplates.size()==0) {
//					for (Template template : detectionList) {
//						listOfTemplates.add(template);
//					}
//				}
//				CMatcher.match(listOfTemplates, detectionList);
//				for (Template template : listOfTemplates) {
//					if (template.IdOfContourMatcher!=200) {
//						listOfTemplates.set(listOfTemplates.indexOf(template), detectionList.get(template.IdOfContourMatcher));
//					}
//					
//				}
				/*IMatcher Dmatcher = new DistanceMatcher(); //DETEKCIA POMOCOU VZDIALENOSTI
				Dmatcher.match(listOfTemplates,detectionList);						
				for (Template detection  : detectionList) {
					if (detection.getNearestSizeDistance()>80) {
						listOfTemplates.add(detection);
					}
					else {
						listOfTemplates.set(detection.getIdOfDistanceMatch(), detection);
					}
				}*/
				/*IMatcher Cmatcher=new ColorMatcher();//DETEKTOR PODĽA FARBY
				Cmatcher.match(listOfTemplates, detectionList);
				for (Template detection : detectionList) {
					if (detection.BhattacharyyaCoeficient>1.5) {
						listOfTemplates.add(detection);
					} else {
						listOfTemplates.set(detection.getIdOfColorMatcher()
								, detection);
					}
				}
				useColorMatcher=5;*/
				/*if (useColorMatcher>0) {//VERZIA 1.0 
					useColorMatcher--;
				}
				IMatcher Dmatcher= new DistanceMatcher();
				IMatcher Cmatcher = new ColorMatcher();
				if (useColorMatcher==0) {
					Dmatcher.match(listOfTemplates, detectionList,assignmentArray);
					for (Template det : detectionList) {
						int counter=0;
						for (Template temp : detectionList) {
							if (temp.getDistance(det)<40) {
								counter++;
							}
						}
						if ((counter>=2)&&(useColorMatcher==0)) {
							useColorMatcher=10;
						}
					}
				}

				if (useColorMatcher>0) {
					Cmatcher.match(listOfTemplates, detectionList,assignmentArray);
					for (Template detection : detectionList) {
						if (detection.BhattacharyyaCoeficient>1.5) {
							listOfTemplates.add(detection);
						} else {
							listOfTemplates.set(detection.getIdOfColorMatcher()
									, detection);
						}
					}
				}
				else {
					Dmatcher.match(listOfTemplates,detectionList,assignmentArray);						
					for (Template detection  : detectionList) {
						if (detection.getNearestSizeDistance()>80) {
							listOfTemplates.add(detection);
						}
						else {
							listOfTemplates.set(detection.getIdOfDistanceMatch(), detection);
						}
					}
				}*/
				//VERZIA2.0
				IMatcher cMatcher = new ColorMatcher(); //súbor všetkých matcherov  
				IMatcher dMatcher = new DistanceMatcher();
				IMatcher sMatcher = new SizeMatcher();
				IMatcher tMatcher = new ContourMatcher();
				IMatcher spMatcher= new PredictionMatcher();
				for (Template template : listOfTemplates) {
					template.setMatch(0);
					template.setOccupied(false);
					
				}
				if (oclusionHandler>0) {//Adaptívnosť : zmena multiplikátorov 
					cMatcher.setMultiplicator(1.2);
					//sMatcher.setMultiplicator(0.2);
					//spMatcher.setMultiplicator(0.4);
					oclusionHandler--;
				}
				if (0<oclusionHandler&&oclusionHandler<5) {//Adaptívnosť : zmena multiplikátorov
					spMatcher.setMultiplicator(0.5);
				}
				cMatcher.match(listOfTemplates, detectionList, assignmentArray);//Sem pridávať iba match TOTO
				dMatcher.match(listOfTemplates, detectionList, assignmentArray);
				sMatcher.match(listOfTemplates, detectionList, assignmentArray);	
				tMatcher.match(listOfTemplates, detectionList, assignmentArray);
				spMatcher.match(listOfTemplates, detectionList, assignmentArray);
				for (double[] ds : assignmentArray) {//Výpis priraďovacej matice
					System.out.print("|");
					for (int i = 0; i < ds.length; i++) {
						System.out.print(ds[i]+"|");
					}
					System.out.println("");
					
				}
				System.out.println("--------------------------");
				System.out.println(oclusionHandler);
				for (int i = 0; i < assignmentArray.length; i++) {
					double[] ds = assignmentArray[i];
					int idGoodMatch=200;
					double bestMatch=0;
					if (detectionList.get(i).getBhattacharyyaCoeficient()>2.0//nastavenie hodnôt pri ktorých sa jedná a nový objekt
							|| detectionList.get(i).getNearestSizeDistance()>80 
							//|| detectionList.get(i).getNearestSizeChange()>3000
							/*|| detectionList.get(i).getNumberOfGoodContours()==0*/) 
					{
						listOfTemplates.add(detectionList.get(i));//Model zjavu 
					}
					for (int j = 0; j < ds.length; j++) {//Priraďovanie najlepšieho kandidáta
						if (bestMatch<ds[j]) {
							bestMatch=ds[j];
							idGoodMatch=j;
						}
					}
					
					if(listOfTemplates.get(idGoodMatch).getOccupied()&&(listOfTemplates.get(idGoodMatch).getMatch()>bestMatch)) {
						int idMatch=200;
						double match=0;
						for (int j = 0; j < ds.length; j++) {
							if (match<ds[j]&&j!=idGoodMatch) {
								match=ds[j];
								idMatch=j;
							}
						}
						bestMatch=match;
						idGoodMatch=idMatch;
						
					}
					else {
						listOfTemplates.set(idGoodMatch, detectionList.get(i));
						detectionList.get(i).setMatch(bestMatch);
						detectionList.get(i).setId(idGoodMatch);
						listOfTemplates.get(idGoodMatch).setOccupied(true);
						double speedInX=detectionList.get(i).getRect().x-listOfTemplates.get(idGoodMatch).getPlacement().x;
						double speedInY=detectionList.get(i).getRect().y-listOfTemplates.get(idGoodMatch).getPlacement().y;
						//Point predictedState = null;
						//predictedState.x=(detectionList.get(i).getRect().x+detectionList.get(i).getRect().width)/2;
						//predictedState.y=(detectionList.get(i).getRect().y+detectionList.get(i).getRect().height)/2;
						listOfTemplates.get(idGoodMatch).setPredictedState(detectionList.get(i).getPredictedState());
						listOfTemplates.get(idGoodMatch).setSpeedInX(speedInX);
						listOfTemplates.get(idGoodMatch).setSpeedInY(speedInY);
					}

				}
				/*for (Template template : listOfTemplates) {
					Point predictedState = new Point();
					predictedState.x=template.getPredictedState().x+template.getSpeedInX();
					predictedState.y=template.getPredictedState().y+template.getSpeedInY();
					template.setPredictedState(predictedState);
				}*/
				/*if (oclusionHandler==0) {//použitie zmeny multiplikátorov
					for (Template det : detectionList) {
						int counter=0;
						for (Template temp : detectionList) {
							if (temp.getDistance(det)<40) {
								counter++;
							}
						}
						if ((counter>=2)&&(oclusionHandler<=5)) {
							oclusionHandler=15;
						}
					}
				}	*/


				if (detectionList.size() > 0) {
					for (Template temp : detectionList) {
						rectPoint1.x = temp.getRect().x;
						rectPoint1.y = temp.getRect().y;
						rectPoint2.x = temp.getRect().x + temp.getRect().width;
						rectPoint2.y = temp.getRect().y + temp.getRect().height;
						// vykresli dane obldzniky do videa
						/*if (useColorMatcher>0) {
							Imgproc.putText(frame, Integer.toString(temp.getIdOfColorMatcher()), rectPoint1 ,Core.FONT_HERSHEY_COMPLEX, 1, new Scalar(0,255,0));
							//System.out.println(temp.getIdOfColorMatcher());
						}
						else {
							Imgproc.putText(frame, Integer.toString(temp.getIdOfDistanceMatch()), rectPoint1 ,Core.FONT_HERSHEY_COMPLEX, 1, new Scalar(0,255,0));
							//System.out.println(temp.getIdOfDistanceMatch());
						}*/
						Core.putText(frame, Integer.toString(temp.getId()), rectPoint1 ,Core.FONT_HERSHEY_COMPLEX, 1, new Scalar(0,255,0));
						
							Core.rectangle(frame, rectPoint1, rectPoint2, new Scalar(255, 0, 0), 2);
							
	
					}
					Core.putText(frame, "frame: "+framecounter, new Point(20, 20) ,Core.FONT_HERSHEY_COMPLEX, 1, new Scalar(0,255,0));
					//System.out.println("---------------------------------------------------");
					
				}
				ImageIcon image = new ImageIcon(ImageFunctions.Mat2BufferedImage(frame));
				vidpanel.setIcon(image);
				vidpanel.repaint();
				try {
				FileWriter fw = new FileWriter("test.txt", true);
				BufferedWriter bw = new BufferedWriter(fw);
			    PrintWriter out = new PrintWriter(bw);
						for (Template detection : detectionList) {
							
							out.println(framecounter+", "+detection.getId()+", "+detection.getRect().x+", "+detection.getRect().y+", "+detection.getRect().width+", "+detection.getRect().height+", -1, -1, -1, -1");
							
						}
						out.close();
					} catch (Exception e) {
						// TODO: handle exception
					}
			}
			
		}

	}
}
