/*
 * classifier_trainer.hpp
 *
 *  Created on: 16.11.2011
 *      Author: isvoboda
 */

#ifndef CLASSIFIER_TRAINER_HPP_
#define CLASSIFIER_TRAINER_HPP_

#include "read_dataset.hpp"
#include "settings_reader.hpp"
#include "bow.hpp"
#include "opencv2/opencv.hpp"
#include "svm.h"
namespace ppd
{

//void ExtractBowFeature(DataSetReader* const reader, const std::string& file_name_words_storage, const std::string file_name_bow_feature_storage);

//void TrainSVM(const CvSVMParams& svm_params, const std::string& file_name_bow_feature_storage, const std::string& file_name_bg_bow_feature_storage, const std::string& classifier_file_name, const std::string& classifier_name);

//void ShuffleIndexes(const unsigned int size, cv::Mat& output);

//void ShuffleMat(const cv::Mat& indexes, cv::Mat& input);

/**
 * Function reads the BOW features stored in OpenCv xml file as matrix
 * @param file_name
 * @param name - internal name(tag) in the xml file
 * @param bow_features - read BOW
 */
void ReadBOW_features(const std::string& file_name, const std::string& name, cv::Mat& bow_features);

/**
 * Scaler transform the input data according to the scaling parameters, ie. distributes the values in the defined range by lower and upper constants.
 */
class Scaler
{
	public:
	Scaler();

	void read_scale_parameters(const std::string& file_name, float& lower, float& upper, std::vector<float>& min_feature, std::vector<float>& max_feature) const;
	void read_scale_parameters(const std::string& file_name);

	void save_scale_parameters(const std::string& file_name, const float lower, const float upper, const std::vector<float>& min_feature, const std::vector<float>& max_feature) const ;
	void save_scale_parameters(const std::string& file_name) const ;


	void scale(const cv::Mat& input, cv::Mat& output, const float lower, const float upper, const std::vector<float>& min_feature, const std::vector<float>& max_feature) const;
	void scale(const cv::Mat& input, cv::Mat& output) const;

	void find_min_max_feature(const cv::Mat& input, std::vector<float>& min_feature, std::vector<float>& max_feature) const;
	void find_min_max_feature(const cv::Mat& input);

	private:
	float _lower;
	float _upper;
	std::vector<float> _min_f;
	std::vector<float> _max_f;
};

/**
 * The SVM classifier
 */
class SVM
{
public:

	/**
	 * NonParametric constructor.
	 */
	SVM(void);

	/**
	 * SVM constructor
	 * @param file_name file name of the stored SVM
	 * @param name internal SVM name in the XML structure
	 */
	SVM(const std::string& file_name, const std::string& name);

	/**
	 * Train the SVM, it randomly shuffle the features and the same way also the Labels, it means the label is on the same index as its feature in the end.
	 * @param features
	 * @param labels
	 */
	void train(cv::Mat& features, cv::Mat& labels);

	/**
	 * Predict the class of the feature
	 * @param feature input feature
	 * @return the class-label
	 */
	float predict(const cv::Mat& feature) const;

	float predict_probability(const cv::Mat& feature, std::vector<float>& probabilities) const;

	/**
	 * Sets the default parameters for SVM training - The type of SVM C-SVM and the Type of kernel (RBF)
	 */
	void set_params(void);

	/**
	 * Sets training parameters of SVM
	 * @param c_grid - the interval of parameter C to try (as the Bias)
	 * @param gamma_grid - the interval of parameter gamma to try (for RBF kernel)
	 */
	void set_train_params(const CvParamGrid& c_grid, const CvParamGrid& gamma_grid);

	/**
	 * Sets the classifier name
	 * @param file_name
	 * @param name - in the xml structure
	 */
	void set_classifier_name(const std::string& file_name, const std::string& name);

	/**
	 * Loads classifier defined by name set by constructor.
	 */
	void load_classifier();

	/**
	 * Loads the SVM model
	 * @param file_name
	 * @param name
	 */
	void load_model(const std::string file_name);

	/**
	 * Loads the classifier.
	 * @param file_name
	 * @param name
	 */
	void load_classifier(const std::string& file_name, const std::string& name);
//	~SVM();
//Attributes
private:
	CvSVM classifier;
	cv::SVMParams params;
	std::string classifier_file_name;
	std::string classifier_name;
	CvParamGrid c_grid;
	CvParamGrid gamma_grid;
	svm_model *model;
//Methods
private:
	void ShuffleIndexes(const unsigned int size, cv::Mat& output) const;
	void ShuffleMat(const cv::Mat& indexes, cv::Mat& input) const;

	struct svm_node* libsvm_format(const cv::Mat& feature) const;

};

}
#endif /* CLASSIFIER_TRAINER_HPP_ */
