#include "Intel_Compatibility.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <list>
#include <algorithm>

using namespace std;

struct Reaction {
        unsigned int r1;
        unsigned int r2;
        unsigned int p1;
        unsigned int p2;
        unsigned int numElementsInSDG;
        unsigned int numElementsInDDG;
        float rate;
};

void ProcessReaction(Reaction &r, int z, list<int> &affectedChemicals) {
	if(z == 0)
		return;
	
	int one = 0;
	if(r.r1 == z) one--;
	if(r.r2 == z) one--;
	if(r.p1 == z) one++;
	if(r.p2 == z) one++;

	if(one != 0) {
		for(list<int>::iterator iter = affectedChemicals.begin(); iter != affectedChemicals.end(); iter++)
			if(*iter == z)
				return;

		affectedChemicals.push_back(z);
	}
}

// Compute Affected Chemicals for a Reaction
void ComputeAffectedChemicalsForReaction(Reaction &r, list<int> &affectedChemicals) {
	affectedChemicals.clear();
	ProcessReaction(r, r.r1, affectedChemicals);
	ProcessReaction(r, r.r2, affectedChemicals);
	ProcessReaction(r, r.p1, affectedChemicals);
	ProcessReaction(r, r.p2, affectedChemicals);
}

int main(int argc, char* argv[])
{
	// Argument 1 = Reaction file
	// Argument 2 = Output Singlet Dependency Graph file
	// Argument 3 = Output Doublet Dependency Graph file
	
	ifstream input(argv[1]);

	int numReactions = 0;
	input >> numReactions;

	int *ptrNumReactions = &numReactions;
	cout << "Value of ptrNumReactions is: " << *ptrNumReactions << " and Sizeof an int is: " << sizeof(int*) << std::endl;
	
	vector<Reaction> rxns;
	list< list<int> > SDG;
	list< list<int> > DDG;

	for(int i = 0; i < numReactions; i++) {
		Reaction r;
		input >> r.r1 >> r.r2 >> r.p1 >> r.p2 >> r.rate;
		rxns.push_back(r);
	}

	// Now for each reaction
	// EDIT: We also have to simultaneously output the dependency graph files
	for(int i = 0; i < numReactions; i++) {
		list<int> temp1, temp2;
		SDG.push_back(temp1);
		DDG.push_back(temp2);
		
		// Generate the affected Chemicals list.
		list<int> affectedChemicals;
		ComputeAffectedChemicalsForReaction(rxns[i], affectedChemicals);
		
		rxns[i].numElementsInSDG = rxns[i].numElementsInDDG = 0;
		
		for(int j = 0; j < numReactions; j++) {
			if(std::find(affectedChemicals.begin(), affectedChemicals.end(), (rxns[j].r1)) != affectedChemicals.end() || 
				std::find(affectedChemicals.begin(), affectedChemicals.end(), rxns[j].r2) != affectedChemicals.end()) {
				// Found an affected Reaction
				if(rxns[j].r1 == rxns[j].r2) {
					DDG.back().push_back(j);
					rxns[i].numElementsInDDG += 1;
				} else {
					SDG.back().push_back(j);
					rxns[i].numElementsInSDG += 1;
				}
			}
		}
	}

	cout << "Generated the Parser Dependency Graph Files internally... now outputting!" << std::endl;
	
	// Now output the Dependency Graph Files
	ofstream sdgOutput(argv[2]);
	ofstream ddgOutput(argv[3]);

	for(int i = 0; i < numReactions; i++) {
		sdgOutput << rxns[i].numElementsInSDG << std::endl;
		for(int j = 0; j < rxns[i].numElementsInSDG; j++) {
			sdgOutput << "	" << SDG.front().front() << std::endl;
			SDG.front().pop_front();
		}
		
		SDG.pop_front();
	}

	for(int i = 0; i < numReactions; i++) {
		ddgOutput << rxns[i].numElementsInDDG << std::endl;
		for(int j = 0; j < rxns[i].numElementsInDDG; j++) {
			ddgOutput << "	" << DDG.front().front() << std::endl;
			DDG.front().pop_front();
		}
		
		DDG.pop_front();
	}

	return 0;
}
