/*
 *  Brno University of Technology
 *
 *  Copyright (C) 2009-2010 by Brno University of Technology and the contributors
 *
 *  Complete list of developers available at our web site:
 *
 *       http://spl.utko.feec.vutbr.cz
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/.
 */
package cz.vutbr.feec.utko.opencv.operators.imageProcessing;

import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;


import ij.process.ImageProcessor;

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.List;

import com.rapidminer.operator.Operator;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.operator.ports.InputPort;
import com.rapidminer.operator.ports.OutputPort;
import com.rapidminer.operator.ports.metadata.GenerateNewMDRule;
import com.rapidminer.operator.ports.metadata.MetaData;
import com.rapidminer.operator.ports.metadata.SimplePrecondition;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeCategory;
import com.rapidminer.parameter.ParameterTypeDouble;
import com.rapidminer.parameter.ParameterTypeInt;
import com.sun.jna.ptr.IntByReference;

import cz.vutbr.feec.imageprocessing.IOObject.PointsIOObject;
import cz.vutbr.feec.utko.opencv.io.OpenCVColorImage;
import cz.vutbr.feec.utko.opencv.io.OpenCVGrayImage;
import cz.vutbr.feec.utko.opencv.io.OpenCVIOObject;

public class FeaturePoints extends Operator {

	protected InputPort inOpenCV = getInputPorts().createPort("image");
	protected OutputPort outPlug = getOutputPorts().createPort("points");

	/* PARAMS */
	private static final String PARAM1 = "number of points";
	private static final String PARAM2 = "corner quaility";
	private static final String PARAM3 = "corner minimal distance";

	public FeaturePoints(OperatorDescription description) {
		super(description);

		inOpenCV.addPrecondition(new SimplePrecondition(inOpenCV, new MetaData(
				OpenCVIOObject.class)));

		getTransformer().addRule(
				new GenerateNewMDRule(outPlug, PointsIOObject.class));
	}

	public final void doWork() throws OperatorException {
		OpenCVIOObject original1 =inOpenCV.getData();
		IplImage original = original1.getImage();
		

		int MAX_POINTS = getParameterAsInt(PARAM1);
		double CORNER_QUALITY = getParameterAsDouble(PARAM2);
		double CORNER_MIN_DISTANCE = getParameterAsDouble(PARAM3);

		int[] count = new int[1];
		int CORNER_BLOCK_SIZE = 3;

		// Konrola - puvodne bylo cvPoint2D32f.createArray(MAX_POINTS)
		CvPoint2D32f current_points = new CvPoint2D32f(MAX_POINTS);
		count[0] = MAX_POINTS;

		IplImage in = cvCreateImage(cvGetSize(original), IPL_DEPTH_8U, 1);
		cvCvtColor(original, in, CV_RGB2GRAY);

		IplImage eig = cvCreateImage(cvGetSize(original), IPL_DEPTH_32F, 1);
		IplImage temp = cvCreateImage(cvGetSize(original), IPL_DEPTH_32F, 1);

		/*
		 *
		 * (opencv_core.CvArr, 		opencv_core.CvArr, 	  opencv_core.CvArr, 	opencv_core.CvPoint2D32f, 	int[], 			double, double, opencv_core.CvArr, int, int, double) 
		 * (opencv_core.IplImage, 	opencv_core.IplImage, opencv_core.IplImage, opencv_core.CvPoint2D32f[], IntByReference, double, double, null, 			   int, int, double)
		 */
		
		cvGoodFeaturesToTrack(in, eig, temp, current_points, count,
				CORNER_QUALITY, CORNER_MIN_DISTANCE, null, CORNER_BLOCK_SIZE,
				0, 0.40);

		int detected_count = count[0];

		PointsIOObject out = new PointsIOObject(original.width(),
				original.height(), 0, 0);

		for (int i = 0; i < detected_count; i++) {
			out.addPoint((int) current_points.x(),
					(int) current_points.y());
			current_points.position();
		}

		outPlug.deliver(out);
	}

	@Override
	public List<ParameterType> getParameterTypes() {
		List<ParameterType> types = super.getParameterTypes();

		types.add(new ParameterTypeInt(PARAM1, "number of points", 1, 500, 20));
		types.add(new ParameterTypeDouble(PARAM2, "corner quaility", 0.0, 1.0,
				0.2));
		types.add(new ParameterTypeDouble(PARAM3, "corner minimal distance", 1,
				500, 20));

		return types;
	}

}
