#ifndef __HELPER_H__
#define __HELPER_H__

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <string>
#define _USE_MATH_DEFINES
#include <math.h>
using namespace std;

inline void assertTrue(bool flg, char* msg)
{
	if (flg) {
		return;
	}
	fprintf(stderr, "[Assert Failed] %s\n", msg);
	exit(-1);
}

inline void fatalError(char* msg)
{
	fprintf(stderr, "[Fatal ERROR] %s\n", msg);
	exit(-1);
}

inline void debug(char* msg)
{
	fprintf(stderr, "%s\n", msg);
}

inline void updateInterval(double &l, double &r, double x)
{
	l = std::min(l, x);
	r = std::max(r, x);
}

inline unsigned myrand()
{
	unsigned ret = rand();
	ret <<= 15;
	ret += rand();
	return ret;
}

struct Entry
{
	int eid;
	double priority;
	Entry(int eid, double priority) : eid(eid), priority(priority) {}
};

inline bool operator < (const Entry &a, const Entry &b)
{
	return a.priority < b.priority;
}

inline int addNew(map<int, int> &h, int x)
{
	if (h.count(x)) {
		return h[x];
	}
	int newid = h.size();
	return h[x] = newid;
}

struct Configuration
{
	// input
	string inFlowFile, outFlowFile, historicalFile; 
	// output
	string blackholePatternFile, volcanoPatternFile, infoFile, timeFile, absFlowFile, resultTimeFile, resultVisitCountFile; 
	// switch
	int useContinuous, useInitialPruning, useInitEdgePickOrdering, 
		useExpansionOrdering, useDynamicUpperBound, useIslandRemoval; 
	
	//threshold
	int flowThreshold;
	double length, areaThreshold; 

	//days, hours
	int day;
	int startPeriod, endPeriod;
	int stride, noPrev, noHis, dump, cross;

	Configuration() {
		useContinuous = 0;
		useInitialPruning = 1;
		useInitEdgePickOrdering = 0;
		useExpansionOrdering = 0;
		useDynamicUpperBound = 1;

		length = areaThreshold = -1;
		flowThreshold = 1000000000;

		useIslandRemoval = 1;
		day = 1;
		startPeriod = 0;
		endPeriod = -1;
		stride = 1;
	}

	bool loadFromFile(const char* filename) {
		FILE* file = fopen(filename, "r");
		if (file == NULL) {
			return false;
		}
		stride = 1; noHis = noPrev = dump = 0; // default
		char name[255], temp[255];
		int occur = 0, total = 0;
		while (fscanf(file, "%s", name) == 1) {
			if (!strcmp(name, "historicalFile")) {
				++ total;
				fscanf(file, "%s", temp);
				historicalFile = temp;
			} else if (!strcmp(name, "inFlowFile")) {
				++ total;
				fscanf(file, "%s", temp);
				inFlowFile = temp;
			} else if (!strcmp(name, "outFlowFile")) {
				++ total;
				fscanf(file, "%s", temp);
				outFlowFile = temp;
			} else if (!strcmp(name, "blackholePatternFile")) {
				++ total;
				fscanf(file, "%s", temp);
				blackholePatternFile = temp;
			} else if (!strcmp(name, "volcanoPatternFile")) {
				++ total;
				fscanf(file, "%s", temp);
				volcanoPatternFile = temp;
			} else if (!strcmp(name, "outputPrefix")) {
				++ total;
				assertTrue(occur == 3, "day, start, end must be defined before outputPath");
				char prefix[255];
				fscanf(file, "%s", prefix);
				sprintf(temp, "%s%d_%d-%d.blackhold", prefix, day, startPeriod, endPeriod);
				blackholePatternFile = temp;
				sprintf(temp, "%s%d_%d-%d.volcano", prefix, day, startPeriod, endPeriod);
				volcanoPatternFile = temp;
				sprintf(temp, "%s%d_%d-%d.info", prefix, day, startPeriod, endPeriod);
				infoFile = temp;
				sprintf(temp, "%s%d_%d-%d.time", prefix, day, startPeriod, endPeriod);
				timeFile = temp;
				sprintf(temp, "%s%d_%d-%d.absFlow", prefix, day, startPeriod, endPeriod);
				absFlowFile = temp;
				sprintf(temp, "%s%d_%d-%d.resultTime", prefix, day, startPeriod, endPeriod);
				resultTimeFile = temp;
				sprintf(temp, "%s%d_%d-%d.resultVisitCount", prefix, day, startPeriod, endPeriod);
				resultVisitCountFile = temp;
			} else if (!strcmp(name, "useContinuous")) {
				++ total;
				fscanf(file, "%d", &useContinuous);
			} else if (!strcmp(name, "useInitialPruning")) {
				++ total;
				fscanf(file, "%d", &useInitialPruning);
			} else if (!strcmp(name, "useInitEdgePickOrdering")) {
				++ total;
				fscanf(file, "%d", &useInitEdgePickOrdering);
			} else if (!strcmp(name, "useExpansionOrdering")) {
				++ total;
				fscanf(file, "%d", &useExpansionOrdering);
			} else if (!strcmp(name, "useDynamicUpperBound")) {
				++ total;
				fscanf(file, "%d", &useDynamicUpperBound);
			} else if (!strcmp(name, "useIslandRemoval")) {
				++ total;
				fscanf(file, "%d", &useIslandRemoval);
			} else if (!strcmp(name, "flowThreshold")) {
				++ total;
				fscanf(file, "%d", &flowThreshold);
			} else if (!strcmp(name, "length")) {
				++ total;
				fscanf(file, "%lf", &length);
				areaThreshold = length / 1000 * length / 1000;
			} else if (!strcmp(name, "day")) {
				++ total;
				++ occur;
				fscanf(file, "%d", &day);
			} else if (!strcmp(name, "startPeriod")) {
				++ total;
				++ occur;
				fscanf(file, "%d", &startPeriod);
			} else if (!strcmp(name, "endPeriod")) {
				++ total;
				++ occur;
				fscanf(file, "%d", &endPeriod);
			} else if (!strcmp(name, "stride")){
				fscanf(file, "%d", &stride);
			} else if (!strcmp(name, "noPrev")) {
				fscanf(file, "%d", &noPrev);
			} else if (!strcmp(name, "noHis")) {
				fscanf(file, "%d", &noHis);
			} else if (!strcmp(name, "dump")) {
				fscanf(file, "%d", &dump);
			} else if (!strcmp(name, "cross")) {
				fscanf(file, "%d", &cross);
			} else {
				fprintf(stderr, "unknown parameters %s\n", name);
			}
		}
		assertTrue(total >= 14, ">= 14 parameters needed!");
		return true;
	}
};


#endif