/*
 * read_dataset.hpp
 *
 *  Created on: 3.5.2011
 *      Author: Pavel Svoboda
 */
#ifndef _READ_DATASET_
#define _READ_DATASET_

#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>

#include "opencv2/opencv.hpp"

#define TIXML_USE_TICPP
#include "XmlParser/ticpp.h"

#include "settings_reader.hpp"

namespace ppd
{

	/**
	 * Object to wrap exception and exception information..	 */
	class Exception
	{
	private:
		std::string reason;
	public:
		/**
		 * Exception with defined information about.
		 * @param reason
		 */
		Exception(std::string reason) :
			reason(reason)
		{
		}

		/**
		 * Set the information - string
		 * @param reason
		 */
		virtual void set(const std::string reason)
		{
			this->reason = reason;
		}

		/**
		 * Get the information about the exception.
		 * @return string with the exception
		 */
		virtual const std::string get(void) const
		{
			return this->reason;
		}
		virtual ~Exception()
		{}
	};

	/**
	 * Infomration about general object of Pascal dataset.
	 */
	class Object
	{
	public:
		Object();
		/**
		 * Constructor.
		 * @param file_name
		 */
		Object(const std::string& file_name);

		/**
		 * Constructor.
		 * @param file_name - image name
		 * @param flag - presence/no-presence of the object
		 */
		Object(const std::string& file_name, const int flag);
		void set_file_name(const std::string& file_name);
		std::string get_file_name() const;
		void set_flag(const int flag);
		int get_flag(void) const;

	private:
		std::string file_name;
		int flag;
	};

	/**
	 * Derived from Object, add the information about the possition of the object in the image.
	 */
	class BoundedObject : public Object
	{
	public:
		BoundedObject(const std::string& file_name, const int flag, const cv::Rect_<int>& bounding_box);
		void set_bounding_box(const cv::Rect_<int>& bounding_box);
		cv::Rect_<int> get_bounding_box() const;
	private:
		cv::Rect_<int> bounding_box;
	};


	/**
	 * Dataset reader. Reads the dataset - list of images aned annotations files, and then parse the annotation files.
	 */
	class DataSetReader
	{
	public:
		DataSetReader( void );
		DataSetReader( const std::string &object_class );

		/**
		 * Set paths to the daset vie Settings reader object
		 * @param settingsReader
		 */
		void set_properties(const SettingsReader& settingsReader);

		/**
		 * Reads the dataset structure and parse the annotation files
		 */
		void initialize();

		/**
		 * Return the ith image of dataset according to used flag.
		 * @param i
		 * @return image
		 */
		cv::Mat operator[](const unsigned int i) const;

		/**
		 * Get the ith image name in the dataset according to the used flag.
		 * @param i
		 * @return
		 */
		std::string get_file_name(const unsigned int i) const;

		/**
		 * Get the ith object of the dataset according to the flag.
		 * @param i
		 * @return pointer to ith object
		 */
		const Object* get(const unsigned int i) const;

		/**
		 * Returns the ith image in the dataset according to the flag.
		 * @param i - index of image
		 * @return image
		 */
		cv::Mat get_image(const unsigned int) const;

		/**
		 * Returns the flag of the ith image (not object!).
		 * @param index
		 * @return the flag
		 */
		int get_image_flag(const unsigned int) const;

		/**
		 * Returns the number of all front objects, ie the objects of specified class.
		 * @return
		 */
		const unsigned int get_number_of_front_objects() const;

		/**
		 * Returns the number of all background objects.
		 * @return
		 */
		unsigned int get_number_of_bg_objects(void) const;

		/**
		 * Retunr the number of all objects in the dataset = foreground + background.
		 * @return
		 */
		unsigned int get_number_of_objects(void) const;

		/**
		 * Get the class (front/background) of ith object according to flag (working with all/front/background objects).
		 * @param i
		 * @return
		 */
		int get_class(const unsigned int i) const;
		//Set if to work with BG or FG examples

		/**
		 * Set the datasereader to work only with foreground objects (of specified class) of dataset.
		 */
		void work_fg(void);

		/**
		 * Set the datasereader to work only with background objects of dataset.
		 */
		void work_bg(void);

		/**
		 * Set the datasetreader to work with all objects in the dataset (forground and background objects also).
		 */
		void work_all(void);
		enum Flag {BG_OBJECTS = 0, FG_OBJECTS = 1, ALL_OBJECTS = 2 };

	//Private attributes - members
	private:
		//Class
		std::string object_class;
		//Names of annotations files
		std::vector<Object> data_list;
		//Names of images where is the specified class
		std::vector<Object> image_list;
		std::vector<unsigned int> bg_index_list;
		//Vector of bounding boxes around potted plant - there could be more than one in the image
		std::vector<cv::Rect_<int> > bounding_boxes;
		//Number of images in DataSet
		unsigned int nImages;
		std::string path_sets;
		std::string data_list_file_name;
		std::string path_annotations;
		std::string path_image;

		std::vector<Object*> objects;

		std::vector<std::vector<int> > dataset_indexes;

		bool read;

		Flag flag;

		//Private Methods
	private:
		void load_data_list( const std::string file_name );
		void read_annotation_file(const std::string &file_name, std::string& image_name, std::vector<cv::Rect_<int> > &bounding_boxes);
		//	Depreciated
	public:

		/**
		 * Set the name of class to work with.
		 * @param object_class
		 */
		void set_class( const std::string &object_class );

		/**
		 * Depracted, use the SettingsReader object to parse settings file.
		 * @param data_list_file_name
		 * @param path_sets
		 * @param path_annotations
		 * @param path_image
		 * @param path_save_image
		 */
		void set_paths( const std::string& data_list_file_name,const std::string &path_sets, const std::string &path_annotations, const std::string &path_image, const std::string &path_save_image);
		~DataSetReader();
	};

}
#endif /* _READ_DATASET_ */
