// PlaFile.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include "BuddyPlaLoad.h"
#include "PlaFile.h"
#include <malloc.h>

#define ROWCOUNT 1000
enum state{
	start, param, iCount, oCount, pCount, matrix, skip, comment, end
};

int AllocateMatrixs(PlaData *data)
{	
	if(data->p <= 0 && data->allocated <= 0) {
		data->allocated = ROWCOUNT;
		data->p = 0;
		data->iArray = (int **)malloc(data->allocated*sizeof(int));	
		data->oArray = (int **)malloc(data->allocated*sizeof(int));
	}
	else if(data->allocated > 0){
		int **newArrayI = (int **)malloc(data->allocated*sizeof(int)*2);
		int **newArrayO = (int **)malloc(data->allocated*sizeof(int)*2);
		for (int i=0;i<data->allocated;i++){
			newArrayI[i]=data->iArray[i];
			newArrayO[i]=data->oArray[i];
		}
		free(data->iArray);
		free(data->oArray);
		data->iArray = newArrayI;
		data->oArray = newArrayO;
		data->allocated = data->allocated*2;
	}
	else if(data->allocated<=0 && data->p>0){ 
		data->iArray = (int **)malloc(data->p*sizeof(int));	
		data->oArray = (int **)malloc(data->p*sizeof(int));
		for(int i=0;i<data->p;i++){
			data->iArray[i] = (int*)malloc(data->i*sizeof(int));
			data->oArray[i] = (int*)malloc(data->o*sizeof(int));
			if(data->oArray[i] == NULL){
				printf("chyba alokace");
				return false;
			}
		}		
	}
	return true;
}

void PlaFree(PlaData *data){
	if(data->i > 0 && data->o> 0){
		for(int i= 0;i<data->i;i++){
			free(data->iArray[i]);			
		}
		for(i= 0;i<data->o;i++){
			free(data->oArray[i]);			
		}
		free(data->iArray);
		free(data->oArray);
	}
}

bool PlaOpen(char *path, PlaData *result)
{
	char c;
	char comment[50];
	FILE *f = fopen(path, "r");
	int state = 0;
	int lineLength;
	unsigned long matrixCount;	
	result->i = 0;
	result->o = 0;
	result->p = 0;
	result->iArray = NULL;
	result->oArray = NULL;
	result->allocated = 0;
	while (c != EOF){
		c = fgetc(f);
		switch(c){
			case ' ':
			case '\n':
			case '\r':
			case '\t':
			continue;
			case '#': 
				fscanf(f, "%s", &comment);				
			continue;			
		}
		switch(state){
				case start: 				
				switch (c){				
					case '.':
						state = param;
						break;				
					case '#':
						fscanf(f, "%s", &comment);
						break;
					case '0':
					case '1':
					case '-':				
						if(result->i <=0 && result->o <=0) {
							fclose(f);
							PlaFree(result);
							return false;
						}
						state = matrix;
						matrixCount = 0;
						lineLength = result->i + result->o;
						ungetc(c, f);
						if(!AllocateMatrixs(result)) {
							return false;	
						}
						break;
					default:
						fclose(f);
						PlaFree(result);
						return false;
				}
				break;
			case param:
				switch(c){
					case 'i':
						if(result->i == 0){
							state = iCount;
						}
						else {
							fclose(f);
							PlaFree(result);
							return false;
						}
					break;
					case 'o':
						if(result->o == 0){
							state = oCount;
						}
						else {
							fclose(f);
							PlaFree(result);
							return false;
						}
					break;
					case 'p':
						if(result->p == 0){
							state = pCount;
						}
						else {
							fclose(f);
							PlaFree(result);
							return false;
						}
					break;
					default:
						state = skip;
					break;
				}
				break;
			case iCount:
				while(c>='0' && c <='9'){
					result->i = result->i*10 + (c-'0');
					c = getc(f);
				}
				if(result->i == 0) {
					fclose(f);
					PlaFree(result);
					return false;
				}
				else state = start;
				ungetc(c, f);
			break;
			case oCount:
				while(c>='0' && c <='9'){
					result->o = result->o*10 + (c-'0');
					c = getc(f);
				}
				if(result->o == 0){
					fclose(f);
					PlaFree(result);
					return false;
				}
				else state = start;
				ungetc(c, f);
			break;
			case pCount:
				while(c>='0' && c <='9'){
					result->p = result->p*10 + (c-'0');
					c = getc(f);
				}
				if(result->p == 0) {
					fclose(f);
					PlaFree(result);
					return false;
				}
				else state = start;
				ungetc(c, f);
			break;			
			case matrix:
				switch(c){
				case '0':
				case '1':					
				case '-':										
					//pokud nezname p
					if(result->allocated>0 && matrixCount % lineLength == 0){						
							if(result->allocated<= result->p){
								AllocateMatrixs(result);
							}
						result->iArray[result->p] = (int*)malloc(result->i*sizeof(int));
						result->oArray[result->p] = (int*)malloc(result->o*sizeof(int));
						result->p++;
					}					
					if((matrixCount % lineLength) < result->i) 						
						result->iArray[matrixCount / lineLength][matrixCount % lineLength]= (unsigned short)(c == '-') ? c-'-'+2 : c-'0';
					else result->oArray[matrixCount / lineLength] [matrixCount % lineLength - result->i]= (unsigned short)(c == '-') ? c-'-'+2 : c-'0';
					matrixCount++;					
					break;
				}			
			break;
			case skip:
				while (c!='\n') {
					if (c==EOF) {printf("Nelezen konec souboru, ocekavana vsak byla jeste data!"); return false;}
					c=fgetc(f);
				}
				state = start;
				break;
			case end:
				if(c == '->'){
					c = getc(f);
					if(c == 'e') {
						fclose(f);			
						return true;
					}

				}
			return false;
			break;
		}
	}
	fclose(f);	
	return true;
}