#include "console.h"
#include "filesystem.h"
#include "tier1/utlstring.h"
#include "tier1/utlvector.h"

CUtlVector<ConVar*> g_convars;
CUtlVector<ConCommand*> g_commands;

void IConsole::RegisterVar( ConVar *cvar )
{
	g_convars.AppendTail(cvar);
}
void IConsole::UnRegisterVar( ConVar *cvar )
{

}
ConVar *IConsole::FindVar( const char *pName )
{
	for (auto &var: g_convars)
	{
		if (!V_strcmp(var->GetName(), pName))
			return var;
	}
	return NULL;
}

void IConsole::RegisterCommand( ConCommand *cvar )
{
	g_commands.AppendTail(cvar);
}
void IConsole::UnRegisterCommand( ConCommand *cvar )
{

}
ConCommand *IConsole::FindCommand( const char *pName )
{
	for (auto &var: g_commands)
	{
		if (!V_strcmp(var->GetName(), pName))
			return var;
	}
	return NULL;
}
CUtlString g_commandBuffer;

//-----------------------------------------------------------------------------
// Executes arguments from IConsole::Execute 
//-----------------------------------------------------------------------------
void IConsole::Execute2( CUtlVector<CUtlString> &args )
{
	if (args.GetSize()<1)
		return;

	ConCommand *cmd = IConsole::FindCommand(args[0]);
	if (!cmd)
	{
		V_printf("%s not found\n", args[0].GetString());
		return;
	}
	CUtlBuffer<char*> strbuffer(args.GetSize());
	for ( size_t i = 0; i < args.GetSize(); i++)
	{
		strbuffer[i] = args[i].GetString();
	};
	(cmd->GetCallback())(args.GetSize(), strbuffer);
}

void IConsole::Execute( void )
{
	CUtlVector<CUtlVector<CUtlString>> commands = ParseCommandLine(g_commandBuffer);
	g_commandBuffer = 0;
	for (auto &command: commands)
	{
		IConsole::Execute2(command);
	}
}

//-----------------------------------------------------------------------------
// Parses command buffer. 
//-----------------------------------------------------------------------------
CUtlVector<CUtlVector<CUtlString>> IConsole::ParseCommandLine( CUtlString psz )
{	
	CUtlVector<CUtlString> arguments;
	CUtlVector<CUtlVector<CUtlString>> commands;
	CUtlString szArgument;
	bool bIsQuote = false;
	for ( auto &c: (CUtlVector<char>&)psz )
	{
		if ( c == '\"' )
		{
			bIsQuote = !bIsQuote;
			continue;
		}

		if ( c == ';' || c == '\n' )
		{
			if (bIsQuote)
			{
				continue;
			}
			if (szArgument != 0)
				arguments.AppendTail(szArgument);
			if ( arguments.GetSize() > 0 )
				commands.AppendTail(arguments);
			szArgument = 0;
			arguments = {};
			continue;
		}
		if ( c == '\t' || c == ' ' )
		{
			if (bIsQuote)
			{
				szArgument.AppendTail(c);
				continue;
			}

			if (szArgument != 0)
				arguments.AppendTail(szArgument);
			szArgument = 0;
			continue;
		}
		szArgument.AppendTail(c);
	};
	if (szArgument != 0)
		arguments.AppendTail(szArgument);
	if ( arguments.GetSize() > 0 )
		commands.AppendTail(arguments);
	return commands;
}

void IConsole::AddCommand( const char *psz )
{
	g_commandBuffer.AppendTail(psz);
}

void IConsole::InsertCommand( const char *psz )
{
	g_commandBuffer.AppendHead(psz);
};

ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags ) 
	: ConVar(pName, pDefaultValue, flags, 0)
{
		
}
ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags,
	const char *pHelpString ) 
	: ConVar(pName, pDefaultValue, flags, pHelpString, 0)
{
}
ConVar::ConVar( const char *pName, const char *pDefaultValue, int flags,
	const char *pHelpString, ConCommandFn callback )
{
	m_szName = pName;
	m_flags = flags;
	m_szValue = pDefaultValue;
	m_fValue = V_atof(pDefaultValue);
	m_nValue = V_atoi(pDefaultValue);
	IConsole::RegisterVar(this);
}

bool ConVar::IsFlagSet( int flag )
{

}
const char *ConVar::GetHelpText( void )
{
	return m_szHelpString;
}
bool ConVar::IsRegistered( void )
{

}
const char *ConVar::GetName( void )
{
	return m_szName;
}
void ConVar::AddFlags( int flags )
{

}
bool ConVar::IsCommand( void )
{

}

void ConVar::InstallChangeCallback( ConCommandFn )
{

}

float ConVar::GetFloat( void )
{
	return m_fValue; 
}
int ConVar::GetInt( void )
{
	return m_nValue; 
}
bool ConVar::GetBool( void )
{
	return m_nValue;
}
const char *ConVar::GetString( void ) 
{

}

void ConVar::SetValue( const char *szValue )
{
	if (!szValue)
		return;
	m_szValue = szValue;
	m_fValue = V_atof(szValue);
	m_nValue = V_atoi(szValue);
}
void ConVar::SetValue( float fValue )
{
	m_fValue = fValue;
	m_nValue = fValue;
	m_szValue = CUtlString("%f\n",fValue);
}
void ConVar::SetValue( int iValue )
{
	m_fValue = iValue;
	m_nValue = iValue;
	m_szValue = CUtlString("%i\n",iValue);
}

ConCommand::ConCommand(const char *pName, ConCommandFn callback, 
	const char *pHelpString, int flags)
{
	m_szName = pName;
	m_callback = callback;
	m_flags = flags;
	IConsole::RegisterCommand(this);
};
const char *ConCommand::GetHelpText( void )
{
	return m_szHelpString;
}
const char *ConCommand::GetName( void )
{
	return m_szName;
}
ConCommandFn ConCommand::GetCallback( void )
{
	return m_callback;
}



void IConsole_Exec( int argc, char **argv)
{
	if (argc != 2)
		return;

	FileHandle_t f = IFileSystem::Open(argv[1], IFILE_READ);
	if (!f)
		return;
	CUtlBuffer<char> b(IFileSystem::Size(f)+1);
	IFileSystem::Read(f, b, b.GetSize());
	b[IFileSystem::Size(f)] = 0;
	IConsole::AddCommand(b);
	IConsole::AddCommand(";");
	IConsole::Execute();
}

ConCommand IConsole_ExecCmd("exec", IConsole_Exec);
