#include "Utils.h"

string thread = "none";
string solutionPath = "none";
string instanceName = "none";
int labellingCalls = 0;
double LB_before_final_MIP = -1;
double time_final_MIP = -1;
double gap_final_MIP = -1;
//bool isToPrint = false;
bool isToBranch = true;
//bool isOHnotFound = false;
//bool isCliqueNotFound = false;
//int counter = 0;

clock_t BPC_start;
double tl = -1.0;

extern inline bool isBPC_toStop() {

	clock_t currentTime = clock();
	double time = TIME_CONVERSION * (currentTime - ::BPC_start) / CLOCKS_PER_SEC;
	return (time > tl);

}

extern inline bool strictly_less(double x, double y) {

	bool result = false;
	result = ((y - x) > EPSILON) ? true : false;
	return result;

};

extern inline bool less(double x, double y) {

	bool result = false;
	result = ((y - x) > -EPSILON) ? true : false;
	return result;

};

extern inline bool equal(double x, double y) {

	bool result = false;
	result = (fabs(y - x) <= EPSILON) ? true : false;
	return result;

};

extern inline bool strictly_greater(double x, double y) {

	bool result = false;
	result = ((x - y) > EPSILON) ? true : false;
	return result;

};

extern inline bool greater(double x, double y) {

	bool result = false;
	result = ((x - y) > -EPSILON) ? true : false;
	return result;

};

extern inline double minimum(double x, double y) {

	if ((x - y) > EPSILON)
		return y;
	else
		return x;

};

extern inline double maximum(double x, double y) {

	if ((x - y) > EPSILON)
		return x;
	else
		return y;

};

extern inline double computeFractionalPart(double x) {

	double toFloor = x + ::EPSILON;
	double toCeil = x - ::EPSILON;
	return  min(x - floor(toFloor), ceil(toCeil) - x);

};

extern inline double rounder(double x) {
	
	if (x < 0) {
		double toCeil = x - 0.5;
		return ceil(toCeil);
	}
	double toFloor = x + 0.5;
	return floor(toFloor);

};

extern inline double rounderToNDecimals(double x, unsigned int precision) {

	double pow_10 = pow(10.0f, precision);
	return rounder(x * pow_10) / pow_10;

}

extern inline int randomIntBetween(int _min, int _max, mt19937& generator) {

	int minimum = min(_min, _max);
	int maximum = max(_min, _max);
	uniform_int_distribution<int>  distr(minimum, maximum);

	//return distr(generator);
	return minimum + (rand() % (int)(maximum - minimum + 1));

}

extern inline double pick_probability_randomly(mt19937& generator, double min_probability = 0, double max_probability = 1) {

	return randomIntBetween(static_cast<int>(min_probability * 100), static_cast<int>(max_probability * 100), generator) / 100.0;

}

extern inline void handleException(const string& instance, const string& where, const string& when) {

	string streamName = ::solutionPath + instance + "_EXCEPTIONS_" + ::thread + ".txt";
	ofstream mystream;
	mystream.open(streamName, ios::app);

	clock_t currentTime = clock();
	double currentExecutionTime = TIME_CONVERSION * (currentTime - ::BPC_start) / CLOCKS_PER_SEC;

	try {
		throw;
	}
	catch (const GRBException& e) {

		cerr << "Concert exception caught in " << where << ": " << e.getErrorCode() << " at time " << currentExecutionTime << endl;
		cout << when << endl;
		mystream << "Concert exception caught in " << where << ": " << e.getErrorCode() << " at time " << currentExecutionTime << endl;
		mystream << when << endl;
		mystream.close();
		return;

	}
	catch (const exception& ex) {

		cerr << "C++ exception caught in " << where << ": " << ex.what() << " at time " << currentExecutionTime << endl;
		cout << when << endl;
		mystream << "C++ exception caught in " << where << ": " << ex.what() << " at time " << currentExecutionTime << endl;
		mystream << when << endl;
		mystream.close();
		return;

	}
	catch (...) {

		cerr << "Unknown exception caught in " << where << " at time " << currentExecutionTime << endl;
		cout << when << endl;
		mystream << "Unknown exception caught in " << where << " at time " << currentExecutionTime << endl;
		mystream << when << endl;
		mystream.close();
		return;

	}

};

extern inline void appendToFile(const string& file, const string& content) {

	string streamName = ::solutionPath + file;
	ofstream mystream;
	mystream.open(streamName, ios::app);

	mystream << content;

	mystream.close();

}

extern inline void removeAndWriteFile(const string& file, const string& content) {

	string streamName = ::solutionPath + file;
	ofstream mystream;
	mystream.open(streamName, ios::trunc);

	mystream << content;

	mystream.close();

}