// InstanceWindow.cpp : implementation file
//

#include "stdafx.h"
#include "MW4GameEd.h"
#include "EditorChildWnd.h"
#include <direct.h>
#include <stdlib.h>
#include <stdio.h>
#include <Adept\Map.hpp>
#include "MoveCommand.h"
#include "AddCommand.h"
#include <Adept\EntityManager.hpp>
#include <Adept\Mission.hpp>
#include <Adept\Connection.hpp>
#include <Adept\Application.hpp>
#include <MW4\Mech.hpp>
#include <MW4\Vehicle.hpp>
#include <MW4\Building.hpp>
#include <MW4\Turret.hpp>
#include "InstanceWindow.h"
#include "GenericTextDlg.h"
#include "transDlg.h"
#include "DeleteCommand.h"
#include <Adept\Player.hpp>
#include "EditorWaypoint.h"
#include "GenericListDlg.h"
#include <mw4\AI.hpp>
#include <mw4\EffectGenerator.hpp>
#include <Adept\DropZone.hpp>
#include <Adept\NameTable.hpp>
#include <Adept\CollisionGrid.hpp>
#include "LatticeLinkDlg.h"
#include <MW4\CombatAI.hpp>
#include "LightWnd.h"
#include "AblMemDlg.h"
#include "DisplayWindow.h"
#include "OverviewWindow.h"
#include "Selection.h"
#include "editskilldlg.hpp"
#include <mbstring.h>
#define __mbschr(s,c) (char*)_mbschr((const unsigned char*)(s),(c))
#define __mbsrchr(s,c) (char*)_mbsrchr((const unsigned char*)(s),(c))

Entity* CallbackEntity = NULL;
extern CMW4GameEdApp theApp;

bool InstanceEditScriptCallback(char* filename)
{
	if (CallbackEntity)
	{
		ABL::ABLError err;

		MWObject *obj;

		obj = Cast_Object (MWObject *,CallbackEntity);		// should not fail since you should not be able to attach an ai to a non mwobject

		if (!obj->m_AI->LoadScript(filename))
		{
			char errString[256];
			sprintf(errString,"%s on Line %d.",err.String(),err.Line());
			MessageBox(NULL,errString,"ABL Error",MB_OK);
			return false;
		}
	}
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CInstanceWindow

IMPLEMENT_DYNCREATE(CInstanceWindow, CEditorChildWnd)

CInstanceWindow::CInstanceWindow() :
	mechList(NULL),
	buildingList(NULL),
	vehicleList(NULL),
	miscList(NULL)
{
CString title;
	RECT	rect;

	TLDlg = NULL;
	scriptWnd = NULL;

	title.LoadString(IDS_INSTANCEWINDOWTITLE);
	rect.top = 410; rect.left = 650; rect.bottom = 600; rect.right = 900;

	Create(NULL,title,WS_CHILD | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_VISIBLE,rect);//,theApp.m_pMainWnd,0);

}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CInstanceWindow::~CInstanceWindow()
{
	ClearInstanceLists();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BEGIN_MESSAGE_MAP(CInstanceWindow,CEditorChildWnd)
	//{{AFX_MSG_MAP(CInstanceWindow)
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_WM_RBUTTONDOWN()
	ON_COMMAND(ID_OBJ_NAME, OnObjName)
	ON_COMMAND(ID_OBJ_PARAMETERS, OnObjParameters)
	ON_COMMAND(ID_OBJ_TRANSLATION, OnObjTranslation)
	ON_COMMAND(ID_OBJ_REMOVEINSTANCE, OnObjRemoveinstance)
	ON_COMMAND(ID_OBJ_GOTOINSTANCE, OnObjGotoinstance)
	ON_COMMAND(ID_OBJ_DAMAGEOBJARMOR, OnObjDamageobjArmor)
	ON_COMMAND(ID_OBJ_DAMAGEOBJINTERNAL, OnObjDamageobjInternal)
	ON_COMMAND(ID_OBJ_EDITDRIVER, OnObjEditDriver)
	ON_COMMAND(ID_OBJ_SPECIFYSCRIPT, OnObjSpecifyScript)
	ON_COMMAND(ID_OBJ_EDITSCRIPT, OnObjEditScript)
	ON_COMMAND(ID_OBJ_CLEARAI, OnClearAI)
	ON_COMMAND(ID_OBJ_EDITOBJECTIVE, OnObjEditObjective)
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDBLCLK()
	ON_COMMAND(ID_OBJ_ALIGNMENT, OnObjAlignment)
	ON_COMMAND(ID_EDITLIGHT, OnEditLight)
	ON_COMMAND(ID_OBJ_ABLMEMORY, OnABLMemory)
	ON_COMMAND(ID_OBJ_EDITSKILL, OnEditSkill)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CInstanceWindow message handlers


int CInstanceWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CEditorChildWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	TLDlg = new CObjWindow;

	TLDlg->Create(CObjWindow::IDD,this);

	RECT r;
	memset(&r,0,sizeof(r));
	TLDlg->m_ObjList.Create(WS_CHILD | WS_VISIBLE | LBS_EXTENDEDSEL | LBS_NOINTEGRALHEIGHT | LBS_STANDARD,r,TLDlg,0);

	TLDlg->m_TabCtrl.InsertItem(0,TLDlg->mechTab);
	TLDlg->m_TabCtrl.InsertItem(1,TLDlg->buildingTab);
	TLDlg->m_TabCtrl.InsertItem(2,TLDlg->vehicleTab);
	TLDlg->m_TabCtrl.InsertItem(3,TLDlg->miscTab);

	((CButton*)(TLDlg->GetDlgItem(IDC_INSTANCETYPEBTN)))->SetCheck(1);
	TLDlg->GetDlgItem(IDC_INSTANCEALINGMENTBTN)->ShowWindow(SW_SHOW);
	TLDlg->GetDlgItem(IDC_INSTANCETYPEBTN)->ShowWindow(SW_SHOW);
//	TLDlg->GetDlgItem(IDC_MULTIDROP)->ShowWindow(SW_HIDE);
	TLDlg->ShowWindow(SW_SHOW);

	return 0;
}

void CInstanceWindow::OnSize(UINT nType, int cx, int cy)
{
	CEditorChildWnd::OnSize(nType, cx, cy);
	
	if(TLDlg)
	{
		TLDlg->SetWindowPos(NULL,0,0,cx,cy,SWP_NOZORDER);
		TLDlg->m_TabCtrl.SetWindowPos(NULL,0,0,cx,cy,SWP_NOZORDER);	
		RECT r,l,b;
		TLDlg->m_TabCtrl.GetClientRect(&r);
		TLDlg->m_TabCtrl.GetItemRect(0,&l);
		TLDlg->GetDlgItem(IDC_INSTANCETYPEBTN)->GetClientRect(&b);
		TLDlg->m_ObjList.SetWindowPos(NULL,3,l.bottom + 3,r.right - 7,r.bottom - l.bottom - 14 - b.bottom,SWP_NOZORDER);
		CButton* typeButton = (CButton*)(TLDlg->GetDlgItem(IDC_INSTANCETYPEBTN));
		CButton* alignButton = (CButton*)(TLDlg->GetDlgItem(IDC_INSTANCEALINGMENTBTN));
		typeButton->GetWindowRect(&r);
		typeButton->SetWindowPos(NULL,cx / 2 - (r.right - r.left) - 10, cy - 17 - (r.bottom - r.top) / 2,
								 r.right - r.left, r.bottom - r.top, SWP_NOZORDER);
		alignButton->SetWindowPos(NULL,cx / 2 + 10, cy - 17 - (r.bottom - r.top) / 2,
								 r.right - r.left, r.bottom - r.top, SWP_NOZORDER);
	}
}

void CInstanceWindow::FillTabBox(int tab)
{
//	int lastSortType = -1;

	if(theApp.m_editorState != CMW4GameEdApp::NoGameIdleState &&
	   theApp.m_editorState != CMW4GameEdApp::InitializingState)
	{
		if (tab < 0)
			tab = TLDlg->m_TabCtrl.GetCurSel();

		switch(tab)
		{
			case MECH_TAB:
			{
				ChainIteratorOf<TabList*> iterator(&mechList);
				FillTabBox(iterator);
				break;
			}
			case BUILDING_TAB:
			{
				ChainIteratorOf<TabList*> iterator(&buildingList);
				FillTabBox(iterator);
				break;
			}
			case VEHICLE_TAB:
			{
				ChainIteratorOf<TabList*> iterator(&vehicleList);
				FillTabBox(iterator);
				break;
			}
			case MISC_TAB:
			{
				ChainIteratorOf<TabList*> iterator(&miscList);
				FillTabBox(iterator);
				break;
			}
		}
	}
}

void CInstanceWindow::FillTabBox(ChainIteratorOf<TabList*> &iterator)
{
	TLDlg->m_ObjList.ResetContent();
	TabList* item;

	while ((item = iterator.ReadAndNext()) != NULL)
	{
		int index = TLDlg->m_ObjList.AddString(item->itemString);
		TLDlg->m_ObjList.SetItemDataPtr(index,(void*)LPCTSTR(item->data));
	}
}

void CInstanceWindow::ClearInstanceLists()
{
	TabList* current;
	ChainIteratorOf<TabList*> mechIterator(&mechList);
	while((current = mechIterator.GetCurrent()) != NULL)
	{
		mechIterator.Remove();
		mechIterator.First();
		delete current;
	}
	ChainIteratorOf<TabList*> buildingIterator(&buildingList);
	while((current = buildingIterator.GetCurrent()) != NULL)
	{
		buildingIterator.Remove();
		buildingIterator.First();
		delete current;
	}
	ChainIteratorOf<TabList*> vehicleIterator(&vehicleList);
	while((current = vehicleIterator.GetCurrent()) != NULL)
	{
		vehicleIterator.Remove();
		vehicleIterator.First();
		delete current;
	}
	ChainIteratorOf<TabList*> miscIterator(&miscList);
	while((current = miscIterator.GetCurrent()) != NULL)
	{
		miscIterator.Remove();
		miscIterator.First();
		delete current;
	}
}

void CInstanceWindow::ResetInstanceLists()
{
	ClearInstanceLists();

	Check_Object(Map::Instance);
	ChainIteratorOf<Entity *> iterator(&Map::Instance->childEntityChain);
	Entity* entity;

	while((entity = iterator.ReadAndNext()) != NULL)
	{
		if (entity->IsDerivedFrom(EditorLatticeNode::DefaultData) || // && !theApp.m_showLattice) ||
			entity->IsDerivedFrom(Adept::DropZone::DefaultData) ||
			entity->IsDerivedFrom(EditorBoundaryNode::DefaultData) ||
			entity->IsDerivedFrom(MechWarrior4::Objective::DefaultData) ||
			entity->IsDerivedFrom(EditorDropZonePoint::DefaultData) ||
			entity->IsDerivedFrom(EditorPathNode::DefaultData) ||
			entity->IsDerivedFrom(CameraShip::DefaultData) ||
			entity->IsDerivedFrom(MechWarrior4::Path::DefaultData) ||
			entity->IsDerivedFrom(EffectGenerator::DefaultData)
			)
			continue;

		AddInstance(entity,false);
	}
	FillTabBox();
}

BOOL CInstanceWindow::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	if (UINT(wParam) == IDC_OBJECTTAB)
		FillTabBox(((NMHDR*)(lParam))->code);
	
	*pResult = 0;
	
	return CEditorChildWnd::OnNotify(wParam, lParam, pResult);
}

void CInstanceWindow::AddInstance(Entity* entity, bool fill)
{
	Check_Object(entity);

	if (entity->IsDerivedFrom(EditorPathNode::DefaultData) ||
		entity->IsDerivedFrom(Adept::Driver::DefaultData))
	{
		return;
	}

	TabList* newNode = new TabList;

	newNode->itemString = entity->instanceName;
	newNode->itemPath = "";
	newNode->data = DWORD(entity);

	if(entity->IsDerivedFrom(Mech::DefaultData))
	{
		mechList.Add(newNode);
	}
	else if(entity->IsDerivedFrom(Building::DefaultData) || entity->IsDerivedFrom(Turret::DefaultData))
	{
		buildingList.Add(newNode);
	}
	else if(entity->IsDerivedFrom(Vehicle::DefaultData) )
	{
		vehicleList.Add(newNode);
	}
	else
	{
		// BS to make drop nodes transparent to user
		if (entity->IsDerivedFrom(EditorDropNode::DefaultData))
		{
			EditorDropNode* node;
			node = Cast_Object(EditorDropNode*,entity);
			newNode->itemString = node->dropZone->instanceName;
		}
		if (entity->IsDerivedFrom(EditorCameraShip::DefaultData))
		{
			EditorCameraShip* node;
			node = Cast_Object(EditorCameraShip*,entity);
			newNode->itemString = node->cameraShip->instanceName;
		}
//		else if (entity->IsDerivedFrom(MechWarrior4::Objective::DefaultData))
		else if (entity->IsDerivedFrom(EditorObjectiveMarker::DefaultData))
		{
			EditorObjectiveMarker* node;
			node = Cast_Object(EditorObjectiveMarker*,entity);
			newNode->itemString = node->objective->instanceName;
		}
		else if (entity->IsDerivedFrom(EditorMovementPath::DefaultData))
		{
			EditorMovementPath* node;
			node = Cast_Object(EditorMovementPath*,entity);
			newNode->itemString = node->pathSlot.GetCurrent()->instanceName;
		}
		miscList.Add(newNode);
	}
	
	if (fill)
		FillTabBox();
}

void CInstanceWindow::RemoveInstance(Entity* entity)
{
	TabList* current;



	if(entity->IsDerivedFrom(Mech::DefaultData))
	{
			ChainIteratorOf<TabList*> iterator(&mechList);
			while((current = iterator.ReadAndNext()) != NULL)
			{
				if (current->data == DWORD(entity))
				{
					mechList.Remove(current);
					break;
				}
			}
	}
	else if(entity->IsDerivedFrom(Building::DefaultData) || entity->IsDerivedFrom(Turret::DefaultData))
	{
			ChainIteratorOf<TabList*> iterator(&buildingList);
			while((current = iterator.ReadAndNext()) != NULL)
			{
				if (current->data == DWORD(entity))
				{
					buildingList.Remove(current);
					break;
				}
			}
	}
	else if(entity->IsDerivedFrom(Vehicle::DefaultData) )
	{
			ChainIteratorOf<TabList*> iterator(&vehicleList);
			while((current = iterator.ReadAndNext()) != NULL)
			{
				if (current->data == DWORD(entity))
				{
					vehicleList.Remove(current);
					break;
				}
			}
	}
	else
	{
			ChainIteratorOf<TabList*> iterator(&miscList);
			while((current = iterator.ReadAndNext()) != NULL)
			{
				if (current->data == DWORD(entity))
				{
					miscList.Remove(current);
					break;
				}
			}
	}


	FillTabBox();
}

void CInstanceWindow::OnRButtonDown(UINT nFlags, CPoint point)
{
	if (Application::Instance->GetApplicationState()
		== ApplicationStateEngine::RunningGameState &&
		theApp.m_editorState != CMW4GameEdApp::AddingObjectState)
	{
		BOOL outside;
		UINT selected = TLDlg->m_ObjList.ItemFromPoint(point,outside);

		TLDlg->m_ObjList.SetSel(-1,FALSE);
		TLDlg->m_ObjList.SetSel(selected,TRUE);

		Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(selected);
		CMenu menu;

		if (entity->IsDerivedFrom(EditorLight::DefaultData))
		{
			VERIFY(menu.LoadMenu(IDR_LIGHTPOPUP));
		}
		else
		{
			VERIFY(menu.LoadMenu(IDR_OBJECTPOPUP));
		}
		CMenu* pPopup = menu.GetSubMenu(0);
		ASSERT(pPopup != NULL);

		CPoint point;

		GetCursorPos(&point);

		CSelectionList::Instance->ClearSelectionList();
		TLDlg->m_ObjList.ScreenToClient(&point);

		if (entity->IsDerivedFrom(Entity::DefaultData))
		{
			if (entity->IsDerivedFrom(EditorLight::DefaultData))
			{
				if (entity->IsDerivedFrom(EditorPointLight::DefaultData) ||
					entity->IsDerivedFrom(EditorSpotLight::DefaultData))
				{
					pPopup->InsertMenu(-1,MF_BYPOSITION,ID_OBJ_GOTOINSTANCE,"Goto Instance");
				}
			}
			else if ((!entity->IsDerivedFrom(MechWarrior4::Path::DefaultData)) &&
				(!entity->IsDerivedFrom(DropZone::DefaultData)) &&
				!entity->IsDerivedFrom(EditorWaypoint::DefaultData) &&
				!entity->IsDerivedFrom(EditorPathNode::DefaultData) &&
				!entity->IsDerivedFrom(EditorLatticeNode::DefaultData) &&
				!entity->IsDerivedFrom(EditorBoundaryNode::DefaultData) &&
				!entity->IsDerivedFrom(EditorDropNode::DefaultData) &&
				!entity->IsDerivedFrom(EditorDropZonePoint::DefaultData) &&
				!entity->IsDerivedFrom(EditorObjectiveMarker::DefaultData) &&
				!entity->IsDerivedFrom(EditorCameraShip::DefaultData))
			{
				pPopup->InsertMenu(-1,MF_BYPOSITION,ID_OBJ_EDITDRIVER,"Edit Driver...");
				pPopup->InsertMenu(-1,MF_BYPOSITION,ID_OBJ_SPECIFYSCRIPT,"Specify ABL Script...");
				pPopup->InsertMenu(-1,MF_BYPOSITION,ID_OBJ_CLEARAI,"Clear AI Info");
				pPopup->InsertMenu(-1,MF_SEPARATOR);
				pPopup->InsertMenu(-1,MF_BYPOSITION,ID_OBJ_ABLMEMORY,"Edit Memory Cells...");
				pPopup->InsertMenu(-1,MF_BYPOSITION,ID_OBJ_EDITSKILL,"Edit Skills...");
//				pPopup->InsertMenu(-1,MF_BYPOSITION,ID_OBJ_EDITSCRIPT,"Edit ABL Script...");
			}
		}
		if (entity->IsDerivedFrom(EditorObjectiveMarker::DefaultData))
		{
			pPopup->RemoveMenu(ID_OBJ_GOTOINSTANCE,MF_BYCOMMAND);
			pPopup->InsertMenu (-1,MF_BYPOSITION,ID_OBJ_EDITOBJECTIVE,"Edit Objective...");
		}
		if (entity->IsDerivedFrom(Vehicle::DefaultData))
		{
			pPopup->GetSubMenu(0)->InsertMenu(1,MF_BYPOSITION,ID_OBJ_DAMAGEOBJARMOR,"Armor...");
			pPopup->GetSubMenu(0)->InsertMenu(2,MF_BYPOSITION,ID_OBJ_DAMAGEOBJINTERNAL,"Internal...");
			pPopup->GetSubMenu(0)->InsertMenu(3,MF_BYPOSITION,ID_OBJ_SUBSYSTEM,"Subsystems...");
		}
		CSelectionList::Instance->AddSelection(entity);
		TLDlg->m_ObjList.ClientToScreen(&point);
		pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);	// changed back to this line, menu messages where being routed to tldlg,
//		pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, TLDlg);	// but all of the handlers where in this class.
	}
	CEditorChildWnd::OnRButtonDown(nFlags, point);
}

int CInstanceWindow::GetSelectedObject()
{
	int value = -1;

	int selCount = TLDlg->m_ObjList.GetSelCount();
	Verify(selCount == 1);
	int* selected = new int;

	TLDlg->m_ObjList.GetSelItems(1,selected);
	value = *selected;
	delete selected;

	Verify(value >= 0);
	return value;
}

void CInstanceWindow::OnObjName()
{
	ChangeObjName();
}

void CInstanceWindow::ChangeObjName()
{
	int index = GetSelectedObject();

	Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(index);
	Check_Object(entity);

	CGenericTextDlg dlg;
	dlg.m_Title = "Set Object Name";
	dlg.m_MessageText = "Enter the new name of this object";


	if (entity->IsDerivedFrom(EditorDropNode::DefaultData))
	{
		EditorDropNode* node;
		node = Cast_Object(EditorDropNode*,entity);
		entity = node->dropZone;
	}
	if (entity->IsDerivedFrom(EditorCameraShip::DefaultData))
	{
		EditorCameraShip* node;
		node = Cast_Object(EditorCameraShip*,entity);
		entity = node->cameraShip;
	}
	else if (entity->IsDerivedFrom(MechWarrior4::Objective::DefaultData))
	{
		EditorObjectiveMarker* node;
		node = Cast_Object(EditorObjectiveMarker*,entity);
		entity = node->objective;
	}
	else if (entity->IsDerivedFrom(EditorMovementPath::DefaultData))
	{
		EditorMovementPath* node;
		node = Cast_Object(EditorMovementPath*,entity);
		entity = node->pathSlot.GetCurrent();
	}
	else if (entity->IsDerivedFrom(EditorObjectiveMarker::DefaultData))
	{
		EditorObjectiveMarker* node;
		node = Cast_Object(EditorObjectiveMarker*,entity);
		entity =node->objective;
	}

	dlg.m_EditText = entity->instanceName;



	if (dlg.DoModal() == IDOK)
	{
		EntityManager::Instance->GetNameSocket()->Remove(entity);
	
		entity->instanceName = dlg.m_EditText;
		
		EntityManager::Instance->GetNameSocket()->AddValue(entity, entity->instanceName);
/*
		DWORD data = TLDlg->m_ObjList.GetItemData(index);
		TLDlg->m_ObjList.DeleteString(index);
		index = TLDlg->m_ObjList.AddString(entity->instanceName);
		TLDlg->m_ObjList.SetItemData(index,data);
*/
		Check_Object(NameTable::Instance);
		NameTable::Instance->SetName(entity->objectID, entity->instanceName);
		NameTable::Instance->IsValid();
		theApp.MakeObjectNamesUnique();
		ResetInstanceLists();
	}		
}

void CInstanceWindow::OnObjParameters()
{
	Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());
	Check_Object(entity);

	EditEntityDlg edit_dialog(NULL, entity);
	edit_dialog.DoModal();
}

void CInstanceWindow::OnObjTranslation()
{
	Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());
	Check_Object(entity);

	if(!theApp.displayWindow->translationDlg)
	{
		theApp.displayWindow->translationDlg = new CTransDlg;
		Register_Pointer(theApp.displayWindow->translationDlg);
		theApp.displayWindow->translationDlg->Create(CTransDlg::IDD,this);
	}
	theApp.displayWindow->translationDlg->SetObject(entity,theApp.GetEntityData(entity));
	theApp.displayWindow->translationDlg->ShowWindow(SW_SHOW);
}

void CInstanceWindow::OnObjRemoveinstance()
{
	theApp.currentCommand = new DeleteCommand();	
	Register_Object(theApp.currentCommand);
	CSelectionList::Instance->ClearSelectionList(false);
	theApp.m_editorState = CMW4GameEdApp::SelectingObjectState;
	theApp.undoChain.Add(theApp.currentCommand);
	theApp.currentCommand = NULL;
	theApp.toolBar->EnableButton(ID_EDIT_UNDO);
}

void CInstanceWindow::OnObjGotoinstance()
{

	Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());

	if (entity->IsDerivedFrom(EditorMovementPath::DefaultData))
	{
		EditorMovementPath* path;
		path = Cast_Object(EditorMovementPath*,entity);
		ChainIteratorOf<EditorPathNode*> iterator(&path->pathNodes);
		entity = iterator.GetCurrent();
	}
	Check_Object(entity);

	LinearMatrix4D matrix;
	Point3D newPoint;
	YawPitchRoll newOrientation;

  //
  // Get the current angle and position above ground for the camera and figure out where to place the camera when we set focus
  //
	LinearMatrix4D oldCameraMatrix;
	Point3D oldCameraPosition;
	YawPitchRoll oldCameraOrientation;
  Point3D intersectCameraWithGround;

	oldCameraMatrix= Player::Instance->GetLocalToWorld();
  oldCameraOrientation = oldCameraMatrix;
  oldCameraPosition = oldCameraMatrix;


  // cast a line from this point to the ground or object in center of view, in the current direction and get the distance.
	Adept::Entity *entity_hit = NULL;
	Stuff::Line3D line;

	line.m_length = 1000.0f;
  oldCameraMatrix.GetLocalForwardInWorld(&(line.m_direction));
	line.SetOrigin(oldCameraPosition);

	Stuff::Normal3D inormal;
	Stuff::Line3D iline;
	Stuff::Normal3D normal;

  Check_Object(CollisionGrid::Instance);
	
  Entity::CollisionQuery query(&line, &normal, Adept::Entity::CanBeWalkedOnFlag, NULL);

  entity_hit = CollisionGrid::Instance->ProjectLine(&query);
  //
  // If the camera is facing anything it can collide with like the ground or an object within 1000M we have a distance for the camera
  //
  if (entity_hit)
  {
		line.FindEnd(&intersectCameraWithGround);
    // now we have an intersection distance in line
    matrix = entity->GetLocalToWorld();
    newPoint = matrix;
    newOrientation = oldCameraOrientation;

    if (newPoint.x < -(theApp.displayWindow->mapX*0.5f))
		  newPoint.x = 1.0f;
	  else if (newPoint.x > (theApp.displayWindow->mapX*0.5f))
		  newPoint.x = (theApp.displayWindow->mapX*0.5f) - 1.0f;

	  if (newPoint.z < -(theApp.displayWindow->mapZ*0.5f))
		  newPoint.z = 1.0f;
	  else if (newPoint.z > (theApp.displayWindow->mapZ*0.5f))
		  newPoint.z = (theApp.displayWindow->mapZ*0.5f) - 1.0f;

    //
    // reverse the direction of the line that we used to get the position of the camera from the nearest obstacle
    // then we can use this line to position the camera relative to the entity we are going to
    //
	line.m_direction.Negate(line.m_direction);
    line.SetOrigin(newPoint);
    line.FindEnd(&newPoint);
    // newPoint should now be where we want the camera
  }
  else
    //
    // This is the old code. If for some reason the camera isn't pointing at anything (up, horizontal, etc...)
    // then we will just rely on the old positioning code.
    //
  {
    matrix = entity->GetLocalToWorld();
	  newPoint = matrix;
	  newOrientation = matrix;

	  newPoint.z -= Cos(newOrientation.yaw) * 25;
	  newPoint.x -= Sin(newOrientation.yaw) * 25;

	  if (newPoint.x < 0)
		  newPoint.x = 1.0f;
	  else if (newPoint.x > theApp.displayWindow->mapX)
		  newPoint.x = theApp.displayWindow->mapX - 1.0f;

	  if (newPoint.z < 0)
		  newPoint.z = 1.0f;
	  else if (newPoint.z > theApp.displayWindow->mapZ)
		  newPoint.z = theApp.displayWindow->mapZ - 1.0f;

	  line.m_length = 1000.0f;
	  line.m_direction = Vector3D::Down;

	  Check_Object(CollisionGrid::Instance);

	  newPoint.y = 600;
	  line.SetOrigin(newPoint);
	  Entity::CollisionQuery query(&line, &normal, Entity::AlwaysCollidesMask, NULL);
	  entity_hit = CollisionGrid::Instance->ProjectLine(&query);

	  while (entity_hit)
	  {
		  newPoint.z -= 25.0f;
		  line.SetOrigin(newPoint);
		  Entity::CollisionQuery query(&line, &normal, Entity::AlwaysCollidesMask, NULL);
		  entity_hit = CollisionGrid::Instance->ProjectLine(&query);
	  }
	  Verify(newPoint.z >= 1.0f);
	
	  newPoint.y = theApp.displayWindow->GetMapPointVertical(newPoint.x,newPoint.z);

  }

  matrix.BuildTranslation(newPoint);
	matrix.BuildRotation(newOrientation);
	Player::Instance->SetNewLocalToParent(matrix);
	Player::Instance->SyncMatrices(true);
	theApp.overviewWindow->DrawWindow();

}

void CInstanceWindow::CheckHiddenObject(Entity* entity)
{
	if (TLDlg->m_TabCtrl.GetCurSel() == 3)
	{
		if (entity->IsDerivedFrom(EditorMovementPath::DefaultData))
		{
			theApp.m_showPaths = false;
			theApp.OnToolsMovmentlayerShowpaths();
		}
		else if (entity->IsDerivedFrom(EditorDropNode::DefaultData))
		{
			theApp.m_showDropZones = false;
			theApp.OnToolsMovmentlayerShowdropzones();
		}
		else if (entity->IsDerivedFrom(EditorObjectiveMarker::DefaultData))
		{
			theApp.m_showAI = false;
			theApp.OnToolsMovmentlayerShowobjectives();
		}
	}
}

void CInstanceWindow::OnLButtonUp(UINT nFlags, CPoint point)
{
	if (theApp.m_editorState == CMW4GameEdApp::MovingObjectState)
		return;

	int selCount = TLDlg->m_ObjList.GetSelCount();
	int* selected = new int [selCount];

	TLDlg->m_ObjList.GetSelItems(selCount,selected);

	CSelectionList::Instance->ClearSelectionList();
	for (int i = 0; i < selCount; i++)
	{
		Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(selected[i]);
		CSelectionList::Instance->AddSelection(entity);
		CheckHiddenObject(entity);
	}

	if (theApp.displayWindow->translationDlg->IsWindowVisible())
	{
		if (selCount == 1)
		{
			Entity *tmpentity=(Entity*)TLDlg->m_ObjList.GetItemData(selected[0]);
			theApp.displayWindow->translationDlg->SetObject(tmpentity,theApp.GetEntityData(tmpentity));
		}
		else
		{
			theApp.displayWindow->translationDlg->ShowWindow(SW_HIDE);
		}
	}
	delete [] selected;

	CEditorChildWnd::OnLButtonUp(nFlags, point);
}

void CInstanceWindow::ResetSel()
{
	TLDlg->m_ObjList.SetSel(-1,FALSE);

	ChainIteratorOf<CSelectionNode*> iterator(&CSelectionList::Instance->selectionList);
	CSelectionNode* selection;

	while ((selection = iterator.ReadAndNext()) != NULL)
	{
		int index = TLDlg->m_ObjList.FindStringExact(0,selection->selectedEntity->instanceName);
		
		if (index != LB_ERR)
			TLDlg->m_ObjList.SetSel(index);
	}
}

void CInstanceWindow::OnObjDamageobjArmor()
{
	Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());
	Check_Object(entity);

	EditEntityDlg edit_dialog(NULL,entity,EDIT_DAMAGE_OBJECTARMOR);
	edit_dialog.DoModal();
}

void CInstanceWindow::OnObjDamageobjInternal()
{
	Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());
	Check_Object(entity);

	EditEntityDlg edit_dialog(NULL,entity,EDIT_DAMAGE_OBJECTINTERNAL);
	edit_dialog.DoModal();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void EditObjective (Entity *entity);
void CInstanceWindow::OnObjEditObjective()
{
	EditObjective ((Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject()));
}

void EditAIDriver (Entity *entity);
void CInstanceWindow::OnObjEditDriver()
{
	EditAIDriver ((Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject()));
}

void CInstanceWindow::OnObjSpecifyScript()
{
	Entity* entity;
	entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());

	OnObjSpecifyScript(entity);
}

void CInstanceWindow::OnObjSpecifyScript(Entity* entity)
{
	MWObject *obj;

	if (!entity->IsDerivedFrom (MWObject::DefaultData))
	{
		MessageBox("Object is not derived from MWobject","not MWObject");	// localize
		return;
	}

	obj = Cast_Object (MWObject *,entity);	

	if (obj->m_AI == NULL)
	{
		MessageBox("You must attach a driver first.","Driver Not Found");	// localize
		return;
	}

	char scriptPath[MAX_PATH],oldDir[MAX_PATH];
	OPENFILENAME ofn;

	_getcwd(oldDir,MAX_PATH - 1);

	memset(&scriptPath,0,MAX_PATH);
	memset(&ofn,0,sizeof(ofn));

	if (obj->m_AI->GetScriptName())
	{
		char *p,tmp[MAX_PATH];
		strncpy(tmp,obj->m_AI->GetScriptName(),MAX_PATH);
		p = __mbsrchr(tmp,'\\');
		if (p)
			strncpy(scriptPath,++p,MAX_PATH);
	}

	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = NULL;
	ofn.lpstrFilter = "ABL files {*.ABL}\0*.abl\0All Files {*.*}\0*.*\0\0";
	ofn.lpstrFile = scriptPath;
	ofn.nMaxFile = MAX_PATH;
	ofn.Flags = OFN_FILEMUSTEXIST;
	ofn.lpstrDefExt = "abl";

	char path[MAX_PATH],*p;
	strcpy(path,theApp.missionFileName);
	p = __mbsrchr(path,'\\');
	*p = 0;
	strcat(path,"\\Scripts");
	if (_chdir(path) != 0)
	{
		if (!CreateDirectory(path,NULL))	
		{
			DWORD err = GetLastError();
			sprintf(path,"Could not create Scripts directory. Error %d",err);
			MessageBox(path,"File Error");	// localize
			return;
		}
		if (_chdir(path) != 0)
		{
			DWORD err = GetLastError();
			sprintf(path,"Could not find Scripts directory. Error %d",err);
			MessageBox(path,"File Error");	// localize
			return;
		}
	}

	if (GetOpenFileName(&ofn))
	{
		_chdir(oldDir);
		char path_buffer[_MAX_PATH],drive[_MAX_DRIVE],dir[_MAX_DIR],fname[_MAX_FNAME],ext[_MAX_EXT];

		_splitpath(ofn.lpstrFile,drive,dir,fname,ext);
		p = __mbsrchr(dir,'\\');
		*p = 0;
		p = __mbschr(dir,'\\');
		p++;
		p = __mbschr(p,'\\');
		p++;

		if (stricmp(strstr(p,"Content"),strstr(path,"Content")) != 0)
		{
			sprintf(path_buffer,"%s\\%s%s",path,fname,ext);
			if (!CopyFile(ofn.lpstrFile,path_buffer,TRUE))
			{
				DWORD err = GetLastError();
				if (err == 80)	// file exists
				{
					if (MessageBox("A file of that name already exists in the mission script folder.  Do you wish to overwrite that file?","File Error",MB_YESNO) == IDYES)
						CopyFile(ofn.lpstrFile,path_buffer,FALSE);
				}
				else
				{
					sprintf(path,"Could not copy ABL file to current mission folder. Error %d",err);
					MessageBox(path,"File Error");	// localize
					return;
				}
			}
			if (!SetFileAttributes(path_buffer,FILE_ATTRIBUTE_NORMAL))
			{
				DWORD err = GetLastError();
				sprintf(path,"Could not clear readonly flag on ABL file in current mission folder, please do so yourself. Error %d",err);
				MessageBox(path,"File Error");	// localize
				return;
			}
		}
		else
			strcpy(path_buffer,ofn.lpstrFile);

		if (obj->m_AI)
		{
			ABL::ABLError err;
			if (!obj->m_AI->LoadScript(strstr(path_buffer,"Content")))
			{
				char errString[256];
				sprintf(errString,"%s on Line %d.",err.String(),err.Line());
				MessageBox(errString,"ABL Error");
				ObjEditScript(path_buffer,err.Line());
			}
		}
		else
		{
			ABL::ABLError err;
			AI* ai;
			ai = Cast_Object(AI*,entity);

			ai->LoadScript(ofn.lpstrFile);
		}
	}
	_chdir(oldDir);
}

void CInstanceWindow::OnObjEditScript()
{
	ObjEditScript();
}

void CInstanceWindow::ObjEditScript(char* file, int line)
{
	line -= 1;
	Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());

	MWObject *obj;

	if (!entity->IsDerivedFrom (MWObject::DefaultData))
	{
		MessageBox("Object is not derived from MWobject","not mwobject");	// localize
		return;
	}

	obj = Cast_Object (MWObject *,entity);	

	if (obj->m_AI == NULL)
	{
		MessageBox("You must attach a driver first.","Driver Not Found");	// localize
		return;
	}

	char scriptPath[MAX_PATH];

	if (file)
		strncpy(scriptPath,file,MAX_PATH - 1);
	else
		strncpy(scriptPath,obj->m_AI->GetScriptName(),MAX_PATH - 1);

	if (!scriptWnd)
	{
		scriptWnd = new CEditWnd(scriptPath);
		RECT r;
		r.left = 50;
		r.top = 50;
		r.right = 690;
		r.bottom = 530;
		scriptWnd->Create(NULL,"AI Script",NULL,r);
	}
	else if (file)
	{
		scriptWnd->LoadFile(file);
		scriptWnd->SetWindowText("AI Script");
	}
	scriptWnd->ShowWindow(SW_SHOW);
	scriptWnd->BringWindowToTop();

	scriptWnd->editWnd.LineScroll(line - scriptWnd->editWnd.GetFirstVisibleLine());
	POINT p;
	p.x = p.y = 50;
	SetCaretPos(p);
	ShowCaret();
	scriptWnd->editWnd.SetScrollPos(SB_VERT,scriptWnd->editWnd.GetFirstVisibleLine());
	scriptWnd->editWnd.SetSel(scriptWnd->editWnd.LineIndex(line),scriptWnd->editWnd.LineIndex(line) + scriptWnd->editWnd.LineLength(line));
	CallbackEntity = entity;
	scriptWnd->CloseCallback = InstanceEditScriptCallback;
}

void CInstanceWindow::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	if (!TLDlg->m_ObjList.GetSelCount())
		return;

	Entity* entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());
	CheckHiddenObject(entity);

	if (entity->IsDerivedFrom(EditorMovementPath::DefaultData) ||
		entity->IsDerivedFrom(EditorAmbientLight::DefaultData) ||
		entity->IsDerivedFrom(EditorInfiniteLight::DefaultData))
	{
		MessageBox("Cannot move that type of object","Move Error");		// localize
	}
	else
	{
		theApp.m_editorState = CMW4GameEdApp::MovingObjectState;
		theApp.currentCommand = new MoveCommand(entity);
		CSelectionList::Instance->RemoveCollision();
		Register_Object(theApp.currentCommand);

		if (CSelectionList::Instance->GetSelectionCount() > 1 &&
			theApp.displayWindow->translationDlg->IsWindowVisible())
			theApp.displayWindow->translationDlg->ShowWindow(SW_HIDE);

		if (CSelectionList::Instance->GetSelectionCount() > 1 &&
			theApp.displayWindow->latticeLinkDlg->IsWindowVisible())
			theApp.displayWindow->latticeLinkDlg->ShowWindow(SW_HIDE);
	}

//	CEditorChildWnd::OnLButtonDblClk(nFlags, point);
}

void CInstanceWindow::OnObjAlignment()
{
	theApp.displayWindow->OnObjAlignment((Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject()));
}

void CInstanceWindow::OnEditLight()
{
	EditorLight* editorLight = (EditorLight*) TLDlg->m_ObjList.GetItemData(GetSelectedObject());

	theApp.CreateLightDlg();
	theApp.lightDlg->SetLight(editorLight);
	theApp.lightDlg->ShowWindow(SW_SHOW);
}

void CInstanceWindow::OnClearAI()
{
	Entity* entity;
	entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());

	OnClearAI(entity);
}

void CInstanceWindow::OnClearAI(Entity* entity)
{
	MWObject *obj;

	obj = Cast_Object (MWObject *,entity);

	if (obj->m_AI)
	{
		NameTable::Instance->RemoveEntry(obj->m_AI->objectID);
		NameTable::Instance->IsValid();
		obj->m_AI->SentenceToDeathRow();
		obj->m_AI = NULL;	// clear the driver
	}
}

void CInstanceWindow::OnABLMemory()
{
	Entity* entity;
	entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());

	OnABLMemory(entity);
}

void CInstanceWindow::OnABLMemory(Entity* entity)
{
	MWObject *obj;

	if (!entity->IsDerivedFrom (MWObject::DefaultData))
	{
		MessageBox("Object is not derived from MWobject","not mwobject");	// localize
		return;
	}

	obj = Cast_Object (MWObject *,entity);	

	if (obj->m_AI == NULL)
	{
		MessageBox("You must attach a driver first.","Driver Not Found");	// localize
		return;
	}

	AblMemDlg dlg(entity);
	dlg.DoModal();
}

void CInstanceWindow::OnEditSkill()
{
	Entity* entity;
	entity = (Entity*)TLDlg->m_ObjList.GetItemData(GetSelectedObject());

	OnEditSkill(entity);
}

void CInstanceWindow::OnEditSkill(Entity* entity)
{
	MWObject *obj;

	if (!entity->IsDerivedFrom (MWObject::DefaultData))
	{
		MessageBox("Object is not derived from MWobject","not mwobject");	// localize
		return;
	}

	obj = Cast_Object (MWObject *,entity);	

	if (obj->m_AI == NULL)
	{
		MessageBox("You must attach a driver first.","Driver Not Found");	// localize
		return;
	}

	EditSkillsDlg dlg(entity);
	dlg.DoModal();
}