#include "CFGFileParser.h"

CFGFileParser::CFGFileParser(SDCardManager &sdCardManager, const char *file):AbstractParser(file), _state(INIT), _type(PARAMETER), _quotedParameter(false), _quotedValue(false), _sdCardManager(sdCardManager)
{

}

void *CFGFileParser::parseFile()
{
    //Here is the logic for the file parser
    File file;
    
    CFGDictionary<CFGParameterValue> *dictioRef = new CFGDictionary<CFGParameterValue>;
    char readChar(0), *parsedParameter(NULL), *parsedValue(NULL);

    file = _sdCardManager.open(_resource);
    if(!file)
    {
      delete dictioRef;
      file.close();
      return NULL;
    }
	
	_state = INIT;
    while(file.available())
    {
      readChar = (char)file.read();
      
        //Do work
        switch(_state)
        {
        case INIT:
            if(readChar == '#') _state = COMMENT_SECTION;
            else if((readChar >= 65 && readChar <= 90) || (readChar >= 97 && readChar <= 122) || (readChar >= 48 && readChar <= 57))
            {
                _state = PARAM_SECTION;
                parsedParameter = addChar(parsedParameter, readChar);
                if(parsedParameter == NULL)
                    _state = ERROR;
                //printf("%c",readChar);
            }
            else if(readChar == '\'')
            {
                _state = OPENING_QUOTE;
                _type = PARAMETER;
            }
            else
                _state = ERROR;
            break;
        case COMMENT_SECTION:
            if(readChar == '\r' || readChar == '\n') _state = LINE_BREAK;
            break;
        case LINE_BREAK:
            if(readChar == '#')
                _state = COMMENT_SECTION;
            else if(readChar == '\r' || readChar == '\n') _state = LINE_BREAK;
            else if((readChar >= 65 && readChar <= 90) || (readChar >= 97 && readChar <= 122) || (readChar >= 48 && readChar <= 57))
            {
                _state = PARAM_SECTION;
                //printf("%c",readChar);
                _type = PARAMETER;
                parsedParameter = addChar(parsedParameter, readChar);
                if(parsedParameter == NULL)
                    _state = ERROR;
            }
            else if(readChar == '\'')
            {
                _state = OPENING_QUOTE;
                _type = PARAMETER;
            }
            else
                _state = ERROR;
            break;
        case PARAM_SECTION:
            if(readChar == '\'')_state = OPENING_QUOTE;
            else if(readChar == ':') _state = SEPARATION;
            else if(readChar == '\r' || readChar == '\n')
            {
                _state = LINE_BREAK;
                if(parsedParameter != NULL)
                {
                    //printf("%s --> %s\n", parsedParameter, parsedValue);
                    dictioRef->add(parsedParameter, new CFGParameterValue(parsedParameter, parsedValue == NULL ? "":parsedValue, _quotedParameter, _quotedValue));
                    free(parsedParameter);free(parsedValue);
                    parsedParameter = NULL;parsedValue = NULL;
                    _quotedParameter = false;_quotedValue = false;

                }
            }
            else if(readChar == ' ') _state = PARAM_SECTION;
            else if((readChar >= 65 && readChar <= 90) || (readChar >= 97 && readChar <= 122) || readChar == '_' || (readChar >= 48 && readChar <= 57))
            {
                if(_type == PARAMETER)
                {
                    parsedParameter = addChar(parsedParameter, readChar);
                    if(parsedParameter == NULL)
                        _state = ERROR;
                }
                else
                {
                    parsedValue = addChar(parsedValue, readChar);
                    if(parsedValue == NULL)
                        _state = ERROR;
                }
                //printf("%c",readChar);
            }
            else
                _state = ERROR;
            break;
        case OPENING_QUOTE:
            if(readChar == '\'')
            {
                _state = PARAM_SECTION;
                if(_type == PARAMETER)
                    _quotedParameter = true;
                else
                    _quotedValue = true;
            }
            else if((readChar >= 65 && readChar <= 90) || (readChar >= 97 && readChar <= 122) || readChar == ' ' || readChar == '_' || (readChar >= 48 && readChar <= 57))
            {
                //printf("%c",readChar);
                if(_type == PARAMETER)
                {
                    parsedParameter = addChar(parsedParameter, readChar);
                    if(parsedParameter == NULL)
                        _state = ERROR;
                }
                else
                {
                    parsedValue = addChar(parsedValue, readChar);
                    if(parsedValue == NULL)
                        _state = ERROR;
                }
            }
            else
                _state = ERROR;
            break;
        case SEPARATION:
            _type = VALUE;
            if(readChar == '\'')_state = OPENING_QUOTE;
            else if(readChar == ' ') _state = PARAM_SECTION;
            else if((readChar >= 65 && readChar <= 90) || (readChar >= 97 && readChar <= 122) || (readChar >= 48 && readChar <= 57))
            {
                _state = PARAM_SECTION;

                parsedValue = addChar(parsedValue, readChar);
                if(parsedValue == NULL)
                    _state = ERROR;
            }
            else _state = ERROR;
            break;
        case ERROR:
            dictioRef->dispose();
            delete dictioRef;
            free(parsedValue);
            free(parsedParameter);
            parsedValue = NULL;
            parsedParameter = NULL;
            return NULL;
            break;
        }
    }

    file.close();
    return dictioRef;
}

boolean CFGFileParser::save(void *data)
{
  if(data == NULL)
	return false;
  Dictionary<CFGParameterValue> *ref = (Dictionary<CFGParameterValue> *) data;
  int truncateHere(0);
  char readChar(0);
  
  File file = _sdCardManager.open(_resource, FILE_READWRITE);
  
  if(!file)
  {
    file.close();
    return false;
  }
  
  file.seek(0);
  _state = INIT;
  
  //We find out where to truncate the file
  while(file.available())
  {
	readChar = (char)file.read();
	switch(_state)
	{
		case INIT:
			if(readChar == '#')
			{
				truncateHere++;
				_state = COMMENT_SECTION;
			}
			else
				_state = DONE;
			break;
		case COMMENT_SECTION:
			truncateHere++;
			if(readChar == '\n') _state = LINE_BREAK;
			break;
		case LINE_BREAK:
			truncateHere++;
			if(readChar == '#')
                _state = COMMENT_SECTION;
			else if(readChar == '\n') _state = DONE;
			break;
	}
  }
  
  if(!file.truncate(truncateHere))
  {
	file.close();
	return false;
  }
  
  //Let's write the settings
  for(int i = 0; i < ref->count(); i++)
  {
	CFGParameterValue *cfgPV = ref->getAt(i);
	
	if(cfgPV->isQuotedParameter())
	{
		file.write('\'');
		file.print(cfgPV->getParameter());
		file.write('\'');
	}
	else
	{
		file.print(cfgPV->getParameter());
	}
	
	file.print(F(" : "));
	
	if(cfgPV->isQuotedValue())
	{
		file.write('\'');
		file.print(cfgPV->stringValue());
		file.println('\'');
	}
	else
	{
		file.println(cfgPV->stringValue());
	}
  }
  
  file.close();
  return true;
}
