#ifndef INC_IMP_TABUSEARCH
#define INC_IMP_TABUSEARCH

#include "TabuSearch.hh"


namespace TabuSearch{

  // Returns a valeu greater than any other
  inline double TS_INFINITY ()
  {
	double one=1.0;
	double zero=0.0;
	return one/zero;
  }


  // Returns an undefined value
  inline double TS_UNDEFINED ()
  {
	double zero=0.0;
	return zero/zero;
  }



  class State {

	public:

		Direction direction;
		int       current_trial;
		int       current_iteration;
		double    current_init_cost;

		Solution  current_solution;
		double    current_cost;
		Solution  current_best_solution;
		double    current_best_cost;
		double    current_worst_cost;

		Solution  global_best_solution;
		double    global_best_cost;
		double    global_worst_cost;
		float     time_spent;
		
		State( const Problem& pbm );
		~State();

		void update( const int trial, const int iteration, const double cicost,
					 const Solution csolution, const double ccost,
                     const float time );

		State& operator= (const State& state);
		friend ostream& operator<< (ostream& os, const State& state);
		friend istream& operator>> (istream& is, State& state);
		friend opacket& operator<< (opacket& op, const State& state);
		friend ipacket& operator>> (ipacket& ip, State& state);
		
  };



  class Statistics {

	public:

		int    total_nb_trials;
		State  last_state;			

		double fraction_of_tabu_moves;
		double improve_wrt_init_sol;
		double improve_wrt_subopt;
		double average_best_cost;
		
		Statistics ( const Problem& pbm );
		~Statistics();

		void reset ();
		void update( const int ntrials, const State& state,
					 const double fraction, const double improve_init,
					 const double improve_subopt, const double avgbcost );

		friend ostream& operator<< (ostream& os, const Statistics& stats);
		friend opacket& operator<< (opacket& op, const Statistics& stats);		
  };



  class Solver {

	protected:

		const Problem&     problem;
		const SetUpParams& params;

		State          state;
		Statistics     statistics;
		UserStatistics userstat;
		TabuStorage    structure;

		int tid;

    public:

		Solver (const Problem& pbm, const SetUpParams& setup);
		virtual ~Solver ();
		virtual void run () =0;

		const State& get_state () const;
		const Statistics& get_statistics () const;

		const Solution& best_solution () const;
		double  best_cost () const;
		double  worst_cost () const;
  };


  class Solver_Seq: public Solver {

	public:

		Solver_Seq (const Problem& pbm, const SetUpParams& setup);
		virtual ~Solver_Seq ();
		void run ();
  };


  class Solver_Lan: public Solver {

	public:

		Solver_Lan (const Problem& pbm, const SetUpParams& setup);
		virtual ~Solver_Lan ();
		void run ();
  };


  class Solver_Wan: public Solver {

	public:

		Solver_Wan (const Problem& pbm, const SetUpParams& setup);
		virtual ~Solver_Wan ();
		void run ();
  };



}


#endif
