///////////////////////////////////////////////////////////
///////////////// Have an itch? Scratch it! ///////////////
///////////////////////// SCRATCH /////////////////////////
/////////////////////  A MUD  Server   ////////////////////
///////////////////// By: Jared Devall ////////////////////
/////////////////////      Thanks:     ////////////////////
/////////////////////  DIKU/Merc/ROM   ////////////////////
///////////////////// Aetas/Deus Gang  ////////////////////
/////////////////////       Beej       ////////////////////
///////////////////////////////////////////////////////////

#include <map>
#include "commandTable.h"
#include "world.h"
#include "stringutil.h"
#include "split.h"

using namespace std;

CommandTable::CommandTable( ) {	
	LoadCommands( );	
}	

bool CommandTable::LoadCommands( ) {
	// Populate list with commands
	_commands.push_back( new CmdBuzz );
	_commands.push_back( new CmdCommands );
	_commands.push_back( new CmdDelete );
	_commands.push_back( new CmdDisable );
	_commands.push_back( new CmdDisconnect );
	_commands.push_back( new CmdEdit );
	_commands.push_back( new CmdEmote );
	_commands.push_back( new CmdPassword );
	_commands.push_back( new CmdPrompt );
	_commands.push_back( new CmdQuit );
	_commands.push_back( new CmdReboot );
	_commands.push_back( new CmdReply );
	_commands.push_back( new CmdSave );
	_commands.push_back( new CmdSay );
	_commands.push_back( new CmdShutdown );
	_commands.push_back( new CmdSockets );
	_commands.push_back( new CmdTell );
	_commands.push_back( new CmdTitle );
	_commands.push_back( new CmdWho );	
	
	// Make sure if any commands are supposed to be disabled we disable them
	LoadDisabledCommands( );
	return true;
}

bool CommandTable::LoadDisabledCommands( ) {
	string query;
	list< Command *>::iterator it;
	map< string, string >::iterator command;
	
	for ( it = _commands.begin(); it != _commands.end(); ++it ) {
		query.erase();
		query << "SELECT * FROM disabled_commands WHERE command='" << (*it)->_name << "'";			

		if ( !Mysql::Instance().Load( query.c_str() ) ) 
			continue;	
		
		// Found the command in the disabled database
    	(*it)->_enabled = false;			
    }
	return true;
}

Command * CommandTable::FindCommand( Avatar * avatar, const string &command, bool shortcut ) {
	list< Command * >::iterator it;
	string command1 = command;

	for ( it = _commands.begin(); it != _commands.end(); ++it ) {
		if ( (*it)->_enabled == false && ( str_cmp( (*it)->_name, command1 ) || ( str_prefix( command1, (*it)->_name ) ) ) && ( avatar->Get( "group" ).find( (*it)->_group ) != string::npos ) ) {
			if ( avatar->Get( "group" ).find( (*it)->_group ) != string::npos )
				avatar->Send( "That command is disabled.\n\r" );
			else 
				avatar->Send( "That is an invalid command.\n\r" );
			
			return NULL;
		}
		
		// If it's a shortcut, check against the commands shortcut
		if ( shortcut == true && !(*it)->_shortcut.empty() ) {
			if ( ( str_cmp( (*it)->_shortcut, command1 ) ) && ( avatar->Get( "group" ).find( (*it)->_group ) != string::npos ) ) {
				if ( ( (*it)->_enabled == false ) && (avatar->Get( "group" ).find( (*it)->_group ) != string::npos ) ) {
					avatar->Send( "That command is disabled.\n\r" );
					return NULL;
				} else if ( ( (*it)->_enabled == false ) && ( avatar->Get( "group" ).find( (*it)->_group ) == string::npos ) ) {
					avatar->Send( "That is an invalid command.\n\r" );
					return NULL;
				}
				return (*it);
			}
		}	
		if ( ( str_cmp( (*it)->_name, command1 ) || ( str_prefix( command1, (*it)->_name ) ) ) && ( avatar->Get( "group" ).find( (*it)->_group ) != string::npos ) ) {
		   return (*it);
		}
	}
	return NULL;
}

bool CommandTable::Execute( Avatar * avatar, const string &commandAndArgs ) {
	string commandss = commandAndArgs;
	string command1;
	string arguments;
	Command * command;
	string buf;
	bool shortcut = false;
	list< Command * >::iterator it;
	

	if ( commandAndArgs.empty() || commandAndArgs[0] == '\n' || commandAndArgs[0] == '\r' )
		return false;

	// Check to see if there is a 'shortcut' used. Really checking if
	// it's a nonalphanumeric character.	
	for ( string::iterator cChar = commandss.begin(); cChar != commandss.end(); ++cChar ) {
		if ( !isalpha( (*cChar) ) && !isdigit( (*cChar) ) && cChar == commandss.begin() ) {
			command1 = (*cChar);
			shortcut = true;
		} else {
			arguments << (*cChar); 
		}
	 } 
	 // No shortcut
	 if ( shortcut == false ) {
		 arguments.erase();
		 split( commandAndArgs, command1, arguments );
	 }
	
	if ( ( command = FindCommand( avatar, command1, shortcut ) ) != NULL ) {
		command->Execute( avatar, arguments );
		return true;
	} 
   
	avatar->Send( "That is an invalid command.\n\r" );
	return false;
}