#include <common/macro.hpp>
#include <common/systime.hpp>
#include <common/diskinfo.hpp>
#include <common/regkey.hpp>

WORD SymbolTable::isInSymbols(char symbol)
{
	for(int i=0;i<mCurrentSymbols;i++)if(symbol==*((LPSTR)mSymbolTable+i))return TRUE;
	return FALSE;
}

Macro::Macro(void)
: mUnsetString("UNSET")
{
}

Macro::~Macro()
{
}

void Macro::processEmbeddedMacro(String &someString)
{
	mInputString=someString;
	mlpPtrString=mInputString;

	while(mlpPtrString&&0!=*mlpPtrString)
	{
		switch(*mlpPtrString)
		{
			case '$' :
				expandEmbeddedMacro();
				break;
			default :
				++mlpPtrString;
		}
	}
	someString=mInputString;
}

void Macro::expandEmbeddedMacro(void)
{
	String macroString;
	String tempString;
	Block<String> macroStrings;
	char *startPosition=mlpPtrString;
	WORD offsetPosition;

	pushSymbol(EnvMacroMid);
	pushSymbol(EnvMacroEnd);
	pushSymbol(EnvMacroSync);
	pushSymbol(EnvMacroStart);
	if(!expect(EnvMacroStart))return;
	if(!expect(EnvMacroSync))return;
	popSymbol(2);
	extractString(macroString);
	macroStrings.insert(&macroString);
	popSymbol(1);
	while(isInSymbols(*mlpPtrString))
	{
		pushSymbol(EnvMacroEnd);
		if(!expect(*mlpPtrString))return;
		extractString(macroString);
		macroStrings.insert(&macroString);
		popSymbol(1);
	}
	popSymbol(1);
	pushSymbol(EnvMacroEnd);
	if(!expect(*mlpPtrString))return;
	popSymbol(1);
	*startPosition=0;
	tempString=mInputString;
	macroString=locateFirstEnvironmentString(macroStrings);
	tempString+=macroString;
	offsetPosition=::strlen(mInputString)+::strlen(macroString);
	tempString+=mlpPtrString;
	mInputString=tempString;
	mlpPtrString=((LPSTR)mInputString+offsetPosition);
}

void Macro::extractString(String &macroString)
{
	String tempString;
	BYTE counter(0);

	while(0!=*mlpPtrString&&!isInSymbols(*mlpPtrString))
  {
		*((LPSTR)tempString+counter++)=*mlpPtrString;
		mlpPtrString++;
	}
	*((LPSTR)tempString+counter)=0;
	macroString=tempString;
}

WORD Macro::expect(char symbol)
{
	if(*mlpPtrString==symbol)
	{
		mlpPtrString++;
		return TRUE;
	}
	while(0!=*mlpPtrString&&!isInSymbols(*mlpPtrString))mlpPtrString++;
	return FALSE;
}

String Macro::locateFirstEnvironmentString(Block<String> &varStrings)
{
	size_t size(varStrings.size());
	char *envPtr;

	for(int i=0;i<size;i++)
  {
		if(0!=(envPtr=::getenv(varStrings[i])))return String(envPtr);
		else if(expandFunction(varStrings[i]))return varStrings[i];
    else if(expandLiteral(varStrings[i]))return varStrings[i];
	}
  return mUnsetString;
}

WORD Macro::expandLiteral(String &literalString)const
{
	String workString;

	if(literalString.isNull())return FALSE;
	workString=literalString.betweenString('"','"');
	if(workString.isNull())return FALSE;
	literalString=workString;
  return TRUE;
}

WORD Macro::expandFunction(String &atFunction)const
{
	WORD returnCode(FALSE);

	if(atFunction==String("@TIME"))
	{
	  SystemTime systemTime;
		atFunction=systemTime.toString();
		returnCode=TRUE;
	}
	else if(atFunction==String("@PWD"))
	{
	  DiskInfo diskInfo;
		diskInfo.getCurrentDirectory(atFunction);
		returnCode=TRUE;
	}
	else if(atFunction==String("@PROGRAMFILESDIR"))
	{
	  RegKey regKey(RegKey::LocalMachine);
		regKey.openKey("Software\\Microsoft\\Windows\\CurrentVersion");
		regKey.queryValue("ProgramFilesDir",atFunction);
		if(atFunction.isNull())atFunction="c:\\program files";
		returnCode=TRUE;
	}
	return returnCode;
}
