#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pspiofilemgr.h>
#include <pspctrl.h>

#include "conf.h"

//#define isvalidvarchar(c) (isalnum(c) || c == '_' || c == '=') 

#define isvalidvarchar(c) (c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e' || c == 'f' \
 || c == 'g' || c == 'h' || c == 'i' || c == 'j' || c == 'k' || c == 'l' || c == 'm' || c == 'n' || c == 'o' \
 || c == 'p' || c == 'q' || c == 'r' || c == 's' || c == 't' || c == 'u' || c == 'v' || c == 'w' || c == 'x' \
 || c == 'y' || c == 'z' || c == 'A' || c == 'B' || c == 'C' || c == 'D' || c == 'E' || c == 'F' \
 || c == 'G' || c == 'H' || c == 'I' || c == 'J' || c == 'K' || c == 'L' || c == 'M' || c == 'N' || c == 'O' \
 || c == 'P' || c == 'Q' || c == 'R' || c == 'S' || c == 'T' || c == 'U' || c == 'V' || c == 'W' || c == 'X' \
 || c == 'Y' || c == 'Z' || c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' \
 || c == '7' || c == '8' || c == '9' || c == '_' || c == '=')


static int read_line(SceUID fd, char *line, int max)
{
	int i, read;
	char ch;

	i = 0;

	if (max == 0)
		return 1;

	do
	{
		read = sceIoRead(fd, &ch, 1);
		
		if (read && ch != '\n' && ch != '\r')
			line[i++] = ch;		

	} while (ch != '\n' && read == 1 && i < max);

	line[i] = 0;

	return !read;
}

static int get_tokens(char tokens[][128], int maxtokens, char *line)
{
	int iline = 0;
	int itoken = 0;
	int jtoken = 0;
	int intoken = 0;
	int instring = 0;
	char ch;

	while (itoken < maxtokens)
	{
		ch = line[iline++];

		if (ch == 0)
		{
			if (instring)
				return 0; // Error: not terminated string

			if (intoken)			
				tokens[itoken++][jtoken] = 0;

			break;
		}

		if (!instring && (ch == '#' || ch == ';'))
		{
			if (intoken)			
				tokens[itoken++][jtoken] = 0;

			break;
		}

		//if (isspace(ch) || ch == '=')
		if(ch == ' ' || ch == '=')
		{
			if (intoken)
			{
				if (!instring)
				{
					intoken = 0;
					tokens[itoken++][jtoken] = 0;
					jtoken = 0;
				}

				else
				{
					tokens[itoken][jtoken++] = ch;
				}
			}
		}

		else if (ch == '"')
		{
			if (intoken)
			{
				if ((!instring && jtoken != 0) || 
					(instring && isvalidvarchar(line[iline])))
				{
					// Error: Mixing string token with something else 
					return 0; 
				}

				tokens[itoken][jtoken++] = ch;				
				instring = !instring;
			}
			
			else
			{
				intoken = 1;
				instring = 1;
				tokens[itoken][jtoken++] = ch;
			}
		}

		else if (isvalidvarchar(ch))
		{
			if (!intoken)
				intoken = 1;

			tokens[itoken][jtoken++] = ch;
		}

		else
		{
			if (instring)
				tokens[itoken][jtoken++] = ch;
		}
	}

	return itoken;
}

static char *get_string(char *out, int max, char *in)
{
	char *p;
	int len;
	
	memset(out, 0, max);

	if (in[0] != '"')
		return NULL;

	p = strchr(in+1, '"');

	if (!p)
		return NULL;

	if (p-(in+1) > max)
		len = max;
	else
		len = p-(in+1);

	strncpy(out, in+1, len);	

	return out;
}

static int get_integer(char *str)
{
	return strtol(str, NULL, 0);
}

static int get_boolean(char *str)
{
	if (strcmp(str, "false") == 0)
		return 0;

	if (strcmp(str, "true") == 0)
		return 1;	

	if (strcmp(str, "off") == 0)
		return 0;

	if (strcmp(str, "on") == 0)
		return 1;

	return get_integer(str);
}


void read_config(const char *file, CONFIGFILE *config)
{
	SceUID fd = sceIoOpen(file, PSP_O_RDONLY, 0777);

	/* Default: all values to zero */
	memset(config, 0, sizeof(CONFIGFILE));

	if (fd > 0)
	{
		int eof = 0, ntokens;
		char line[128];
		char tokens[2][128];
		
		while (!eof)
		{
			eof = read_line(fd, line, 127);
			ntokens = get_tokens(tokens, 2, line);	

			if (ntokens == 2)
			{
				// MUSIC
				if (strcmp(tokens[0], "music_dir") == 0)
				{
					get_string(config->music_dir, 64, tokens[1]);
				}
				if (strcmp(tokens[0], "musicButton") == 0)
				{
					get_string(config->musicButton, 10, tokens[1]);
					musicButtonEnable=1;
				}

				// Default vars
				if (strcmp(tokens[0], "enableUsbMass") == 0)
				{
					config->enableUsbMass = get_boolean(tokens[1]);
				} 	
				else if (strcmp(tokens[0], "defaultCpuSpeedGame") == 0)
				{
					config->defaultCpuSpeedGame = get_integer(tokens[1]);
				}
				else if (strcmp(tokens[0], "defaultBrightnessGame") == 0)
				{
					config->defaultBrightnessGame = get_integer(tokens[1]);
					defaultBrightnessEnable=1;
				}
				else if (strcmp(tokens[0], "usePspSlim") == 0)
				{
					config->usePspSlim = get_boolean(tokens[1]);
				}
				
				else if (strcmp(tokens[0], "comboButton") == 0)
				{
					get_string(config->comboButton, 10, tokens[1]);
				}
				
				
				// Reset Function 1
				else if (strcmp(tokens[0], "resetButton1") == 0)
				{
					get_string(config->resetButton1, 10, tokens[1]);
					reset1Enable=1;	
				}
				else if (strcmp(tokens[0], "resetButton1_TM_BOOT") == 0)
				{
					get_string(config->resetButton1_TM_BOOT, 32, tokens[1]);
				}

				// Reset Function 2
				else if (strcmp(tokens[0], "resetButton2") == 0)
				{
					get_string(config->resetButton2, 10, tokens[1]);
					reset2Enable=1;	
				}
				else if (strcmp(tokens[0], "resetButton2_TM_BOOT") == 0)
				{
					get_string(config->resetButton2_TM_BOOT, 32, tokens[1]);
				}
				
				
				// Power Off Function
				else if (strcmp(tokens[0], "poweroffButton") == 0)
				{
					get_string(config->poweroffButton, 10, tokens[1]);
					poweroffEnable=1;
				}
				
				
				// Cpu Speed Function			
				else if (strcmp(tokens[0], "cpuspeedButton") == 0)
				{
					get_string(config->cpuspeedButton, 10, tokens[1]);
					cpuspeedEnable=1;
				}
				
				
				// Usb Mass Storage Function
				else if (strcmp(tokens[0], "startStopUsbmassButton") == 0)
				{
					get_string(config->startStopUsbmassButton, 10, tokens[1]);
					startStopUsbmassEnable=1;
				}
				
				
				// Ftpd Function
				else if (strcmp(tokens[0], "startFtpdButton") == 0)
				{
					get_string(config->startFtpdButton, 10, tokens[1]);
					startFtpdEnable=1;
				}
				
				
				// Screenshot Function
				else if (strcmp(tokens[0], "takeScreenshotButton") == 0)
				{
					get_string(config->takeScreenshotButton, 10, tokens[1]);
					takeScreenshotEnable=1;
				}
				
				
				// Capture Function
				else if (strcmp(tokens[0], "captureButton") == 0)
				{
					get_string(config->captureButton, 10, tokens[1]);
					captureEnable=1;
				}
				
				// Brightness Function
				else if (strcmp(tokens[0], "maxBrightnessButton") == 0)
				{
					get_string(config->maxBrightnessButton, 10, tokens[1]);
					maxBrightnessEnable=1;
				}
	
				// Help Function
				else if (strcmp(tokens[0], "showHelpButton") == 0)
				{
					get_string(config->showHelpButton, 10, tokens[1]);
					showHelpEnable=1;	
				}
				
				// Capture Folder Directory
				else if (strcmp(tokens[0], "captureFolder") == 0)
				{
					get_string(config->captureFolder, 64, tokens[1]);
				}

				// ...
				else if (strcmp(tokens[0], "use_transparency") == 0)
				{
					config->use_transparency = get_boolean(tokens[1]);
				} 		
			}
		}

		sceIoClose(fd);
	}
}
