#include "mathStringParser.h"

namespace mathParser
{

bool mathParser::isOpenBrace( char char_ )
{
	if (  char_ == '(' || char_ == '[' || char_ == '{' )
	{
		return true;
	}
	return false;
}
bool mathParser::isClosedBrace( char char_ )
{
	if (  char_ == ')' || char_ == ']' || char_ == '}' )
	{
		return true;
	}
	return false;
}
bool mathParser::isOperator( char char_ )
{
	if ( char_ == '+' || char_ == '-' || char_ == '*' || char_ == '/' )
	{
		return true;
	}

	return false;
}

int mathParser::getOperatorPriority( char operator1 )
{
	if ( operator1 == '+' )
	{
		return 10;
	}
	
	if ( operator1 == '-' )
	{
		return 10;
	}

	if ( operator1 == '*' )
	{
		return 20;
	}
	
	if ( operator1 == '/' )
	{
		return 20;
	}

	assert( "Unkown operator!");
	return -1;
}
bool mathParser::isWhitespace( char char_ )
{
	if ( char_ < 33 )
	{
		return true;
	}

	return false;
}
/*
bool isEscapeSequence( char char_ )
{
	if ( char_ == '\\' ) return true;

	return false;
}
*/
bool mathParser::isLowerOrEqualPriority( char operator1, char operator2 )
{
	return ( getOperatorPriority(operator1) <= getOperatorPriority(operator2) );
}

bool mathParser::parseStringToTokens( const std::string & inputStr, vector<Token>& outputTokenArray )
{
	int i=0;
	while (  i<inputStr.length() )
	{
		Token newToken;

		if( isWhitespace( inputStr[i] ) )
		{
			++i; //skip white chars
			continue;
		}

		//OPERATORS
		if ( isOperator(inputStr[i]) )
		{
			newToken.type = OPERATOR;
			newToken.value = inputStr[i];
			outputTokenArray.push_back( newToken );
			++i;
			continue;
		}

		//INTEGER & FLOAT NUMBERS
		if (  inputStr[i] >= '0' && inputStr[i] <= '9' )
		{
			newToken.type = NUMBER;

			do
			{
				newToken.value += inputStr[i];
				++i;
			}
			while (  i<inputStr.length() &&  
					((inputStr[i] >= '0' && inputStr[i] <= '9') || 
					inputStr[i] =='.') );
			
			outputTokenArray.push_back( newToken );
			continue;
		}

		//BRACES
		if ( isOpenBrace(inputStr[i]) || isClosedBrace(inputStr[i]) )
		{
			newToken.type = BRACE;
			newToken.value = inputStr[i];
			outputTokenArray.push_back( newToken );
			++i;
			continue;
		}



		//IDENTIFIERS
		if (	inputStr[i] >= 'A' && inputStr[i] <= 'Z' ||
				inputStr[i] >= 'a' && inputStr[i] <= 'z' )
		{
			newToken.type = IDENTIFIER;

			do
			{
				newToken.value += inputStr[i];
				++i;
			}
			while (  i<inputStr.length() &&
					((inputStr[i] >= '0' && inputStr[i] <= '9') ||
					(inputStr[i] >= 'A' && inputStr[i] <= 'Z') ||
					(inputStr[i] >= 'a' && inputStr[i] <= 'z') ));

			outputTokenArray.push_back( newToken );
			continue;
		}


		//IDENTIFIERS ( identifier name starts and ends with " )
		if ( inputStr[i]=='"' )
		{
			++i; //skip char "
			
			newToken.type = IDENTIFIER;

			do
			{
				newToken.value += inputStr[i];
				++i;
			}
			while (  i<inputStr.length() && inputStr[i] != '"');

			outputTokenArray.push_back( newToken );
			++i; //skip char "
			continue;
		}


		assert( !"Unexpected program flow" );
		return false;
	}

	

	return true;
}

bool mathParser::convertToPrefix( const vector<Token>& inputTokenArray, vector<Token>& outputPrefixTokenArray  )
{
	int i=0;
	int braceDepth= 0;
	vector<Token> hlpTokenArray;

	while ( i< inputTokenArray.size() )
	{
		switch ( inputTokenArray[i].type )
		{
		case BRACE:
			if ( isOpenBrace(inputTokenArray[i].value[0]) )
			{
				++braceDepth;
				hlpTokenArray.push_back( inputTokenArray[i] );
			}
			else
			{
				--braceDepth;


				//remove part of help stack to main stack
				while ( hlpTokenArray.back().type != BRACE && !isOpenBrace(hlpTokenArray.back().value[0]) )
				{
					assert( hlpTokenArray.back().type == OPERATOR && "Parse failed, operator expected!" );
					if ( hlpTokenArray.back().type != OPERATOR )
					{
						return false;
					}

					outputPrefixTokenArray.push_back( hlpTokenArray.back() );
					hlpTokenArray.pop_back();
				}

				//remove stop open bracket 
				hlpTokenArray.pop_back();
			}

			break;

		case OPERATOR:
			if ( isOperator(inputTokenArray[i].value[0]) )
			{
				/*
				if ( braceDepth== 0 )
				{
					//move to main stack
				}
				*/

				

				while ( !hlpTokenArray.empty() && isLowerOrEqualPriority(inputTokenArray[i].value[0], hlpTokenArray.back().value[0]) )
				{
					outputPrefixTokenArray.push_back( hlpTokenArray.back() );
					hlpTokenArray.pop_back();
				}

				hlpTokenArray.push_back( inputTokenArray[i] );
			}
			break;

		case NUMBER:
			outputPrefixTokenArray.push_back( inputTokenArray[i] );
			break;

		case IDENTIFIER:
			outputPrefixTokenArray.push_back( inputTokenArray[i] );
			break;
		}

		++i;
	}

	while ( !hlpTokenArray.empty() )
	{
		outputPrefixTokenArray.push_back( hlpTokenArray.back() );
		hlpTokenArray.pop_back();
	}

	assert( braceDepth == 0 && "Open and Close braces do not fit!");
	if ( braceDepth != 0 )
	{
		return false;
	}

	return true;
}

}