#include "test.h"

int** BuildTD(MemoryManager* memory, int filled[], int* TDVector, int* TDCount, int Transitions);
int* PrepareMsplit(MemoryManager* mem, msplit_r *Data, int Mask[], int* TotalTDCount);
void CleanUpIncidence(MemoryManager* memory, matrix* D, matrix* Dm, matrix* Dp, int* filled);

int main(int argc, char* argv[])
{
	char ProblemFormat[] = "matrix Dm, matrix Dp, matrix D, arrayi mask, matrix M\
	,matrix L0, matrix L, arrayi ipl, arrayi dpl, arrayi TD, arrayi TDCount";
	char SolutionFormat[] = "matrix Dfm, matrix Dfp, matrix Df, matrix Mf, matrix\
	L0f, matrix Lf, arrayi iplf, arrayi TDfVector, arrayi TDfCount";
	matrix Dm, Dp, D, M, L0, L;
	int **TD;
	int *ipl, *dpl, *TDVector, *TDCount, *mask, *filled, *ResultTDVector;
	int OverallTDCount, ipCount, dpCount, dummy, Transitions;
	int ResultMask[9];
	
	MemoryManager memory;
	
	msplit_r Return;
	
	FILE* Input;
	if (! (Input = ParseCmdLine(argc,argv))) return 0;
	
	memory = CreateMemoryManager(10, 10, 0, 0);
	
	while (ParseStructure(Input, ProblemFormat, &filled, &memory, &Dm, &Dp, &D, &mask, &dummy, &M, &L0, &L, &ipl, &ipCount, &dpl, &dpCount, &TDVector, &OverallTDCount, &TDCount, &dummy))
	{
		CleanUpIncidence(&memory, &D, &Dm, &Dp, filled);		
		printf("Problem Summary:\n");
		Transitions = filled[0] ? NumberOfColumns(Dm) : NumberOfColumns(D);
		DisplayStructure(ProblemFormat, filled, &Dm, &Dp, &D, mask, Transitions, &M, &L0, &L, ipl, ipCount, dpl, dpCount, TDVector, OverallTDCount, TDCount, Transitions);
		
		TD = BuildTD(&memory, filled, TDVector, TDCount, Transitions);
		
		Return = msplit(filled[0] || filled[2] ? &Dm : 0, filled[1] || filled[2] ? &Dp : 0, filled[3] ? mask : 0, filled[4] ? &M : 0, filled[5] ? &L0 : 0, filled[6] ? &L : 0, filled[7] ? ipl : 0, ipCount, filled[8] ? dpl : 0, dpCount, TD, TDCount);
		
		ResultTDVector = PrepareMsplit(&memory, &Return, ResultMask, &OverallTDCount);
		
		Transitions = NumberOfColumns(Return.Dfm);
		
		printf("Solution:\n");
		
		DisplayStructure(SolutionFormat, ResultMask, &Return.Dfm, &Return.Dfp, &Return.Df, &Return.Mf, &Return.L0f, &Return.Lf, Return.iplf, Return.ipCountf, ResultTDVector, OverallTDCount, Return.TDfCount, Transitions);
		
		FreeMemory(&memory);
		DeallocateMsplit(&Return);
		memory = CreateMemoryManager(10, 10, 0, 0);
		printf("---------------------------------------------\n");
	}
	printf("Freeing memory...");
	FreeMemory(&memory);
	return 0;
}

int* PrepareMsplit(MemoryManager* mem, msplit_r *Data, int Mask[], int* TotalTDCount)
{
	int i, j, c;
	int* Ret = 0;
	/*Clear the mask initially*/
	memset(Mask, 0, sizeof(int) * 9);
	/*Prepare the display mask while we're at it.*/	
	if (HasSelfLoops(&Data->Dfm, &Data->Dfp))
	{		
		Mask[1] = 1;
		Mask[2] = 1;
	}
	else
	{
		Mask[0] = 1;
	}
	if (NumberOfRows(Data->Mf))
	{
		Mask[3] = 1;
	}
	if (NumberOfRows(Data->L0f))
	{
		Mask[4] = 1;
	}
	if (NumberOfRows(Data->Lf))
	{
		Mask[5] = 1;
	}
	if (Data->iplf)
	{
		Mask[6] = 1;
	}	
	if (Data->TDf)
	{
		Mask[7] = 1;
		Mask[8] = 1;
		/*Count the total size of all the TD vectors combined.*/
		c = 0;
		for (i = 0; i < NumberOfColumns(Data->Dfm); i++)
		{
			c += Data->TDfCount[i];
		}
		Ret = mcalloc(mem, c, sizeof(int));
		*TotalTDCount = c;
		
		c = 0;
		/*Combine all the TD vectors into one vector.*/
		for (i = 0; i < NumberOfColumns(Data->Dfm); i++)
		{
			for (j = 0; j < Data->TDfCount[i]; j++)
			{
				Ret[c++] = Data->TDf[i][j];
			}
		}

	}

	return Ret;
}
	
int** BuildTD(MemoryManager* memory, int filled[], int* TDVector, int* TDCount, int Transitions)
{
	int i, j, c = 0;
	int** TD;
	if (! (filled[9] && filled[10])) return 0;
	
	TD = mcalloc(memory, Transitions, sizeof(int*));
	for (i = 0; i < Transitions; i++)
	{
		TD[i] = mcalloc(memory, TDCount[i], sizeof(int));
		for (j = c; j < c + TDCount[i]; j++)
		{
			TD[i][j-c] = TDVector[j];
		}
		c += TDCount[i];
	}
	return TD;
}

void CleanUpIncidence(MemoryManager* memory, matrix* D, matrix* Dm, matrix* Dp, int* filled)
{
	if (filled[0] && filled[1])
	{
		if (HasSelfLoops(Dm, Dp))
		{
			filled[2] = 0;		
		}
		else
		{
			if (filled[2])
			{
				DeallocateMatrix(D);				
			}
			else
			{				
				ManageMatrix(memory, D);
				filled[2] = 1;
			}
			filled[0] = 0;
			filled[1] = 0;
			(*D) = SubtractMatrix(Dp, Dm, (matrix*) 2);
		}
	}
	else if (filled[2])
	{
		if (filled[0]) DeallocateMatrix(Dm);
		if (filled[1]) DeallocateMatrix(Dp);
		AllocateMatrixType(2, Dm, NumberOfRows(*D), NumberOfColumns(*D));
		AllocateMatrixType(2, Dp, NumberOfRows(*D), NumberOfColumns(*D));
		if (! filled[0])
		{
			ManageMatrix(memory, Dm);			
		}
		if (! filled[1])
		{
			ManageMatrix(memory, Dp);			
		}
		d2dd(D, Dm, Dp);
	}
}
