#include <iostream>
#include <stdio.h>
#include <ctime>
#include <list>
#include "Graph.h"
#include "makeGrid.h"
#include "VolcanoBlackholeDetection.h"

void loadFlow(char* filename, Graph &g, vector<int> &flow, int numEdge)
{
	double hour;
	int nodef, nodet, segID, inflow, count = 0;
	double f_lat,f_long,t_lat,t_long;
	flow.clear();
	//by default in/out flow of each edge is zero
	flow.assign(numEdge, 0);

	FILE * file = fopen(filename, "r");
	if(file != NULL) {
		while (fscanf(file, "%lf%d%d%d%lf%lf%d%lf%lf", 
				&hour, &segID, &inflow, &nodef, &f_lat, &f_long, &nodet, &t_lat, &t_long) != EOF) {
			assertTrue(segID >= 0 && segID < numEdge, "Edge ID Exceed in inflow file");
			flow[segID]+=inflow;
		}
		fclose(file);
	} else {
		fatalError("flow file not exist!");
	}
}

//this function fills in inflow and outflow of each edge. some edge has zero in,out flow
//this is an online process so I separate it from readGraph()
void UpdateFlow(char* inflowFileName, char* outflowFileName, Graph& g, vector<int>& inFlow, vector<int>& outFlow, int numEdge)
{
	debug("Updating In Flow...");
	loadFlow(inflowFileName, g, inFlow, numEdge);

	debug("Updating Out Flow...");
	loadFlow(outflowFileName, g, outFlow, numEdge);

	debug("Flow Updated!");
}

//read vertices and edges
//flows are not inserted. flows are updated using UpdateFlow()
//vertices and edges are added to Graph g
int readGraph(const char* RdNetworkFileName, Graph &g)
{
	debug("reading graph...");

	FILE* pFile;
	pFile = fopen(RdNetworkFileName, "r");

	assertTrue(pFile != NULL, "Rd Network file not exsit!");

	int numNode = 0, numEdge = 0, Nodef = 0, Nodet = 0, direction = 0;
	double minLat = INT_MAX, minLong = INT_MAX, maxLat = 0, maxLong = 0;
	
	//read vertices
	assertTrue(fscanf(pFile, "%d", &numNode) == 1, "# of vertices needed!");
	fprintf(stderr, "numNode = %d\n", numNode);

	double _lat, _long;
	int NodeID;
	for(int i = 0; i < numNode; ++ i) {
		fscanf (pFile, "%d%lf%lf", &NodeID, &_lat, &_long);

		g.InsertVertex(NodeID,_lat,_long);

		updateInterval(minLat, maxLat, _lat);
		updateInterval(minLong, maxLong, _long);
	}
	fprintf(stderr, "domain area = %0.16f\n", (maxLat - minLat) * (maxLong - minLong));

	//read edges
	assertTrue(fscanf_s (pFile, "%d", &numEdge) == 1, "# of edges needed!");
	fprintf(stderr, "numEdge = %d\n",numEdge);

	for(int i = 0; i < numEdge; ++ i) {
		fscanf_s(pFile, "%d%d%d\n", &Nodef, &Nodet, &direction);
		g.InsertEdge(i, Nodef, Nodet, 0, 0, direction);
	}
	fclose(pFile);

	return numEdge;
}

int main(int argc, char* argv[])
{
	if (argc < 3) {
		fprintf(stderr, "[usage] <RoadNetworkFile> <config_1> <config_2> ... <config_k>");
		return -1;
	}
	double maxLat = 0, maxLong = 0, minLat = INT_MAX, minLong = INT_MAX;
	const double domainArea = 2507.388763;
	Graph g;
	vector<int> inFlow, outFlow;
	int totalVisitCount = 0;
	double startTime, endTime, totalTime = 0;//*** timer

	//Grid[xx][xx] contains all vertices and edges that overlap the grid cell
	//structure of gridCell in makeGrid.h
	vector<vector<gridCell>> Grid;//grid 

#define RoadNetworkFile argv[1]

	const int numEdge = readGraph(RoadNetworkFile, g);

	//read graph from file
	int totalBlackhole = 0, totalVolcano = 0;
	int continuousBlackhole = 0, continuousVolcano = 0;
	for(int k = 1; k < argc - 1; ++ k) {
		Configuration config;
		if (!config.loadFromFile(argv[k + 1])) {
			fprintf(stderr, "%d-th config file %s does not exsit! skipped\n", k, argv[k + 1]);
			continue;
		}
		fprintf(stderr, "areaThreshold=%.6f\n", config.areaThreshold);

		if((config.useInitialPruning == 1 || config.useDynamicUpperBound==1) && (Grid.size() == 0)) {
			//make a grid
			//assume grid cell area=areaThreshold
			makeGrid(RoadNetworkFile, Grid, g, config.areaThreshold, maxLat, maxLong, minLat, minLong); //separate nodes and edges into grid cells
		}

		vector<vector<int>> prevBlackholes, prevVolcanos;
		totalTime=0;
		totalVisitCount=0;
		//Nov 2012, 25 days*48 half hour
		int i = config.day;
		for(int j = config.startPeriod; j + config.stride - 1 <= config.endPeriod; j += config.stride) {

			inFlow.assign(numEdge, 0); outFlow.assign(numEdge, 0);
			for (int iter = 0; iter < config.stride; ++ iter) {
				//update inflow and out flow
				char tempIn[255], tempOut[255];
				sprintf(tempIn, "%s%d_%d.txt", config.inFlowFile.c_str(), i, j + iter);
				sprintf(tempOut, "%s%d_%d.txt", config.outFlowFile.c_str(), i, j + iter);

				startTime = time(NULL);//*** timer
				UpdateFlow(tempIn,tempOut,g,inFlow,outFlow,numEdge);
				endTime = time(NULL);//*** timer
				std::cout << "day " << i << " Period " << j <<  " Update Flow time: " << endTime - startTime << " seconds.\n";//*** timer
			}

			startTime = clock();//*** timer
			int cb, cv;
			int visitCount=VolcanoBlackholeDetection(g,inFlow,outFlow, config, numEdge, Grid,
													 maxLat, maxLong, minLat, minLong, prevBlackholes, prevVolcanos, k, i, j, cb, cv);
			endTime = clock();//*** timer
			totalVisitCount += visitCount;

			cout << "day " << i << " Period " << j << " stride = " << config.stride << " Runtime: " << (endTime - startTime) / CLOCKS_PER_SEC << " seconds.\n";//*** timer
			cout << "edge visit = " << visitCount << endl << endl;
			cout << "# blackhole = " << prevBlackholes.size() << endl;
			cout << "# volcanos = " << prevVolcanos.size() << endl;
			cout << endl;

			totalTime += (endTime - startTime) / CLOCKS_PER_SEC;

			totalBlackhole += prevBlackholes.size();
			totalVolcano += prevVolcanos.size();
			continuousBlackhole += cb;
			continuousVolcano += cv;
		}
		FILE * pFile_time=fopen(config.resultTimeFile.c_str(), "a");
		FILE * pFile_visitCount=fopen(config.resultVisitCountFile.c_str(), "a");
		fprintf(pFile_time,"%lf\n",totalTime);
		fprintf(pFile_visitCount,"%d\n",totalVisitCount);
		fclose(pFile_time);
		fclose(pFile_visitCount);

		cout << "[Attention!] total visit count = " << totalVisitCount << endl;
	}
#undef RoadNetworkFile

	printf("blackholes %d/%d = %.6f\n", continuousBlackhole, totalBlackhole, (double)continuousBlackhole / totalBlackhole);
	printf("volcanos %d/%d = %.6f\n", continuousVolcano, totalVolcano, (double)continuousVolcano / totalVolcano);
	fprintf(stderr, "finished!");
	//std::system("PAUSE");

	return 0;
}
