#ifndef MODELS_H
#define MODELS_H

#include"data.h"
#include"costfunctions.h"

/*
 * Model
 */

class Model{
	public:
		//Virtual Constructor & Destructor for any model type
		Model();
		Model(const Model&);
		Model(Data);
		virtual ~Model(){delete m_cost;};
		//Link model to data set and cost function
		virtual void setModelData(Data);
		virtual void setExpData(Data);
		virtual void setCost(CostFunction*);
		//Virtual solution, parameters, neighbor solution and cost getter
		virtual Data getSol() const = 0;
		virtual void setParam(std::vector<double>){};
		virtual std::vector<double> getParam() const = 0;
		virtual std::vector<double> getNeighbor(double) const = 0;
		virtual double getCost() = 0;
		//Virtual export model parameters
		virtual void exportModel() const = 0;
		virtual void displayModel() const = 0;
	protected:
		Data m_data;		//Data set containing points obtained using model
		Data exp_data;		//Data set containing experimental points to approximate
		CostFunction* m_cost;	//Pointer to cost function to minimize
};

/*
 * Linear Approximation model
 */

class LinearApprox : public Model{
	public:
		//Virtual Constructor & Destructor for this model
		LinearApprox();
		LinearApprox(const LinearApprox&);
		LinearApprox(Data);
		LinearApprox(Data,std::vector<double>);
		~LinearApprox(){};
		//Set data model, experimental data and cost function
		void setModelData(Data);
		void setExpData(Data);
		void setCost(CostFunction*);
		//Solution, neighbor and cost getter
		Data getSol() const;
		void setParam(std::vector<double>);
		std::vector<double> getParam() const;
		std::vector<double> getNeighbor(double) const;
		double getCost();
		//Export model parameters
		void exportModel() const;
		void displayModel() const;
		//Set and get parameters for this model
		Data getExpData() const;
		void setSlope(double);
		double getSlope() const;
		void setOffset(double);
		double getOffset() const;
	private:
		std::vector<double> param;
};

/*
 * Polynomial Approximation model
 */

class PolynomialApprox : public Model{
	public:
		//Virtual Constructor & Destructor for this model
		PolynomialApprox();
		PolynomialApprox(const PolynomialApprox&);
		PolynomialApprox(int);
		PolynomialApprox(Data,int);
		PolynomialApprox(Data,std::vector<double>);
		~PolynomialApprox(){};
		//Set data model, experimental data and cost function
		void setModelData(Data);
		void setExpData(Data);
		void setCost(CostFunction*);
		//Solution, neighbor and cost getter
		Data getSol() const;
		void setParam(std::vector<double>);
		std::vector<double> getParam() const;
		std::vector<double> getNeighbor(double) const;
		double getCost();
		//Export model parameters
		void exportModel() const;
		void displayModel() const;
		//Set and get parameters for this model
		Data getExpData() const;
	private:
		std::vector<double> param;
};


/*
 * Traveling SalesPerson problem
 */

class TSP : public Model{
	public:
		//Virtual Constructor & Destructor for this model
		TSP();
		TSP(const TSP&);
		TSP(Data);
		TSP(Data,std::vector<int>);
		~TSP(){};
		//Set data model, experimental data and cost function
		void setModelData(Data);
		void setExpData(Data);
		void setCost(CostFunction*);
		//Solution, neighbor and cost getter
		Data getSol() const;
		void setParam(std::vector<double>);
		std::vector<double> getParam() const;
		std::vector<double> getNeighbor(double) const;
		double getCost();
		//Export model parameters
		void exportModel() const;
		void displayModel() const;
		//Set and get parameters for this model
		Data getExpData() const;
		void setOrder(std::vector<int>);
		std::vector<int> getOrder() const;
	private:
		std::vector<int> order;
};


#endif
