#include "test.h"
#include "../../pnheaders/pns.h"
#include "../spnbox.h"

int main(int argc, char* argv[])
{	
	FILE* input;
	char IDesc[] = "matrix D, matrix Dm, matrix Dp, indexarray Tuc, indexarray Tuo, matrix L, matrix F, matrix C, arrayi b, arrayi m0, arrayi LB, arrayi UB, matrix H";
	char ODesc[] = "matrix Df, matrix Dfm, matrix Dfp, arrayi mso, string how, matrix Lf, matrix Cf";
	int *IFilled;
	int OFilled[8];
	int Transitions;
	matrix D, Dm, Dp, DDm, DDp, L, L_star, H, F, C, DNew, LD;
	int *b, *CD, *m0, *Tuc, *Tuo, *LB, *UB, *m1, *label0;
	int bnum, m0num, TucCount, TuoCount, LBnum, UBnum;
	pns plant1, plant2;
	linenf_r sol;
	MemoryManager memory;
	int i, j, Constraints;
	expression2 root, node5, node6;
	inequality2 s1, s21, s22, s3, s4;
	variable v1[6], v21[6], v22[6], v3[6], v4[6];
	
	/*Get the input file pointer.*/
	if (! (input = ParseCmdLine(argc,argv)))
	{
		return 0;
	}
	memory = CreateMemoryManager(20, 20, 0, 0);
	
	/*Initialize the petri net output matrix to a zero-by-zero, needed because
	its dimensions are used later without checking to make sure it has been
	initialized. Just to prevent runtime errors. Will suppress the Tuc and Tuo
	output if a problem is given without any incidence matrices.*/	
	while (ParseStructure(input, IDesc, &IFilled, &memory, &D, &Dm, &Dp, &Tuc, &TucCount, &Tuo, &TuoCount, &L, &F, &C, &b, &bnum, &m0, &m0num, &LB, &LBnum, &UB, &UBnum, &H))/*,  ))*/
	{		
		/*Display the problem.*/
		Transitions = IFilled[0] ? NumberOfColumns(D) : (IFilled[1] ? NumberOfColumns(Dm) : 0);
		DisplayStructure(IDesc, IFilled, &D, &Dm, &Dp, Tuc, TucCount, Transitions, Tuo, TuoCount, Transitions, &L, &F, &C, b, bnum, m0, m0num, LB, LBnum, UB, UBnum, &H);
	
		/*Fill in the i/o matrices from the incidence matrix if applicable.*/
		FillDmDp(IFilled, &D, &Dm, &Dp, &memory);

		/*Convert disjunctive constraints to normal constraints, get new D L b m0*/
		label0 = mmalloc(&memory, D.nc * sizeof(int));
		for(j = 0; j < D.nc; j++) {
		  label0[j] = j+1;
		}
		plant1 = createpn("mD m0 label", D, m0, label0);
		
		/*Define a tree as constraints:
		                  root(OR)
			        /    |     \
                             s1 node5(AND) node6(AND)
			        /   \      /   \
			      s3    s21   s4   s22
		  where s1, s21, s22, s3, s4 are inequalities,
		  s21 and s22 are identical.(See test_me_2.m)
		*/
		for(i = 0; i < 6; i++) {
		  if(i < 2) { 
		    v1[i].type = MARKINGV;
		    v1[i].index = i;
		  }
		  else {
		    v1[i].type = FIRINGV;
		    v1[i].index = i - 2;
		  }
		  if(i == 0) v1[i].coefficient = 1;
		  else  v1[i].coefficient = 0;
		  v1[i].pn = &plant1;
		  if(i < 5) v1[i].next = &v1[i+1];
		  else v1[i].next = 0;
		}
		for(i = 0; i < 6; i++) {
		  if(i < 2) { 
		    v21[i].type = MARKINGV;
		    v21[i].index = i;
		  }
		  else {
		    v21[i].type = FIRINGV;
		    v21[i].index = i - 2;
		  }
		  if(i == 3) v21[i].coefficient = 1;
		  else  v21[i].coefficient = 0;
		  v21[i].pn = &plant1;
		  if(i < 5) v21[i].next = &v21[i+1];
		  else v21[i].next = 0;
		}
		for(i = 0; i < 6; i++) {
		  if(i < 2) { 
		    v22[i].type = MARKINGV;
		    v22[i].index = i;
		  }
		  else {
		    v22[i].type = FIRINGV;
		    v22[i].index = i - 2;
		  }
		  if(i == 3) v22[i].coefficient = 1;
		  else  v22[i].coefficient = 0;
		  v22[i].pn = &plant1;
		  if(i < 5) v22[i].next = &v22[i+1];
		  else v22[i].next = 0;
		}
		for(i = 0; i < 6; i++) {
		  if(i < 2) { 
		    v3[i].type = MARKINGV;
		    v3[i].index = i;
		  }
		  else {
		    v3[i].type = FIRINGV;
		    v3[i].index = i - 2;
		  }
		  if(i == 4) v3[i].coefficient = 1;
		  else  v3[i].coefficient = 0;
		  v3[i].pn = &plant1;
		  if(i < 5) v3[i].next = &v3[i+1];
		  else v3[i].next = 0;
		}
		for(i = 0; i < 6; i++) {
		  if(i < 2) { 
		    v4[i].type = MARKINGV;
		    v4[i].index = i;
		  }
		  else {
		    v4[i].type = FIRINGV;
		    v4[i].index = i - 2;
		  }
		  if(i == 1) v4[i].coefficient = 1;
		  else  v4[i].coefficient = 0;
		  v4[i].pn = &plant1;
		  if(i < 5) v4[i].next = &v4[i+1];
		  else v4[i].next = 0;
		}
		s1.free_term = 0;
		s1.lb = 0;
		s1.ub = 3;
		s1.variable_list = v1;
		s21.free_term = 0;
		s21.lb = 0;
		s21.ub = 1;
		s21.variable_list = v21;
		s22.free_term = 0;
		s22.lb = 0;
		s22.ub = 1;
		s22.variable_list = v22;
		s3.free_term = 0;
		s3.lb = 0;
		s3.ub = 1;
		s3.variable_list = v3;
		s4.free_term = 0;
		s4.lb = 0;
		s4.ub = 11;
		s4.variable_list = v4;
		root.type = 1;
		root.n = 3;
		root.leaf = mmalloc(&memory, root.n * sizeof(inequality2*));
		root.successor = mmalloc(&memory, root.n * sizeof(expression2*));
		root.leaf[0] = &s1;
		root.successor[0] = 0;
		root.leaf[1] = 0;
		root.successor[1] = &node5;
		root.leaf[2] = 0;
		root.successor[2] = &node6;
		node5.type = 0;
		node5.n = 2;
		node5.leaf = mmalloc(&memory, node5.n * sizeof(inequality2*));
		node5.successor = mmalloc(&memory, node5.n * sizeof(expression2*));
		node5.leaf[0] = &s3;
		node5.successor[0] = 0;
		node5.leaf[1] = &s21;
		node5.successor[1] = 0;
		node6.type = 0;
		node6.n = 2;
		node6.leaf = mmalloc(&memory, node6.n * sizeof(inequality2*));
		node6.successor = mmalloc(&memory, node6.n * sizeof(expression2*));
		node6.leaf[0] = &s4;
		node6.successor[0] = 0;
		node6.leaf[1] = &s22;
		node6.successor[1] = 0;

		/*Test whether the expression expr is satisfied at the initial marking*/
		plant1.marking[0] = 0;
		plant1.marking[1] = 0;
		int se = satisfied_expr(&root);

		/*Convert tree constraints to normal constraints, get new D L b
		  m0. Since L and b is computed from the tree rather than inputed
		  from the file, we set the mark for b and L manually. The memory
		  address stored in b will be changed in function tree2spec, thus 
		  we are passing by pointer of b.*/
		IFilled[8] = 1;
		IFilled[5] = 1;
		b = mmalloc(&memory, sizeof(int));
		tree2spec(&plant1, &root, "dynamic", &plant2, &L, &b);

		/*Do the constraint enforcement.*/
		sol = linenf(IFilled[1] ? &plant2.out : 0, IFilled[2] ? &plant2.in : 0, IFilled[5] ? &L : 0, IFilled[8] ? b : 0, IFilled[9] ? plant2.marking : 0, IFilled[6] ? &F : 0, IFilled[7] ? &C : 0, IFilled[3] ? TucCount : 0, Tuc, IFilled[4] ? TuoCount : 0, Tuo);
		
		/*Get the list of which output parameters are present for display. Also 
		manage memory. (Defaults to nothing present)*/
		memset(OFilled, 0, sizeof(int) * 8);
		Constraints = 0;
		
		/*If there are no self-loops than optimize display by showing an incidence
		matrix instead of both the input and the output matrices.*/
		if (! HasSelfLoops(&sol.Dfm, &sol.Dfp))
		{
			DNew = SubtractMatrix(&sol.Dfp, &sol.Dfm, (matrix*) 2);
			ManageMatrix(&memory, &DNew);
			OFilled[0] = 1;
		}
		else
		{
			OFilled[1] = 1;
			OFilled[2] = 1;
		}				
		if (sol.ms0)
		{			
			OFilled[3] = 1;
		}
		if (sol.how)
		{
			OFilled[4] = 1;
		}
		if (sol.Lf.type)
		{
			OFilled[5] = 1;
			Constraints = NumberOfRows(sol.Lf);
		}
		if (sol.Cf.type)
		{
			OFilled[6] = 1;
			Constraints = NumberOfRows(sol.Cf);
		}
		if (sol.bf)
		{
			OFilled[7] = 1;
		}
		
		printf("Solution:\n");
		/*Display the result.*/
		DisplayStructure(ODesc, OFilled, &DNew, &sol.Dfm, &sol.Dfp, sol.ms0, NumberOfRows(sol.Dfm), sol.how, &sol.Lf, &sol.Cf);
		/*Display the per-constraint messages that are not OK.*/
		if (sol.dhow)
		{	
			for (i = 0; i < Constraints; i++)
			{
				if (strcmp(HOW_OK, sol.dhow[i]))
				{
					printf("Constraint %d: %s\n", i, sol.dhow[i]);
				}
			}
		}
		printf("---------------------------------------------------------------\n");
		FreeMemory(&memory);
		deallocpn(&plant1);
		DeallocateLinenf(&sol);
		memory = CreateMemoryManager(15, 15, 0, 0);
	}
	FreeMemory(&memory);
	return 0;
}
