/*****************************************************************//**
 * \file   Instance.h
 * \brief	Represents the studied data.
 * 
 * \author Matteo Petris
 * \date   February 2023
 *********************************************************************/
#ifndef INSTANCE_H
#define INSTANCE_H

#include "Vertex.h"
#include "Utils.h"



/**
*	\class Instance.
*	\brief	Represents the studied data.
*/
class Instance {

protected:

	string path;
	string name;
	bool isMedicalBenefit;

	int cyclesLength;											/**< The maximum length of the exchange cycles*/
	int	chainsLength;											/**< The maximum length of the exchange chains*/
	int	altruisticDonorsNumber;									/**< Number of altruistic donors*/
	int	incompatiblePairsNumber;								/**< Number of incompatible pairs*/
	vector<vector<int>> compatibleMatrix;						/**< it includes the dummy vertex*/
	vector<vector<int>> FloydWarshallMatrix;					/**< it includes the dummy vertex*/
	int dummyNodeId;											/**< id of the dummy node (required in the pricing graph)*/
	vector<Vertex> vertices;									/**< Vector of vertices in the compatible graph (dummy node included)*/
	vector<int> altruisticDonors;								/**< Vector containing the positions in vertices of the altruistic donors*/
	vector<int> incompatiblePairs;								/**< Vector containing the positions in vertices of the incompatible pairs*/
	int wordsNumber;											/**< Number of words required to encode the vertices with bits*/
	vector<unordered_map<int, int>> bitDictionary;				/**< in each word, key = bitKey, value = id*/
	unordered_map<int, int> IKEPdictionary;						/**< key = vertex id in KEP, value = vertex id in IKEP*/
	unordered_map<int, int> IKEPperiodDictionary;				/**< key = vertex id in KEP, value = vertex id in IKEP*/

	int exchangesPerVertexInitialisation;
	vector<int> pairsToProcess;
	vector<unordered_set<int>> nodesPerPairToProcess;
	vector<vector<vector<int>>> arcsPerPairToProcess;

	double timeFloydWarshall;
	double timeOmerPreprocessing;
	int removedArcsFW;
	int removedNodesFW;
	int pairGraphsOP;
	double avgNodesGraphsOP;
	double avgArcsGraphsOP;

public:

	//CONSTRUCTORS (default, parametrized, copy)
	Instance(const string& path, const string& name, const bool& isMedicalBenefit);
	Instance(const Instance& i);

	//DESTRUCTOR
	~Instance();

	//OPERATORS OVERLOADING (assignment, equality, not equal to)
	Instance& operator=(const Instance& i);
	friend bool operator==(const Instance& i1, const Instance& i2);
	friend bool operator!=(const Instance& i1, const Instance& i2);

	//METHODS
	void processData(const int& ngSetSize);
	void read();
	vector<vector<int>> preprocessingFloydWarshall();
	vector<vector<int>> detectArcsToRemove(const vector<vector<int>>& distances);
	vector<int> detectIsolatedVertices(const vector<vector<int>>& arcsToRemove);
	void buildVertices(const vector<vector<int>>& distances, const vector<vector<int>>& arcsToRemove, const vector<int>& isolatedVertices, const int& ngSetSize);
	void addExtendedPredecessors(const unordered_map<int, int>& mapIds, const vector<vector<int>>& distances);
	//bool can_j_be_in_an_exchange_after_i(const int& i, const int& j) const;
	void preprocessingOmer(const unordered_map<int, int>& mapIds);
	vector<int> BellmanFordPreprocessing_forward(const vector<vector<int>>& availableArcs, const int& source);
	vector<int> BellmanFordPreprocessing_backward(const vector<vector<int>>& availableArcs, const int& sink);
	vector<int> BreadthFirstSearchPreprocessing_forward(const vector<vector<int>>& availableArcs, const int& source);
	vector<int> BreadthFirstSearchPreprocessing_backward(const vector<vector<int>>& availableArcs, const int& sink);

	//GET METHODS
	const int& getCyclesLength() const;
	const int& getChainsLength() const;
	//const vector<vector<int>>& getCompatibleMatrix() const;
	//const vector<vector<int>>& getFloydWarshallMatrix() const;
	const int& getAltruisticDonorsNumber() const;
	const int& getIncompatiblePairsNumber() const;
	const int& getVertexNumber() const;
	const int& getDummyNodeId() const;
	const vector<Vertex>& getVertices() const;
	const vector<int>& getAltruisticDonors() const;
	const vector<int>& getIncompatiblePairs() const;
	const int& getWordsNumber() const;
	const int& getExchangesPerVertexInitialisation() const;
	const vector<int>& getPairsToProcess() const;
	const vector<vector<vector<int>>>& getArcsPerPairToProcess() const;
	const vector<unordered_set<int>>& getNodesPerPairToProcess() const;
	const double& getTimeFloydWarshall() const;
	const double& getTimeOmerPreprocessing() const;
	const int& getRemovedArcsFW() const;
	const int& getRemovedNodesFW() const;
	const int& getPairGraphsOP() const;
	const double& getAvgNodesGraphsOP() const;
	const double& getAvgArcsGraphsOP() const;
	const unordered_map<int, int>& getIKEPdictionary() const;
	const unordered_map<int, int>& getIKEPperiodDictionary() const;
	const int& get_shortest_path_FW(const int& origin, const int& destination) const;

	void resetNgSet(const int& ngSetSize);

	void set_exchangesPerVertexInitialisation(const int& n);

	const string toString(const bool& areArcsPrinted) const;
	void print(const string& filename) const;
	void print_PrefLib_format() const;

};

#endif //INSTANCE_H