#ifndef __MAKE_GRID__
#define __MAKE_GRID__

#include "makeGrid.h"
//#include "Graph.h"

using namespace std;

/*	The code of GeoDistance function:
Input: Two coordination {Latitude1, Longitude1, Latitude2, Longitude2 } (type:double)
Output: Distance(Unit: m) (type:double)
*/

double Rad(double d)
{
	return d * M_PI / 180.0;
}

double Geodist(double lat1, double lon1, double lat2, double lon2)
{
	double radLat1 = Rad(lat1);
    double radLat2 = Rad(lat2);
    double delta_lon = Rad(lon2 - lon1);
    double top_1 = cos(radLat2) * sin(delta_lon);
    double top_2 = cos(radLat1) * sin(radLat2) - sin(radLat1) * cos(radLat2) * cos(delta_lon);
    double top = sqrt(top_1 * top_1 + top_2 * top_2);
    double bottom = sin(radLat1) * sin(radLat2) + cos(radLat1) * cos(radLat2) * cos(delta_lon);
    double delta_sigma = atan2(top, bottom);
    double distance = delta_sigma * 6378137.0;
    return distance;
}

void initializeGridCell(vector<vector<gridCell>>& GC,int NumGridCellrow,int NumGridCellcol)
{
	vector<gridCell> row;
	gridCell cell;
	row.assign(NumGridCellcol, cell);
	GC.assign(NumGridCellrow, row);
}

int findDomainSizeAndInsertNodes(FILE * pFile, double& maxLat, double& maxLong, double& minLat, double& minLong, int numNode, map<int,vertex>& Nodes, Graph& g, double areaThreshold)
{
	debug("finding domain size and insert nodes");

	fscanf_s(pFile, "%d", &numNode);
	fprintf(stderr, "numNode=%d\n", numNode);

	float _lat, _long;
	int NodeID;
	for(int i = 0; i < numNode; ++ i) {
		fscanf_s (pFile, "%d%f%f", &NodeID,&_lat,&_long);

		vertex n;
		n.la=_lat;
		n.lo=_long;
		Nodes[NodeID]=n;

		updateInterval(minLat, maxLat, _lat);
		updateInterval(minLong, maxLong, _long);
	}
	double length = Geodist(maxLat, maxLong, maxLat, minLong) / 1000.0;
	double area = length * length;
	fprintf(stderr, "area = %lf areaThreshold = %lf \n", area, areaThreshold);
	int numberOfCell = area / areaThreshold;

	debug("find domain size and insert nodes finish!");
	return numberOfCell;
}

void putNodesIntoGridCell(const GridCellDistributor &gridCellDistributor, map<int,vertex>& Nodes, vector<vector<gridCell>>& GC)
{
	debug("putting nodes into grid cells...");
	int i, j;
	map<int,vertex>::const_iterator itr;
	for(itr = Nodes.begin(); itr != Nodes.end(); ++ itr) {
		gridCellDistributor.findGridCell(i, j, itr->second.la, itr->second.lo);
		GC[i][j]._Node[(*itr).first] = 1;
	}
	debug("put nodes into grid cells finished!");
}

void putEdgesIntoGridCell(FILE *pFile, const GridCellDistributor &gridCellDistributor, map<int,vertex>& Nodes, vector<vector<gridCell>>& GC, int numEdge)
{
	debug("putting edges into grid cells...");
	fscanf_s (pFile, "%d", &numEdge);
	fprintf(stderr, "numEdge = %d\n",numEdge);

	int Nodef, Nodet, i_f, j_f, i_t, j_t;

	for(int i = 0; i < numEdge; ++ i) {
		fscanf_s(pFile, "%d%d\n", &Nodef,&Nodet);

		gridCellDistributor.findGridCell(i_f, j_f, Nodes[Nodef].la, Nodes[Nodef].lo);
		gridCellDistributor.findGridCell(i_t, j_t, Nodes[Nodet].la, Nodes[Nodet].lo);

		if(i_f == i_t && j_f == j_t) {//the edge does NOT cross grid cell
			GC[i_f][j_f]._Edge[i] = 1;
		} else {//the edge cross grid cell
			GC[i_f][j_f]._Edge[i] = 1;
			GC[i_t][j_t]._Edge[i] = 1;
		}
	}
	debug("put edges into grid cells finish!");
}

void makeGrid(char* RdNetworkFileName,vector<vector<gridCell>>& GC,Graph& g,double areaThreshold,double& maxLat,double& maxLong,double& minLat,double& minLong)
{
	debug("Making Grid...");

	char str [100];
	
	int numNode = 0, numEdge = 0;
	FILE * pFile;
	map<int,vertex> Nodes;

	fopen_s(&pFile,RdNetworkFileName,"r");

	int numberOfGridCell = findDomainSizeAndInsertNodes(pFile, maxLat, maxLong, minLat, minLong, numNode, Nodes, g, areaThreshold);
	int row = sqrt(numberOfGridCell) + 1, col = sqrt(numberOfGridCell) + 1;
	fprintf(stderr, "numberOfGridCell=%d (%d X %d) grid\n", numberOfGridCell, row, col);

	GridCellDistributor gridCellDistributor(minLat, maxLat, minLong, maxLong, row, col);

	initializeGridCell(GC, row, col);

	putNodesIntoGridCell(gridCellDistributor, Nodes, GC);

	putEdgesIntoGridCell(pFile, gridCellDistributor, Nodes, GC, numEdge);
	
	fclose (pFile);

	debug("Make Grid finish!");
}

#endif
