/**
*	\file HalfCycleFormulation.h
*	\brief	Class representing a vertex.
*	\author	Matteo Petris
*	\date	december 2021
*/
#ifndef HALFCYCLEFORMULATION_H
#define HALFCYCLEFORMULATION_H

#include "Instance.h"
#include "Exchange.h"
#include "Label.h"

/**
*	\class Vertex.
*	\brief	Class a vertex in the compatibility graph
*/
class HalfCycleFormulation {

protected:

	const Instance* instance;

	double lowerBound;
	double time;
	double upperBound;
	vector<Exchange> solution;

public:

	//CONSTRUCTORS (default, parametrized, copy)
	HalfCycleFormulation(const Instance* instance);
	HalfCycleFormulation(const HalfCycleFormulation& hcf);

	//DESTRUCTOR
	~HalfCycleFormulation();

	//OPERATORS OVERLOADING (assignment, equality, not equal to)
	HalfCycleFormulation& operator=(const HalfCycleFormulation& hcf);
	friend bool operator==(const HalfCycleFormulation& hcf1, const HalfCycleFormulation& hcf2);
	friend bool operator!=(const HalfCycleFormulation& hcf1, const HalfCycleFormulation& hcf2);

	//METHODS
	vector<Exchange> buildHalfCycles();
	vector<vector<Label>> dynamicProgram(const int& source, const int& maxLength);
	void buildSolveModel();

	void extract_solution_stats(const GRBModel* model, const vector<Exchange>& halfCycles, const  vector<GRBVar>& variables);

	//GET METHODS
	const double& getLowerBound() const;
	const double& getUpperBound() const;
	const double& getTime() const;

	//SET METHODS

	/**
	*	\brief	Converts the vertex into a string containing information related to it.
	*	Useful to have the vertex in an output like a text file or console.
	*	\return converted_vertex : string
	*/
	const string toString() const;

};

class mycallback_hcf : public GRBCallback {
public:
	double& bound;
	double& value;
	int& bab_nodes;
	mycallback_hcf(double& incumbent_value, double& bound, int& bab_nodes) : bound(bound), value(incumbent_value), bab_nodes(bab_nodes) {
	}
protected:
	void callback() {
		try {
			if (where == GRB_CB_MIPNODE) {
				if (getIntInfo(GRB_CB_MIPNODE_STATUS) == GRB_OPTIMAL) {
					this->bound = getDoubleInfo(GRB_CB_MIPNODE_OBJBND);
					this->value = getDoubleInfo(GRB_CB_MIPNODE_OBJBST);
					this->bab_nodes = getDoubleInfo(GRB_CB_MIPNODE_NODCNT);
				}
			}
		}
		catch (GRBException e) {

			cout << "[mycallback_hcf::solve()] - Error code = " << e.getErrorCode() << endl;
			cout << e.getMessage() << endl;
		}
		catch (...) {
			cout << "[mycallback_hcf::solve()] - Error during optimization" << endl;
		}
	}
};

#endif //HALFCYCLEFORMULATION_H