#include "MW4Headers.hpp"
#include "Adept\AdeptHeaders.hpp"
#include "server\comline.hpp"
#include "mw4.hpp"
#include "moverai.hpp"
#include "Adept\Interface.hpp"
#include "Adept\Application.hpp"
#include "mwmission.hpp"

namespace MechWarrior4
{
	CCommandLineServer *g_ComServer = NULL;
}
extern char gszBuildNumber[];
AI *g_CurrentDebugAI = NULL;

void ABLDebugCallback (char *s)
{
	if (g_ComServer)
		g_ComServer->PushLine (s);
	else
		SPEW (("afarrier",s));
}



bool MW4_BuildNum (CCommandLineServer *thisptr,NCOMLINE::LineData& p1)
{
	char string[256];

	strncpy (string,gszBuildNumber,255);
	string[255] = 0;
	thisptr->PushLine (string);
	return true;
}

NameTableEntry *ComFindEntry (NCOMLINE::LineData& p1,int arg)
{
	char name[100];
	int i,size;

	if (p1.m_NumArgs <= arg)
		return NULL;
	p1.Argument (arg,name,100);
	size = strlen (name);
	for (i=0;i<(size-4);i++)
	{
		name[i] = name[i+4];
	}
	name[i] = 0;
	return NameTable::GetInstance()->FindEntry(name);
}

bool MW4_ABL_Continue (CCommandLineServer *thisptr,NCOMLINE::LineData& p1)
{
	ABL::Debugger *fred = ABL::ABLi_getDebugger ();
	if (!fred)
	{
		thisptr->PushLine ("No ABL debugging support installed");
		return true;
	}

	fred->processCommand (ABL::DEBUG_COMMAND_CONTINUE,NULL,0,NULL);
	return true;
}

bool MW4_ABLDebug (CCommandLineServer *thisptr,NCOMLINE::LineData& p1)
{
	int size;
	int i;
	ABL::Debugger *fred = ABL::ABLi_getDebugger ();
	if (!fred)
	{
		thisptr->PushLine ("No ABL debugging support installed");
		return true;
	}
	char name[101],arg[101],arg2[101];

	p1.Argument (1,name,100);
	if (!stricmp (name,"showmod"))
	{
		fred->displayModuleInstanceRegistry ();
	}
	else if (!stricmp (name,"setmod"))
	{
		if (p1.m_NumArgs == 2)
		{
			fred->processCommand (ABL::DEBUG_COMMAND_SET_MODULE,NULL,1,NULL);
			return true;
		}
		if (p1.m_NumArgs != 3)
		{
			thisptr->PushLine ("Wrong number of arguments");
			return true;
		}
		p1.Argument (2,arg,100);
		if (!stricmp (arg,"mission"))
		{
			Check_Object (MechWarrior4::MWMission::GetInstance());
			MechWarrior4::MWMission *mission = Cast_Object (MechWarrior4::MWMission*,MechWarrior4::MWMission::GetInstance());

			if (mission)
			{
				fred->processCommand (ABL::DEBUG_COMMAND_SET_MODULE,NULL,1,mission->Brain ());
				return true;
			}
		}
		size = strlen (arg);
		for (i=0;i<(size-4);i++)
		{
			arg[i] = arg[i+4];
		}
		arg[i] = 0;
		NameTableEntry *entry;
		entry = NameTable::GetInstance()->FindEntry(arg);
		if (!entry)
		{
			thisptr->PushLine ("No object with this name");
			return true;
		}
		AI *ai;

		ai = static_cast <AI *> (entry->dataPointer->GetCurrent());
		if (!ai->IsDerivedFrom (AI::DefaultData))
		{
			thisptr->PushLine ("That object is not an ai");
			return true;
		}

		fred->processCommand (ABL::DEBUG_COMMAND_SET_MODULE,NULL,1,ai->Brain ());
		if (g_CurrentDebugAI)
		{
      g_CurrentDebugAI->Debug (false,NULL);
		}
		ai->Debug (true,ABLDebugCallback);
    g_CurrentDebugAI = ai;
	}
	else if (!stricmp (name,"trace"))
	{
		if (p1.m_NumArgs != 3)
		{
			thisptr->PushLine ("Wrong number of arguments");
			return true;
		}
		p1.Argument (2,arg,100);
		if (arg[0] == '+')
			fred->processCommand (ABL::DEBUG_COMMAND_TRACE,NULL,1,NULL);
		else
			fred->processCommand (ABL::DEBUG_COMMAND_TRACE,NULL,0,NULL);
	}
	else if (!stricmp (name,"step"))
	{
		if (p1.m_NumArgs != 3)
		{
			thisptr->PushLine ("Wrong number of arguments");
			return true;
		}
		p1.Argument (2,arg,100);
		if (arg[0] == '+')
			fred->processCommand (ABL::DEBUG_COMMAND_STEP,NULL,1,NULL);
		else
			fred->processCommand (ABL::DEBUG_COMMAND_STEP,NULL,0,NULL);
	}
	else if (!stricmp (name,"break"))
	{
		if (p1.m_NumArgs != 4)
		{
			thisptr->PushLine ("Wrong number of arguments");
			return true;
		}
		p1.Argument (2,arg,100);
		p1.Argument (3,arg2,100);
		i = atoi (arg2);
		if (arg[0] == '+')
			fred->processCommand (ABL::DEBUG_COMMAND_BREAKPOINT_SET,NULL,i,NULL);
		else
			fred->processCommand (ABL::DEBUG_COMMAND_BREAKPOINT_REMOVE,NULL,i,NULL);
	}
	else if (!stricmp (name,"watch"))
	{
		if (p1.m_NumArgs != 4)
		{
			thisptr->PushLine ("Wrong number of arguments");
			return true;
		}
		p1.Argument (3,arg,100);
		p1.Argument (2,arg2,100);
		int numparam;
		switch (arg2[0])
		{
		case 'f':
		case 'F':
			switch (arg2[1])
			{
			case '+':
				numparam = WATCH_FETCH_ON;
				break;
			case '-':
				numparam = WATCH_FETCH_OFF;
				break;
			default:
				thisptr->PushLine ("Wrong format for watch command");
				return true;
				break;
			}
			break;
		case 's':
		case 'S':
			switch (arg2[1])
			{
			case '+':
				numparam = WATCH_STORE_ON;
				break;
			case '-':
				numparam = WATCH_STORE_OFF;
				break;
			default:
				thisptr->PushLine ("Wrong format for watch command");
				return true;
				break;
			}
			break;
		default:
				thisptr->PushLine ("Wrong format for watch command");
				return true;
			break;
		}
		fred->processCommand (ABL::DEBUG_COMMAND_WATCH_SET,arg,numparam,NULL);
	}
	else if (!stricmp (name,"watchremove"))
	{
		fred->processCommand (ABL::DEBUG_COMMAND_WATCH_REMOVE_ALL,NULL,0,NULL);
	}
	else if (!stricmp (name,"print"))
	{
		if (p1.m_NumArgs != 3)
		{
			thisptr->PushLine ("Wrong number of arguments");
			return true;
		}
		p1.Argument (2,arg,100);
		fred->processCommand (ABL::DEBUG_COMMAND_PRINT,arg,0,NULL);
	}
	else if (!stricmp (name,"continue"))
	{
		if (p1.m_NumArgs != 2)
		{
			thisptr->PushLine ("Wrong number of arguments");
			return true;
		}
		fred->processCommand (ABL::DEBUG_COMMAND_CONTINUE,NULL,0,NULL);
	}
	else if (!stricmp (name,"help"))
	{
		if (p1.m_NumArgs != 2)
		{
			thisptr->PushLine ("Wrong number of arguments");
			return true;
		}
		fred->processCommand (ABL::DEBUG_COMMAND_HELP,NULL,0,NULL);
	}
	else if (!stricmp (name,"info"))
	{
		if (p1.m_NumArgs != 2)
		{
			thisptr->PushLine ("Wrong number of arguments");
			return true;
		}
		fred->processCommand (ABL::DEBUG_COMMAND_INFO,NULL,0,NULL);
	}
	else
	{
		thisptr->PushLine ("Unknown debugger command");
	}

	return true;
}				

bool MW4_EntityList (CCommandLineServer *thisptr,NCOMLINE::LineData& p1)
{
	int i,j,size;
	char prefix[5];
  NameTable *table = NameTable::GetInstance();
	Check_Object (table);

	prefix[4] = 0;
	for (i=NameTable::DefaultArray;i<NameTable::TableSize;i++)
	{
		switch (i)
		{
			case NameTable::VehicleArray:
				strncpy (prefix,"eve_",4);
				break;
			case NameTable::BuildingArray:
				strncpy (prefix,"ebu_",4);
				break;
			case NameTable::SoundArray:
				strncpy (prefix,"eso_",4);
				break;
			case NameTable::PathArray:
				strncpy (prefix,"epa_",4);
				break;
			case NameTable::NavArray:
				strncpy (prefix,"ena_",4);
				break;
			case NameTable::ObjectiveArray:
				strncpy (prefix,"eob_",4);
				break;
			case NameTable::DropZoneArray:
				strncpy (prefix,"edr_",4);
				break;
			case NameTable::AIArray:
				strncpy (prefix,"eai_",4);
				break;
			case NameTable::TurretArray:
				strncpy (prefix,"etu_",4);
				break;
			case NameTable::CameraShipArray:
				strncpy (prefix,"eca_",4);
				break;
			case NameTable::FlagArray:
				strncpy (prefix,"efl_",4);
				break;
			default:
				strncpy (prefix,"ede_",4);
				break;
		}
		size = table->nameTableArray[i].GetLength ();
		for (j=0;j<size;j++)
		{
			NameTableEntry *data;
			char name[256],output[256];
			char *temp;

			data = &table->nameTableArray	[i][j];

			sprintf (name,"%s%s",prefix,(char *) data->objectName);
			temp = name;
			while (*temp != 0)
			{
				*temp = (char) tolower (*temp);
				temp++;
			}

			sprintf (output,"%s = %d",name,data->GetObjectID ());
			thisptr->PushLine (output);
		}
	}
	return true;
}

bool MW4_AILoc (CCommandLineServer *thisptr,NCOMLINE::LineData& p1)
{
	char name[100];
	Stuff::Point3D loc;
	AI *who;
	Entity *ent;
	NameTableEntry *entry;

	entry = ComFindEntry (p1,1);

	if (!entry)
	{
		thisptr->PushLine ("No object with this name");
		return true;
	}

	ent = (Entity *) entry->dataPointer->GetCurrent();;
	if ((!ent) || (ent == (Entity*) -1))
	{
		thisptr->PushLine ("No object with this name");
		return true;
	}

	if (ent->IsDerivedFrom (AI::DefaultData))
	{
		who = Cast_Object (AI *,ent);
		loc = (Point3D) who->getEntity ()->GetLocalToWorld ();
		sprintf (name,"AI at %f,%f,%f",loc.x,loc.y,loc.z);
	}
	else
	{
		loc = (Point3D) ent->GetLocalToWorld ();
		sprintf (name,"Entity at %f,%f,%f",loc.x,loc.y,loc.z);
	}

	thisptr->PushLine (name);

	return true;
}

bool MW4_AIState (CCommandLineServer *thisptr,NCOMLINE::LineData& p1)
{
	AI *who;
	char name[100];
	Stuff::Point3D loc;
	NameTableEntry *entry;

	entry = ComFindEntry (p1,1);

	if (!entry)
	{
		thisptr->PushLine ("No object with this name");
		return true;
	}

	who = (AI *) entry->dataPointer->GetCurrent();
	if (!who)
	{
		thisptr->PushLine ("No object with this name");
		return true;
	}
	if (!who->IsDerivedFrom (AI::DefaultData))
	{
		thisptr->PushLine ("Not an AI object with this name");
		return true;
	}
	loc = (Point3D) who->getEntity ()->GetLocalToWorld ();
	sprintf (name,"AI at %f,%f,%f",loc.x,loc.y,loc.z);
	thisptr->PushLine (name);
	return true;
}

bool MW4_AIID (CCommandLineServer *thisptr,NCOMLINE::LineData& p1)
{
	char name[100],text[100];
	Stuff::Point3D loc;
	NameTableEntry *entry;

	entry = ComFindEntry (p1,1);
	if (!entry)
	{
		thisptr->PushLine ("No object with this name");
		return true;
	}
	sprintf (text,"%s is id %d",name,entry->GetObjectID ());
	thisptr->PushLine (text);
	return true;
}

bool MW4_AIInfo (CCommandLineServer *thisptr,NCOMLINE::LineData& p1)
{
	Stuff::Point3D loc;
	AI *who;
	NameTableEntry *entry;

	entry = ComFindEntry (p1,1);
	if (!entry)
	{
		thisptr->PushLine ("No object with this name");
		return true;
	}
	who = (AI *) entry->dataPointer->GetCurrent();
	if (!who)
	{
		thisptr->PushLine ("No object with this name");
		return true;
	}
	if (!who->IsDerivedFrom (AI::DefaultData))
	{
		thisptr->PushLine ("Not an AI object with this name");
		return true;
	}
	who->Info (ABLDebugCallback);

	return true;
}

bool MW4_ComHelp (CCommandLineServer *thisptr,NCOMLINE::LineData& p1)
{
	thisptr->PushLine ("debug <help>           - For list of debugger commands");
	thisptr->PushLine ("loc <objectname>       - coordinates of object name");
	thisptr->PushLine ("aistate <ainame>       - current abl state of ai");
	thisptr->PushLine ("id <objectname>        - id number of object name");
	thisptr->PushLine ("entities               - list of all entities and their id's");
	thisptr->PushLine ("aiinfo <ainame>        - info on ai with ai name");
	thisptr->PushLine ("c                      - continue in abl debugging, shortcut for debug continue");
	thisptr->PushLine ("help                   - this screen");
	thisptr->PushLine ("?                      - this screen");
	return true;
}

void InitComFuncs (void)
{
	g_ComServer = NULL;
#if 0
	g_ComServer = new CCommandLineServer ();
	g_ComServer->AddCommand (MW4_BuildNum,"build");

	ABL::Debugger *fred = ABL::ABLi_getDebugger ();
	if (fred)
		fred->setCallback (ABLDebugCallback);
	g_ComServer->AddCommand (MW4_ABLDebug,"debug");
	g_ComServer->AddCommand (MW4_AILoc,"loc");
	g_ComServer->AddCommand (MW4_AIState,"aistate");
	g_ComServer->AddCommand (MW4_AIID,"id");
	g_ComServer->AddCommand (MW4_EntityList,"entities");
	g_ComServer->AddCommand (MW4_ABL_Continue,"c");
	g_ComServer->AddCommand (MW4_AIInfo,"aiinfo");
	g_ComServer->AddCommand (MW4_ComHelp,"help");
	g_ComServer->AddCommand (MW4_ComHelp,"?");
#endif
}

void KillComFuncs (void)
{
	delete g_ComServer;
	g_ComServer = NULL;
}