#include "NetworkReader.h"
/**
 * Constructor
 * @param networkFileName input xml file
 */
NetworkReader::NetworkReader(const char * networkFileName)
{
    ldsIndex = 0;
    loadLines(networkFileName);
}

/**
 * Parses a station xml element into an "LDS_LOOP"
 * 
 * @param stationElem the station xml element
 * @param the parent line
 * @return the new station
 */
LDS_LOOP NetworkReader::parseStation(TiXmlElement *stationElem, FEP_LINE line)
{
    LDS_LOOP station;
    
    TiXmlElement *stationSubElem = stationElem->FirstChildElement();
    cout << "Station id: " << stationSubElem->GetText() << endl;
    station.lds = atol(stationSubElem->GetText());
    line.lds.push_back(station.lds);
    line.ldsIndex.push_back(ldsIndex++);
    stationSubElem = stationSubElem->NextSiblingElement();
    station.line_num = atoi(stationSubElem->GetText());
    stationSubElem = stationSubElem->NextSiblingElement();
    station.drop = atoi(stationSubElem->GetText());
    stationSubElem = stationSubElem->NextSiblingElement();
    stationSubElem = stationSubElem->NextSiblingElement(); // skip location
    stationSubElem = stationSubElem->NextSiblingElement(); // skip postmile
    stationSubElem = stationSubElem->NextSiblingElement(); // skip direction
    stationSubElem = stationSubElem->NextSiblingElement(); // skip freeway
    station.MlTotVol = atoi(stationSubElem->GetText());
    stationSubElem = stationSubElem->NextSiblingElement();
    station.OppTotVol = atoi(stationSubElem->GetText());

    station.pos = 0;
    // Add loops to station
    TiXmlElement *loopsElem = stationSubElem->NextSiblingElement();
    TiXmlElement *loopElem = loopsElem->FirstChildElement(); 
    TiXmlElement *saveLoopElem = loopElem;
    // get number of loops in station and assign to station.num
    station.num = 0;
    for(loopElem; loopElem; loopElem = loopElem->NextSiblingElement())
    {
        station.num += 1;
    }
    
    // get loopIDS and locations
    long int loopIDS[station.num];
    char * loopLocs[station.num];
    int index = 0;
    for(saveLoopElem; saveLoopElem; saveLoopElem = saveLoopElem->NextSiblingElement() )
    {
        TiXmlElement *subLoopElem = saveLoopElem->FirstChildElement();
        loopIDS[index] = atoi(subLoopElem->GetText());
        subLoopElem = subLoopElem->NextSiblingElement();
        loopLocs[index++] = (char *) subLoopElem->GetText();
    }
    station.loopID = loopIDS;
    station.loop_loc = loopLocs;

    // Data pack ATMS message
    station.length = station.num * 2 + CONTROL_DATA_LEN;
    station.dataPack = msgDataPack(station);
    
    return station;
}

/**
 * Parses a "Line" xml element into an FEP_LINE
 * @param lineElem the xml element
 * @return FEP_LINE
 */
FEP_LINE NetworkReader::parseLine(TiXmlElement *lineElem)
{
    FEP_LINE line;
    TiXmlElement *lineSubElem = lineElem->FirstChildElement();
    line.lineNum = atoi(lineSubElem->GetText());
    cout << "Line: " << line.lineNum << endl;
    lineSubElem = lineSubElem->NextSiblingElement();
    line.count = atoi(lineSubElem->GetText());
    lineSubElem = lineSubElem->NextSiblingElement();
    line.schedule = atoi(lineSubElem->GetText());
    lineSubElem = lineSubElem->NextSiblingElement();
    line.lineInfo = atoi(lineSubElem->GetText());
    lineSubElem = lineSubElem->NextSiblingElement();
    line.systemKey = atol(lineSubElem->GetText());
    lineSubElem = lineSubElem->NextSiblingElement();
    line.globalSeq = atol(lineSubElem->GetText());
    lineSubElem = lineSubElem->NextSiblingElement();
    line.schedleSeq = atol(lineSubElem->GetText());

    TiXmlElement *stationsElem = lineSubElem->NextSiblingElement();
    TiXmlElement *stationElem = stationsElem->FirstChildElement();
    for(stationElem; stationElem; stationElem = stationElem->NextSiblingElement())
    {
        stations.push_back(parseStation(stationElem, line));
    }
    return line;
}

/**
 * Loads FEPLines from a specified xml file
 * @param networkFileName the input xml file
 */
void NetworkReader::loadLines(const char * networkFileName)
{
    // Load network xml file
    TiXmlDocument doc(networkFileName);
    if(!doc.LoadFile())
    {
        cerr << "TiXmlDocument did not load network file..." << endl;
        return;
    }

    // grab <Network> element
    TiXmlHandle hDoc(&doc);
    TiXmlElement *networkElem = hDoc.FirstChildElement().Element();

    // grab first <Line> element
    TiXmlElement *lineElem = networkElem->FirstChildElement();

    // iterate through each line element to create FEP_LINE list
    for(lineElem; lineElem; lineElem=lineElem->NextSiblingElement())
    {
        lines.push_back(parseLine(lineElem));
    }
}

// determine if a loop has data based on lane config data
bool NetworkReader::DataAvail(char flag, int num)
{
	int mag, fel;

	// find mask value
	if (num == 1)
		mag = 0x01;
	else if (num == 2)
		mag = 0x02;
	else if (num == 3)
		mag = 0x04;
	else if (num == 4)
		mag = 0x08;
	else if (num == 5)
		mag = 0x10;
	else if (num == 6)
		mag = 0x20;
	else if (num == 7)
		mag = 0x40;
	else if (num == 8)
		mag = 0x80;

	fel = flag & mag;
	fel = fel >> (num - 1);

	if (fel == 1)
		return true;
	else
		return false;
}

// Initializes the LDS_LOOP dataPack with all necessary static data and default dynamic data
unsigned char * NetworkReader::msgDataPack(LDS_LOOP loop)
{
	int j;
	// Allocate memory for dataPack
	unsigned char *dataPack = (unsigned char *) malloc(sizeof(unsigned char) * loop.length);

	// dataPack 5-8: lane config
	char d5 = 0, d6 = 0, d7 = 0, d8 = 0;
	for (j = 0; j < loop.num; j++)
	{
		for (int k = 0; k < 8; k++)
		{
			if (strcmp(loop.loop_loc[j], dp5[k]) == 0)
				d5 += pow(2, k);
			if (strcmp(loop.loop_loc[j], dp6[k]) == 0)
				d6 += pow(2, k);
			if (strcmp(loop.loop_loc[j], dp7[k]) == 0)
				d7 += pow(2, k);
			if (strcmp(loop.loop_loc[j], dp8[k]) == 0)
				d8 += pow(2, k);
		}
	}
	dataPack[5-1] = d5;
	dataPack[6-1] = d6;
	dataPack[7-1] = d7;
	dataPack[8-1] = d8;

	// dataPack 1: Drop number, i.e. station address
	dataPack[1-1] = loop.drop;

	// dataPack2 (2 bytes per loop)
	dataPack[2-1] = loop.num * 2 + Fixed_Byte_To_Checksum;

	// dataPacket 3 (lowbyte: # of mainline loops, highbyte: # of opposite loops)
	int low = 0, high = 0;
	for (j = 1; j <= 6; j++)
	{
		low += DataAvail(dataPack[5-1], j);
		high += DataAvail(dataPack[6-1], j);
	}
	high = high << 4;
	dataPack[3-1] = high | low;

	// dataPack4 (Miscl. flags: samples are: 80, A0, E0, 00)
	dataPack[4-1] = 0xA0;

	// dataPack 9: initialized as 00 (meaning no metering); need to be updated every 30 sec
	dataPack[9-1] = 0;

	// datadataPack 10-13: lane malfunction? Assuming all functional
	dataPack[10-1] = 0;
	dataPack[11-1] = 0;
	dataPack[12-1] = 0;
	dataPack[13-1] = 0;

	// dataPack 14-22: ramp metering data
	// BYTE 16 and 22 need to be updated every 30 sec
	bool found = false;
	for (j = 0; j < loop.num; j++)
	{
		if (strcmp(loop.loop_loc[j], "DEMAND") == 0)
		{
			found = true;
			break;
		}
	}
	if (found)
	{
		// BYTE 14: mostly 07, some are 05, 03, 00
		dataPack[14-1] = 0x07;
		// mostly 06(TOD table 1); some are 0B (No metering) or 05(traffic responsive)
		dataPack[15-1] = 0x06;
		// most 00, some are 01 (queue override) or 80(Meter ON sign)
		dataPack[16-1] = 0x00;
		// Field Manual Rate
		dataPack[17-1] = 0xFF;
		// TOC Manual Rate
		dataPack[18-1] = 0xFF;
		// PSO Manual Rate
		dataPack[19-1] = 0xFF;
		// CORM Rate
		dataPack[20-1] = 0xFF;
		// Local Responsive Rate. DON'T UNDERSTAND YET
		dataPack[21-1] = 0x00;
		// TOD Rate: need to query RAMP plugin!
		dataPack[22-1] = 0x00;
	}
	// LDS: NO Metering
	else
	{
		dataPack[14-1] = 0x00;
		dataPack[15-1] = 0x0B;
		dataPack[16-1] = 0x00;
		dataPack[17-1] = 0xFF;
		dataPack[18-1] = 0xFF;
		dataPack[19-1] = 0xFF;
		dataPack[20-1] = 0xFF;
		dataPack[21-1] = 0x00;
		dataPack[22-1] = 0x00;
	}

	// dataPack 23-24: sum of mainline/Oppsite traffic data; need to be updated every 30 sec
	loop.MlTotVol = 0;
	loop.OppTotVol = 0;
	dataPack[23-1] = loop.MlTotVol;
	dataPack[24-1] = loop.OppTotVol;

	// dataPack 25-26: BYTE 25 is fixed, i.e. 03; BYTE 26 is either 0xA2 or 0x84
	dataPack[25-1] = 0x03;
	dataPack[26-1] = 0x84;

	/* printf("lds=%d (%d), p1=%2X, p2=%2X, p3=%2X, p5=%2X, p6=%X, p7=%X, p8=%2X\n",
		loop.lds, loop.length, dataPack[1-1], dataPack[2-1],
		dataPack[3-1], dataPack[5-1],
		dataPack[6-1], dataPack[7-1], dataPack[8-1]);
    */
	return dataPack;
}

/**
 * Getter for lines
 * @return List of FEP_LINES
 */
vector<FEP_LINE> NetworkReader::getLines()
{
    return lines;
}

/**
 * Getter for stations
 * @return List of LDS_LOOPs
 */
vector<LDS_LOOP> NetworkReader::getStations()
{
    return stations;
}

NetworkReader::~NetworkReader()
{

}
