package project;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.video.BackgroundSubtractor;
import org.opencv.video.BackgroundSubtractorMOG2;
import org.opencv.video.Video;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.Videoio;

import MultipleKalmanTracking.CONFIG;
import MultipleKalmanTracking.Tracker;
import javafx.scene.image.Image;

public class Detect {

	static Mat imag = null;
	public static Image finalImage;
	public static Image backgroungImage;
	public Controller controller;
	public CONFIG config;
	public static Tracker tracker;
	public Main main;
	public static VideoCapture camera;
	Size sz = new Size();
	public boolean initiated = false;
	

	public void detection() {
		
		BackgroundSubtractorMOG2 mBGSub = Video.createBackgroundSubtractorMOG2(300, 50, false);
		tracker = new Tracker((float) controller.dt_slider.getValue(),
				(float) controller.noise_slider.getValue(), controller.distance_slider.getValue(),
				(int)controller.skipedFrames_slider.getValue(),
				(int)controller.traceLength_slider.getValue());

		Mat frame = new Mat();
		Mat outerBox = new Mat();
		Mat diff_frame = null;
		Vector<Rect> vector = new Vector<Rect>();
		int i1 = 0;
		boolean set = true;
		Mat firstImage = new Mat();

		while (true) {
			if (Controller.uriDone == true) {

				camera = new VideoCapture(Controller.uri);
				sz = new Size(640,480);
				Controller.uriDone = false;
				Controller.frameCount = (double)camera.get(Videoio.CAP_PROP_FRAME_COUNT);
			}

			if (Controller.Continue == true) {
				
				tracker.updateTrackerValues((float) controller.dt_slider.getValue(),
						(float) controller.noise_slider.getValue(), controller.distance_slider.getValue(),
						(int)controller.skipedFrames_slider.getValue(),
						(int)controller.traceLength_slider.getValue());

				if (camera.read(frame)) {
					Controller.frame = camera.get(Videoio.CAP_PROP_POS_FRAMES);
					//Imgproc.resize(frame, frame, sz);
					Imgproc.resize(frame, frame, sz, 0., 0.,Imgproc.INTER_LINEAR);
					imag = frame.clone();
					if (set) {
						firstImage = frame.clone();
						set = false;
					}
					outerBox = new Mat(frame.size(), CvType.CV_8UC1);
					Imgproc.cvtColor(frame, outerBox, Imgproc.COLOR_BGR2GRAY);

					if (!initiated) {
						// jframe.setSize(frame.width(), frame.height());
						diff_frame = new Mat(outerBox.size(), CvType.CV_8UC1);
						diff_frame = outerBox.clone();

					}

					if (initiated) {
						diff_frame = new Mat(frame.size(), CvType.CV_8UC1);
						processFrame(frame, diff_frame, mBGSub);
						frame = diff_frame.clone(); // doplněni
						vector = detectionContours(diff_frame, controller);
						Vector<Point> vektorBodu = new Vector<>();
						
						if (controller.radioButtonStaticLine.isSelected()) {
							Point line = new Point(320, 0);
							Point line2 = new Point(320, 480);									
							Imgproc.line(imag, new Point(line.x, line.y), new Point(line2.x, line2.y), new Scalar(0, 255, 0),
									5);
							}
						
						for (int j = 0; j < controller.pomocnePoints.size() - 1; j = j + 2) {
							Point dynLine1 = new Point(controller.pomocnePoints.get(j).x,controller.pomocnePoints.get(j).y);
							Point dynLine2 = new Point(controller.pomocnePoints.get(j + 1).x,controller.pomocnePoints.get(j + 1).y);
							Imgproc.line(imag, dynLine1, dynLine2, new Scalar(0, 0, 255), 5);
							
						}
						
						Iterator<Rect> it = vector.iterator();
						while (it.hasNext()) {
							Rect obj = it.next();

							int ObjectCenterX = (int) ((obj.tl().x + obj.br().x) / 2);
							int ObjectCenterY = (int) ((obj.tl().y + obj.br().y) / 2);

							Point pt = new Point(ObjectCenterX, ObjectCenterY);
							vektorBodu.add(pt);
						}

						if (vector.size() > 0) {
							tracker.update(vector, vektorBodu, imag);

							
							Rect obj1 = vector.iterator().next();
							Mat image_roi = new Mat(imag, obj1);
							Imgcodecs.imwrite("C:/eclipse/screens/asd" + i1 + ".bmp", image_roi);
							i1++;
							

							Iterator<Rect> it2 = vector.iterator();

							while (it2.hasNext()) {
								Rect obj = it2.next();
								int ObjectCenterX = (int) ((obj.tl().x + obj.br().x) / 2);
								int ObjectCenterY = (int) ((obj.tl().y + obj.br().y) / 2);
								
								Point pt = new Point(ObjectCenterX, ObjectCenterY);
								
								Imgproc.circle(imag, pt, 1, new Scalar(0, 0, 255), 2);
								
								if (obj.x > 320 && controller.radioButtonStaticLine.isSelected()) {
									Imgproc.rectangle(imag, obj.tl(), obj.br(), new Scalar(0, 255, 0), 1);
									
								}
								if (obj.x > 316 && obj.x < 320 && controller.radioButtonStaticLine.isSelected()) { // malé rozlišení a fps videa, šířka čáry je 5 pixelu proto +-4
																	
									controller.textArea.appendText("The object crossed the static line from the right" + "\n");
								}
								if (obj.x > 320 && obj.x < 324 && controller.radioButtonStaticLine.isSelected()) {
									controller.textArea.appendText("The object crossed the static line from the left" + "\n");
								}
								
								if (controller.radioButtonLine.isSelected()) {
									Imgproc.rectangle(imag, obj.tl(), obj.br(), new Scalar(0, 255, 0), 1);
									if (controller.app.getLines().get(0).crossLine(obj)) {
										controller.textArea.appendText("Object crossed the line" + "\n");
									}
								}
	
								if (controller.radioButtonArea.isSelected() && controller.app.getAreas().get(0).moveInArea(obj)) {
									controller.textArea.appendText("Object entered the area" + "\n");
									Imgproc.rectangle(imag, obj.tl(), obj.br(), new Scalar(0, 255, 0), 1);
								}
								
								if (controller.radioButtonEveryWhere.isSelected()) {
									Imgproc.rectangle(imag, obj.tl(), obj.br(), new Scalar(0, 255, 0), 1);
								}
								
								

							}
						}else if (vector.size()==0)
						{ 
							tracker.updateKalman(imag, vektorBodu); 

							
						}
							for (int k = 0; k < tracker.tracks.size(); k++) {
							int traceNum = tracker.tracks.get(k).trace.size();
							if (traceNum > 1) {
								for (int jt = 1; jt < tracker.tracks.get(k).trace
										.size(); jt++) {
									Imgproc.line(imag,
											tracker.tracks.get(k).trace.get(jt - 1),
											tracker.tracks.get(k).trace.get(jt),
											CONFIG.Colors[tracker.tracks.get(k).track_id % 9],
											2, 4, 0);
								}
							}
						}
					
						
					}

					initiated = true;
					finalImage = Mat2Image(imag);
					backgroungImage = Mat2Image(diff_frame);

							
					controller.update(finalImage, backgroungImage);

				}
			}

			if (Controller.Continue == false) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		}
	}

	public static Image Mat2Image(Mat image) {
		MatOfByte byteMat = new MatOfByte();
		Imgcodecs.imencode(".bmp", image, byteMat);
		return new Image(new ByteArrayInputStream(byteMat.toArray()));
	}

	public static Vector<Rect> detectionContours(Mat outmat, Controller controller) {
		Mat HIERARCHY = new Mat();
		Mat image = outmat.clone();
		List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
		Imgproc.threshold(image, image, 254, 255, Imgproc.THRESH_BINARY);
		Imgproc.findContours(image, contours, HIERARCHY, Imgproc.RETR_LIST,
				Imgproc.CHAIN_APPROX_TC89_L1);

		int maxAreaIdx = -1;
		Rect r = null;
		Vector<Rect> rect_array = new Vector<Rect>();

		for (int idx = 0; idx < contours.size(); idx++) {
			Mat contour = contours.get(idx);
			double contourarea = Imgproc.contourArea(contour);
			if (contourarea > controller.minArea_slider.getValue() && contourarea < controller.maxArea_slider.getValue()) {
				maxAreaIdx = idx;
				r = Imgproc.boundingRect(contours.get(maxAreaIdx));
				rect_array.add(r);
			}

		}

		image.release();
		return rect_array;
	}

	protected void processFrame(Mat mRgba, Mat mFGMask, BackgroundSubtractor mBGSub) {	
		mBGSub.apply(mRgba, mFGMask, controller.learningRate_slider.getValue());
		Imgproc.cvtColor(mFGMask, mRgba, Imgproc.COLOR_GRAY2BGRA, 0);
		Mat dilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));
		Mat openElem = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(7, 7), new Point(1, 1));
		final Size kSize = new Size(controller.kernelSize_slider.getValue(), controller.kernelSize_slider.getValue());
        Imgproc.blur(mFGMask, mFGMask, kSize);		
		Imgproc.dilate(mFGMask, mFGMask, dilate);
		Imgproc.morphologyEx(mFGMask, mFGMask, Imgproc.MORPH_OPEN, openElem);
		
	}	
}