/*
 *  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 java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

import Jama.Matrix;

import com.googlecode.javacv.cpp.opencv_imgproc.IplConvKernel;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.UserError;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeCategory;
import com.rapidminer.parameter.ParameterTypeFile;
import com.rapidminer.parameter.ParameterTypeInt;
import com.rapidminer.parameter.ParameterTypeMatrix;
import com.rapidminer.parameter.conditions.EqualTypeCondition;
import com.rapidminer.parameter.conditions.NonEqualTypeCondition;

import cz.vutbr.feec.utko.opencv.CVUtility;

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


public abstract class BaseErodeDilate extends BaseProcessingOperator {

	protected static final String ITERATION_COUNT = "Iterations";
	private static final String TYPE_OF_KERNEL = "Kernel";
	private static final String COLS_COUNT = "Cols";
	private static final String ROWS_COUNT = "Rows";
	private static final String ANCHOR_X = "Anchor X";
	private static final String ANCHOR_Y = "Anchor Y";
	private static final String[] TYPES_OF_KERNEL = new String[] {
			"Default 3x3", 
			"Rectangular", 
			"Cross shaped", 
			"Elliptical",
			"Custom" };

	private static final String[] PARAMETER_LIST_MATRIXES = new String[] {
    	"File",
    	"Defined matrix",        
    };
	
	protected static final String PARAMETER_MATRIX = "Kernel matrix";
	protected static final String PARAMETER_FILE = "File";
	private static final String PARAMETER_MATRIX_TYPE = "Load from";

	public static final int SHAPE_DEFAULT = 0;
	public static final int SHAPE_RECT = 1;
	public static final int SHAPE_CROSS = 2;
	public static final int SHAPE_ELLIPSE = 3;
	public static final int SHAPE_CUSTOM = 4;
	
    public static final int MATRIX_FROM_FILE = 0;
    public static final int OWN_MATRIX = 1 ;

	public BaseErodeDilate(OperatorDescription description) {
		super(description);
	}

	protected IplConvKernel getKernel() throws UserError {
		switch (getParameterAsInt(TYPE_OF_KERNEL)) {
		case 0:
			return null;
		case 1:
			return cvCreateStructuringElementEx(getParameterAsInt(COLS_COUNT),
					getParameterAsInt(ROWS_COUNT), getParameterAsInt(ANCHOR_X),
					getParameterAsInt(ANCHOR_Y), CV_SHAPE_RECT, null);
		case 2:
			return cvCreateStructuringElementEx(getParameterAsInt(COLS_COUNT),
					getParameterAsInt(ROWS_COUNT), getParameterAsInt(ANCHOR_X),
					getParameterAsInt(ANCHOR_Y), CV_SHAPE_CROSS, null);
		case 3:
			return cvCreateStructuringElementEx(getParameterAsInt(COLS_COUNT),
					getParameterAsInt(ROWS_COUNT), getParameterAsInt(ANCHOR_X),
					getParameterAsInt(ANCHOR_Y), CV_SHAPE_ELLIPSE, null);
		case 4:
			Matrix matrix;
			if(getParameterAsInt(PARAMETER_MATRIX_TYPE) == MATRIX_FROM_FILE){
				String fileName = getParameterAsString(PARAMETER_MATRIX);
				BufferedReader in;
				try {
					in = new BufferedReader(new FileReader(fileName));
				} catch (FileNotFoundException e) {
					throw new UserError(this, 301, fileName);
				}
				try {
					matrix = Matrix.read(in);
				} catch (IOException e) {
					throw new UserError(this, 136, "Cannot read file " + fileName);
				}
			}else{
				matrix = new Matrix(getParameterAsMatrix(PARAMETER_MATRIX));
			}
			int[] vector = CVUtility.matrixToIntVector(matrix);
			return cvCreateStructuringElementEx(getParameterAsInt(COLS_COUNT),
					getParameterAsInt(ROWS_COUNT), getParameterAsInt(ANCHOR_X),
					getParameterAsInt(ANCHOR_Y), CV_SHAPE_CUSTOM, vector);
		default:
			return null;
		}

	}


	@Override
	public List<ParameterType> getParameterTypes() {
		List<ParameterType> p = super.getParameterTypes();
		p.add(new ParameterTypeInt(ITERATION_COUNT,
				"Dedined how many time will be function applied.", 1, 9999999,
				1));
		p.add(new ParameterTypeCategory(TYPE_OF_KERNEL, "Type of kernel.",
				TYPES_OF_KERNEL, 0));
		ParameterType cols = new ParameterTypeInt(COLS_COUNT,
				"Cols count in kernel.", 1, 128, 3);
		ParameterType rows = new ParameterTypeInt(ROWS_COUNT,
				"Rows count in kernel.", 1, 128, 3);
		ParameterType anchX = new ParameterTypeInt(ANCHOR_X,
				"X coordinate of the anchor point.", 0, 127, 1);
		ParameterType anchY = new ParameterTypeInt(ANCHOR_Y,
				"Y coordinate of the anchor point.", 0, 127, 1);

		cols.registerDependencyCondition(new NonEqualTypeCondition(this,
				TYPE_OF_KERNEL, TYPES_OF_KERNEL, true, SHAPE_DEFAULT));
		rows.registerDependencyCondition(new NonEqualTypeCondition(this,
				TYPE_OF_KERNEL, TYPES_OF_KERNEL, true, SHAPE_DEFAULT));
		anchX.registerDependencyCondition(new NonEqualTypeCondition(this,
				TYPE_OF_KERNEL, TYPES_OF_KERNEL, true, SHAPE_DEFAULT));
		anchY.registerDependencyCondition(new NonEqualTypeCondition(this,
				TYPE_OF_KERNEL, TYPES_OF_KERNEL, true, SHAPE_DEFAULT));

		ParameterType listOfMatrixes = new ParameterTypeCategory(PARAMETER_MATRIX_TYPE, "Indicates which type of kernel matrix should be applied.", PARAMETER_LIST_MATRIXES, MATRIX_FROM_FILE );
		listOfMatrixes.registerDependencyCondition(new EqualTypeCondition(this, TYPE_OF_KERNEL, TYPES_OF_KERNEL, true, SHAPE_CUSTOM));
		
		ParameterType fileMatrix = new ParameterTypeFile(PARAMETER_FILE,
				"File to load kernel matrix. All non zeros values will be included", "txt", "matrix.txt");
		fileMatrix.registerDependencyCondition(new EqualTypeCondition(this,
				PARAMETER_MATRIX_TYPE, PARAMETER_LIST_MATRIXES, true,
				MATRIX_FROM_FILE));
		fileMatrix.setExpert(false);

		ParameterType matrix = new ParameterTypeMatrix(PARAMETER_MATRIX,
				"Used matrix for filtration.", "filtration_matrix", "row",
				"column", false);
		matrix.registerDependencyCondition(new EqualTypeCondition(this,
				PARAMETER_MATRIX_TYPE, PARAMETER_LIST_MATRIXES, true,
				OWN_MATRIX));
		matrix.setExpert(false);

		p.add(cols);
		p.add(rows);
		p.add(anchX);
		p.add(anchY);
		p.add(listOfMatrixes);
		p.add(fileMatrix);
		p.add(matrix);
		return p;
	}
}
