//
// Tools_Vertex_Selection.cpp
//
// Created by Richard Rice - 27/01/04
// 
// Copyright (C) 2004 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "Misc/Tools_Vertex_Selection.h"


#include "Rendering/Asura_Module.h"
#include "Mesh/Asura_Mesh.h"
#include "Mesh/Asura_Mesh_System.h"
#include "Interface/Asura_Overlay_System.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Interface.h"
#include "Interface/Asura_Cursor.h"
#include "Core/Asura_Timers.h"
#include "Core/Asura_UserInput.h"
#include "Rendering/Asura_Viewport.h"
#include "Camera/Asura_Camera.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Load&Save/Tools_ModeDataFile.h"
#include "Misc/Tools_LOS.h"
//#include "Misc/Tools_Adjacency.h"
//#include "Texturing/Tools_Texturing_Find.h"
#include "Misc/Tools_Prompted_Selection.h"


#include "Debugging/Asura_Assert.h"

#include "Tools_Overlays.h"
#include "Misc/Tools_Help.h"

#include "Misc/Tools_Adjacency.h"
#include "Misc/Tools_Render.h"
#include "Misc/Tools_Render_Options.h"

///////////////////////////////////////////////////////////////////////////////////////
/*--------------**
** Help Strings **
**--------------*/

static const char* g_apszVertexSelectionHelpStrings [] =
{
	"LMB :         Select vertex",
	"Shift+LMB :   Deselect vertex",
	"",
	"L :           Clear selection",
	"",
	"Shift+Z :     Undo selection",
	"Shift+Y :     Redo selection",
	"Shift+< :     Undo selection",
	"Shift+> :     Redo selection",
	NULL,
};



////////////////////////////////////////////////////////////////////////////////////////
/*----------------------**
** VertexSelectionList **
**----------------------*/

VertexSelectionList::VertexSelectionList(int iModule,int iNumVert)
:ItemSelectionList(iNumVert)
{
	m_iModuleIndex = iModule;
}


void VertexSelectionList::ItemBeingSelected(int iIndex)
{
	Tools_Vertex_Selection::s_xSelectionUndo.LogVertexSelected(m_iModuleIndex,iIndex);
}

void VertexSelectionList::ItemBeingDeselected(int iIndex)
{
	Tools_Vertex_Selection::s_xSelectionUndo.LogVertexDeselected(m_iModuleIndex,iIndex);
}


////////////////////////////////////////////////////////////////////////////////////////
/*----------------------**
** VertexSelectionUndo **
**----------------------*/

void VertexSelectionUndo::ProcessUndoData(void* pData)
{
	VertexSelectionUndoData* pxUndoData = (VertexSelectionUndoData*) pData;
	
	switch(pxUndoData->m_eUndoType)
	{
		case VertexSelectionUndoData::UndoType_Added :
			//deselect the polygon
			Tools_Vertex_Selection::DeselectVertex(pxUndoData->m_iModuleIndex,pxUndoData->m_iVertexIndex);
			//convert the undo data
			pxUndoData->m_eUndoType = VertexSelectionUndoData::UndoType_Removed;
			break;


		case VertexSelectionUndoData::UndoType_Removed :
			//select the polygon
			Tools_Vertex_Selection::SelectVertex(pxUndoData->m_iModuleIndex,pxUndoData->m_iVertexIndex);
			//convert the undo data
			pxUndoData->m_eUndoType = VertexSelectionUndoData::UndoType_Added;
			break;

		default :
			Asura_Assert(0,"Unexpected undo type for vertex selection");
			break;
	}
}

void VertexSelectionUndo::LogVertexSelected(int iModule,int iVertex)
{
	VertexSelectionUndoData* pxUndo = (VertexSelectionUndoData*) AllocateNextUndoData();
	if(!pxUndo) return;

	pxUndo->m_eUndoType = VertexSelectionUndoData::UndoType_Added;
	pxUndo->m_iModuleIndex = iModule;
	pxUndo->m_iVertexIndex = iVertex;
}

void VertexSelectionUndo::LogVertexDeselected(int iModule,int iVertex)
{
	VertexSelectionUndoData* pxUndo = (VertexSelectionUndoData*) AllocateNextUndoData();
	if(!pxUndo) return;

	pxUndo->m_eUndoType = VertexSelectionUndoData::UndoType_Removed;
	pxUndo->m_iModuleIndex = iModule;
	pxUndo->m_iVertexIndex = iVertex;
}

////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------**
** Tools_Vertex_Selection **
**-------------------------*/

//static member variables
int 					Tools_Vertex_Selection::s_iNumberOfModules;
int 					Tools_Vertex_Selection::s_iNumSelectedModules;
VertexSelectionList** 	Tools_Vertex_Selection::s_ppxSelection = NULL;
VertexSelectionUndo	Tools_Vertex_Selection::s_xSelectionUndo;
bool 					Tools_Vertex_Selection::s_bSelectionLocked;
bool 					Tools_Vertex_Selection::s_bShowSelection;
int 					Tools_Vertex_Selection::s_iSelectionMode;
int 					Tools_Vertex_Selection::s_iSelectionModeListOffset;
int 					Tools_Vertex_Selection::s_iCurrentIterationModule;

bool 					Tools_Vertex_Selection::s_bButtonDownForSelection;
Asura_Vector_2			Tools_Vertex_Selection::s_xSelectionOverlayPosition = Asura_Vector_2(3.0f,6.0f);
bool					Tools_Vertex_Selection::s_bSelectionOverlayOpen;
u_int					Tools_Vertex_Selection::s_uSelectionOverlayMinimised = 0;
ModuleVertexPair 				Tools_Vertex_Selection::s_xHighlitVertex;//vertex mouse is currently over
PolygonID 				Tools_Vertex_Selection::s_xHighlitPolygon;//polygon mouse is currently over
bool					Tools_Vertex_Selection::s_bActive = false;

bool					Tools_Vertex_Selection::s_bShowLooseVertices = false;


void Tools_Vertex_Selection::Initialise()
{
	Asura_Assert(!s_ppxSelection,"Vertex selection has alreadt been initialised");

	
	s_iNumberOfModules = Asura_Module_System::GetNumberOfModules();

	//allocate a VertexSelectionList for each module
	s_ppxSelection=new VertexSelectionList*[s_iNumberOfModules];
	for(int i=0;i<s_iNumberOfModules;i++)
	{
		//get the mesh so we can find the number vertices
		Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
		Asura_Assert(pxMesh,"Failed to get the mesh for the module");
		
		s_ppxSelection[i]=new VertexSelectionList(i,pxMesh->NumberOfVertices);
	}
	s_bSelectionLocked = false;
	s_bShowSelection = true;
	s_iSelectionMode = VSelectionMode_Vertex;
	s_iSelectionModeListOffset = 0;
	s_iNumSelectedModules = 0;
	s_bButtonDownForSelection = false;
	s_xHighlitVertex.iModuleIndex = -1;
	s_xHighlitPolygon.ModuleIndex = -1;

	//load values from .dat file
	TransferModeData(TOOLSMODEDATAFILE_LOAD);
	
	s_bSelectionOverlayOpen = true;

	s_xSelectionUndo.Initialise();
}

void Tools_Vertex_Selection::Shutdown()
{

	//save values to .dat file
	TransferModeData(TOOLSMODEDATAFILE_SAVE);
	
	for(int i=0;i<s_iNumberOfModules;i++)
	{
		delete s_ppxSelection[i];
	}
	delete [] s_ppxSelection;
	s_ppxSelection = NULL;

	s_xSelectionUndo.Shutdown();


}

void Tools_Vertex_Selection::Activate()
{
	s_bActive = true;

	s_xHighlitVertex.iModuleIndex = -1;
	s_xHighlitPolygon.ModuleIndex = -1;

	CreateSelectionOverlay();

	//add help
	Tools_Help::AddHelpTopic("Vertex Selection",g_apszVertexSelectionHelpStrings);
}

void Tools_Vertex_Selection::Deactivate()
{
	Tools_Help::RemoveHelpTopic("Vertex Selection");
	CloseSelectionOverlay();

	s_bActive = false;
}

void Tools_Vertex_Selection::TransferModeData(int mode)
{
	//open the file
	Tools_ModeDataFile file("VertexSelection.dat",mode);

	//tranfer the data
	//(none of these should be removed , and new data should go on the end, otherwise
	//the files will get screwed up)
	bool bJunk = false;
	if( false == file.GetError())
	{
		file.Transfer(s_xSelectionOverlayPosition);
		file.Transfer(bJunk);
		file.Transfer(s_uSelectionOverlayMinimised);
	}
}


void Tools_Vertex_Selection::Update(int eUpdateMode /*= VertexSelectionUpdate_Standard*/)
{

	//Flag the selection undo to start a new undo batch
	s_xSelectionUndo.MarkUndoStart();

	//if the mouse button has been release , reset the ButtonHeldForSelection flag
	if(!Asura_UserInput::KeyPressed(ASURA_KEYID_MOUSEBUTTON1))
	{
		s_bButtonDownForSelection = false;
	}

	//reset the highlit vertex
	s_xHighlitVertex.iModuleIndex = -1;
	s_xHighlitPolygon.ModuleIndex = -1;
	
	if(eUpdateMode != VertexSelectionUpdate_NoSelection && !Tools_Prompted_Selection::IsSelecting())
	{
		//act upon keyboard input
		HandleKeyboard();

		if(eUpdateMode == VertexSelectionUpdate_Standard)
		{
			//and handle selection using the mouse
			HandleMouseSelection();
		}
	}
	
}

void Tools_Vertex_Selection::Render()
{

	if(s_bShowLooseVertices)
	{
		for(int i=0;i<s_iNumberOfModules;i++)
		{
			int iNumLoose = Tools_Adjacency::GetNumLooseVertices(i);
			for(int j=0;j<iNumLoose;j++)
			{
				Tools_Render::RenderVertexOutline(i,Tools_Adjacency::GetLooseVertex(i,j),0xff0000ff);
			}
		}
	}

	//Show the currently selected polygons
	if(s_bShowSelection)
	{
		HighlightSelection();
	}

	if(s_iSelectionMode == VSelectionMode_Polygon)
	{
		if(s_xHighlitPolygon.ModuleIndex>=0)
		{
			HighlightPolygon(s_xHighlitPolygon);
		}
	}
	else
	{
		if(s_xHighlitVertex.iModuleIndex>=0)
		{
			HighlightVertex(s_xHighlitVertex);
		}
	}

}


void Tools_Vertex_Selection::SelectVertex(int iModuleIndex,int iVertexIndex)
{
	Asura_Assert(iModuleIndex>=0 && iModuleIndex<s_iNumberOfModules,"Module index out of bounds");
	Asura_Assert(s_ppxSelection,"Selection handling not properly initalised");
	
	if(s_bSelectionLocked) return;

	
	//mark this vertex as selected in the list for the module
	if(!s_ppxSelection[iModuleIndex]->NumSelected())
	{
		s_iNumSelectedModules++;
	}
	s_ppxSelection[iModuleIndex]->Add(iVertexIndex);
}

void Tools_Vertex_Selection::DeselectVertex(int iModuleIndex,int iVertexIndex)
{
	Asura_Assert(iModuleIndex>=0 && iModuleIndex<s_iNumberOfModules,"Module index out of bounds");
	Asura_Assert(s_ppxSelection,"Selection handling not properly initalised");

	if(s_bSelectionLocked) return;

	//mark this vertex as deselected in the list for the module
	if(s_ppxSelection[iModuleIndex]->IsSelected(iVertexIndex))
	{
		s_ppxSelection[iModuleIndex]->Remove(iVertexIndex);
		if(!s_ppxSelection[iModuleIndex]->NumSelected())
		{
			s_iNumSelectedModules--;
		}
	}
}

void Tools_Vertex_Selection::SelectPolygon(int iModuleIndex,int iPolygonIndex)
{
	Asura_Assert(iModuleIndex>=0 && iModuleIndex<s_iNumberOfModules,"Module index out of bounds");
	Asura_Assert(s_ppxSelection,"Selection handling not properly initalised");

	Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(iModuleIndex);
	Asura_Assert(iPolygonIndex>=0 && iPolygonIndex<pxMesh->NumberOfPolygons,"");

	Asura_Mesh_Polygon* pxPoly = &pxMesh->PolygonDataPtr[iPolygonIndex];
	for(int i=0;i<pxPoly->NumberOfVertices();i++)
	{
		SelectVertex(iModuleIndex,pxPoly->VertexID[i]);
	}
}

void Tools_Vertex_Selection::DeselectPolygon(int iModuleIndex,int iPolygonIndex)
{
	Asura_Assert(iModuleIndex>=0 && iModuleIndex<s_iNumberOfModules,"Module index out of bounds");
	Asura_Assert(s_ppxSelection,"Selection handling not properly initalised");

	Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(iModuleIndex);
	Asura_Assert(iPolygonIndex>=0 && iPolygonIndex<pxMesh->NumberOfPolygons,"");

	Asura_Mesh_Polygon* pxPoly = &pxMesh->PolygonDataPtr[iPolygonIndex];
	for(int i=0;i<pxPoly->NumberOfVertices();i++)
	{
		DeselectVertex(iModuleIndex,pxPoly->VertexID[i]);
	}
}


void Tools_Vertex_Selection::SelectObject(int iModuleIndex)
{
	Asura_Assert(iModuleIndex>=0 && iModuleIndex<s_iNumberOfModules,"Module index out of bounds");
	Asura_Assert(s_ppxSelection,"Selection handling not properly initalised");
	
	if(s_bSelectionLocked) return;

	int iNumSelectedBefore = s_ppxSelection[iModuleIndex]->NumSelected();

	for(int i=0;i<s_ppxSelection[iModuleIndex]->NumItems();i++)
	{
 		s_ppxSelection[iModuleIndex]->Add(i);
	}

	if(!iNumSelectedBefore && s_ppxSelection[iModuleIndex]->NumSelected())
	{
		s_iNumSelectedModules++;
	}

}

void Tools_Vertex_Selection::DeselectObject(int iModuleIndex)
{
	Asura_Assert(iModuleIndex>=0 && iModuleIndex<s_iNumberOfModules,"Module index out of bounds");
	Asura_Assert(s_ppxSelection,"Selection handling not properly initalised");

	if(s_bSelectionLocked) return;

	//clear the selection list for the module
	if(s_ppxSelection[iModuleIndex]->NumSelected())
	{
		s_ppxSelection[iModuleIndex]->ClearList();
		
		s_iNumSelectedModules--;

	}
}




void Tools_Vertex_Selection::SelectAll()
{
	if(s_bSelectionLocked) return;
	for(int i=0;i<s_iNumberOfModules;i++)
	{
		SelectObject(i);
	}
}

void Tools_Vertex_Selection::DeselectAll()
{
	Asura_Assert(s_ppxSelection,"Selection handling not properly initalised");
	if(s_bSelectionLocked) return;

	for(int i=0;i<s_iNumberOfModules;i++)
	{
		s_ppxSelection[i]->ClearList();
	}
	s_iNumSelectedModules = 0;
}

int Tools_Vertex_Selection::GetNumberOfSelectedVertices()
{
	int iCount = 0;
	for(int i=0;i<s_iNumberOfModules;i++)
	{
		iCount += s_ppxSelection[i]->NumSelected();
	}
	return iCount;

}


void Tools_Vertex_Selection::StartIteration()
{
	//locate the first module with anything selected
	for(s_iCurrentIterationModule = 0;s_iCurrentIterationModule<s_iNumberOfModules;s_iCurrentIterationModule++)
	{
		if(s_ppxSelection[s_iCurrentIterationModule]->NumSelected())
		{
			s_ppxSelection[s_iCurrentIterationModule]->StartIteration();
			return;
		}
	}
}

bool Tools_Vertex_Selection::GetNextSelected(ModuleVertexPair* pxVertex)
{
	if(s_iCurrentIterationModule >= s_iNumberOfModules) return false;

	//get the current entry from the iteration
	pxVertex->iModuleIndex = s_iCurrentIterationModule;
	pxVertex->iVertexIndex = s_ppxSelection[s_iCurrentIterationModule]->Current();

	//now need to move the iteration on to the next selected entry
	s_ppxSelection[s_iCurrentIterationModule]->Next();
	if(s_ppxSelection[s_iCurrentIterationModule]->Done())
	{
		//done with that module , move onto the next module
		for(s_iCurrentIterationModule++;s_iCurrentIterationModule<s_iNumberOfModules;s_iCurrentIterationModule++)
		{
			if(s_ppxSelection[s_iCurrentIterationModule]->NumSelected())
			{
				s_ppxSelection[s_iCurrentIterationModule]->StartIteration();
				break;
			}
		}
	}
	return true;
}



bool Tools_Vertex_Selection::IsSelected(const ModuleVertexPair& xVertex)
{
	Asura_Assert(s_ppxSelection,"Selection handling not properly initalised");
	Asura_Assert(xVertex.iModuleIndex>=0 && xVertex.iModuleIndex<s_iNumberOfModules,"Module index out of bounds");
	
	return s_ppxSelection[xVertex.iModuleIndex]->IsSelected(xVertex.iVertexIndex);
	
}

int Tools_Vertex_Selection::CountSelectedInModule(int iModuleIndex)
{
	Asura_Assert(iModuleIndex>=0 && iModuleIndex<s_iNumberOfModules,"Module index out of bounds");
	
	return s_ppxSelection[iModuleIndex]->NumSelected();
}


void Tools_Vertex_Selection::HighlightSelection()
{
	Asura_Assert(s_ppxSelection,"Selection handling not properly initalised");

 
	//iterate through selected vertices , giving them a red outline
	for(int i=0;i<s_iNumberOfModules;i++)
	{
		if(s_ppxSelection[i]->NumSelected())
		{
			for(s_ppxSelection[i]->StartIteration();!s_ppxSelection[i]->Done();s_ppxSelection[i]->Next())
			{
				Tools_Render::RenderVertexOutline(i,s_ppxSelection[i]->Current(),0xffff0000);
			}
		}
	}
}

void Tools_Vertex_Selection::HighlightVertex(ModuleVertexPair& xVertex)
{
	if(!Tools_Render::HighlightPolyOrObjectUnderCursor) return;

	float fAlpha = Asura_Maths::Sine( Asura_Timers::GetLocalUnscaledTime() * 2.0f );
	fAlpha = 255.0f * fAlpha * fAlpha;

	unsigned int uColour = 0x00ffffff + (Asura_Maths::FloatToInt( fAlpha )<<24);
	
	Tools_Render::RenderVertexOutline(xVertex.iModuleIndex,xVertex.iVertexIndex,uColour);
}

void Tools_Vertex_Selection::HighlightPolygon(PolygonID& xPolygon)
{
	if(!Tools_Render::HighlightPolyOrObjectUnderCursor) return;

	Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(xPolygon.ModuleIndex);
	if(xPolygon.PolyIndex >= pxMesh->NumberOfPolygons) return;

	float fAlpha = Asura_Maths::Sine( Asura_Timers::GetLocalUnscaledTime() * 2.0f );
	fAlpha = 255.0f * fAlpha * fAlpha;

	unsigned int colour = 0x00ffffff + (Asura_Maths::FloatToInt( fAlpha )<<24);
	
	Tools_Render::RenderPolygonOutline(xPolygon.PolyIndex,xPolygon.ModuleIndex,colour,true);
}



void Tools_Vertex_Selection::HandleMouseSelection()
{
	// If the user is doing anything with overlays or menus,
	// ignore any mousebutton/key presses etc. 
	if (Asura_Interface::UsingMenusOrOverlays()) return;
	
	if (!s_bSelectionLocked)
	{
	
		//see if the mouse is over a vertex
		ModuleVertexPair xVertex;
	   	bool bOverVert = GetVertexUnderMouse(xVertex);

		PolygonID xPoly;
	   	bool bOverPoly = Tools_Polygon_Selection::GetPolygonUnderMouse(xPoly);
	
		if (bOverVert) 		
		{
			//remember this polygon , so we can highlight it during Render()			
			s_xHighlitVertex = xVertex;
		}

		if (bOverPoly) 		
		{
			//remember this polygon , so we can highlight it during Render()			
			s_xHighlitPolygon = xPoly;
		}


		
		//if over a vertex , check for selection/deselection
	 	if (Asura_UserInput::KeyPressed(ASURA_KEYID_MOUSEBUTTON1))
		{
			if(Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_MOUSEBUTTON1) || s_bButtonDownForSelection)
			{
				s_bButtonDownForSelection = true;
				if (bOverVert)
				{
					if (Asura_UserInput::KeyPressed(ASURA_KEYID_SHIFT))
					{
						switch(s_iSelectionMode+s_iSelectionModeListOffset)
						{
							case VSelectionMode_Vertex :
								DeselectVertex(xVertex.iModuleIndex,xVertex.iVertexIndex);
								break;

							case VSelectionMode_Polygon :
								DeselectPolygon(xPoly.ModuleIndex,xPoly.PolyIndex);
								break;


							case VSelectionMode_Object :
								DeselectObject(xVertex.iModuleIndex);
								break;
							
						}
					}
					else
					{
						switch(s_iSelectionMode+s_iSelectionModeListOffset)
						{
							case VSelectionMode_Vertex :
								SelectVertex(xVertex.iModuleIndex,xVertex.iVertexIndex);
								break;

							case VSelectionMode_Polygon :
								SelectPolygon(xPoly.ModuleIndex,xPoly.PolyIndex);
								break;

							case VSelectionMode_Object :
								SelectObject(xVertex.iModuleIndex);
								break;

							
						}
					}
				}
			}
		}
	}
}

void Tools_Vertex_Selection::HandleKeyboard()
{
	if(Asura_Overlay_System::OverlaysHaveKeyboardFocus()) return;
	if(Asura_UserInput::KeyPressed(ASURA_KEYID_ALT)) return;
	
	if(Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL))
	{
	}
	else if(Asura_UserInput::KeyPressed(ASURA_KEYID_SHIFT))
	{
		if( Asura_UserInput::DebouncedKeyPressed( 'z' ) || Asura_UserInput::DebouncedKeyPressed( ',' )) // 'shift+z' or 'shift+<' for selection undo
		{
			Undo();
		}
		if ( Asura_UserInput::DebouncedKeyPressed( 'y' ) || Asura_UserInput::DebouncedKeyPressed( '.' )) // 'shift+y' or 'shift+>' for selection redo
		{
			Redo();
		}
	}
	else
	{
		if(Asura_UserInput::DebouncedKeyPressed('l'))// 'L' for clear selection
		{
			Tools_Vertex_Selection::DeselectAll();
		}
	}
}

void Tools_Vertex_Selection::ToggleSelectionOverlay(void)
{
	s_bSelectionOverlayOpen = !s_bSelectionOverlayOpen;

	if (s_bSelectionOverlayOpen)
	{
		s_uSelectionOverlayMinimised = 0;
		CreateSelectionOverlay();
	}
	else
	{
		CloseSelectionOverlay();
	}
}
bool Tools_Vertex_Selection::SelectionOverlayIsOn(void)
{
	return s_bSelectionOverlayOpen;
}

void Tools_Vertex_Selection::CreateSelectionOverlay(void)
{
	if(!s_bSelectionOverlayOpen) return;
	if(Asura_Overlay_System::DoesOverlayExist(TOOLS_OVERLAY_VERTEX_SELECTION)) return;
	//strings for selection mode options
	static char* s_apszSelectionModeStrings[] =
	{
		"Vertex",
		"Polygon",
		"Object",
	};

	static char* s_apszSelectionModeHelpStrings[] =
	{
		"Selects a single vertex",
		"Selects all the vertices in a polgon",
		"Selects all the vertices in a module",
	};


	Asura_Overlay* pxOverlay;
	pxOverlay = new Asura_Overlay("Selection",false,&s_xSelectionOverlayPosition,&s_uSelectionOverlayMinimised);
	
	Asura_Dialog* pxDialog;
	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f,3.0f);

	
	//heading for selection mode list box
	pxDialog = new Asura_Dialog("Selection Mode :",xOffset);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=1.0f;

	//selection mode list box
	Asura_List_Dialog* pxList = new Asura_List_Dialog(xOffset,s_apszSelectionModeStrings,&Tools_Vertex_Selection::s_iSelectionModeListOffset,&Tools_Vertex_Selection::s_iSelectionMode,3,3,NULL);
	pxDialog = pxList;
	pxList->SetListHelpStrings(s_apszSelectionModeHelpStrings);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=4.2f;
	
	pxDialog = new Asura_Tickbox_Dialog("Lock Selection",xOffset,&(Tools_Vertex_Selection::s_bSelectionLocked));
	pxDialog->SetHelpText("Disables all controls for changing the current selection.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Tickbox_Dialog("Show Selection",xOffset,&(Tools_Vertex_Selection::s_bShowSelection));
	pxDialog->SetHelpText("Highlight currently selected vertices with a red outline");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Tickbox_Dialog("Show Loose Vertices",xOffset,&(Tools_Vertex_Selection::s_bShowLooseVertices));
	pxDialog->SetHelpText("Causes vertices that aren't attached to any polygons to be visible , and allows for them to be selected.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::LargeSpacing();


	pxDialog = new Asura_Function_Dialog("Select All",xOffset,Tools_Vertex_Selection::SelectAll);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog("Clear Selection (L)",xOffset,Tools_Vertex_Selection::DeselectAll);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();
	
	pxDialog = new Asura_Function_Dialog("Undo (Shift+Z)",xOffset,Tools_Vertex_Selection::Undo);
	pxDialog->SetHelpText("Vertex selection undo.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Function_Dialog("Redo (Shift+Y)",xOffset,Tools_Vertex_Selection::Redo);
	pxDialog->SetHelpText("Vertex selection redo.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();
	
	pxOverlay->m_uID = TOOLS_OVERLAY_VERTEX_SELECTION;

	Asura_Overlay_System::SubmitNewOverlay(pxOverlay,false);
}

void Tools_Vertex_Selection::CloseSelectionOverlay()
{
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_VERTEX_SELECTION);
}

void Tools_Vertex_Selection::Undo()
{
	if(!s_bSelectionLocked)
	{
		if(s_xSelectionUndo.Undo())
		{
			Tools_Timed_Message_System::AddMessage(0xffffff,"Selection Undo");
		}
	}
}
void Tools_Vertex_Selection::Redo()
{
	if(!s_bSelectionLocked)
	{
		if(s_xSelectionUndo.Redo())
		{
			Tools_Timed_Message_System::AddMessage(0xffffff,"Selection Redo");
		}
	}
}



void Tools_Vertex_Selection::HandleVertexConversion(int iModuleIndex,int* pxVertConv)
{
	Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(iModuleIndex);
	Asura_Assert(pxMesh,"Failed to get the mesh for the module");


	
	//create new Selection data

	VertexSelectionList* NewSelection = new VertexSelectionList(iModuleIndex,pxMesh->NumberOfVertices);

	//run through the old selection , adding converted values to the new selection
	if(pxVertConv)
	{
		for(s_ppxSelection[iModuleIndex]->StartIteration();!s_ppxSelection[iModuleIndex]->Done();s_ppxSelection[iModuleIndex]->Next())
		{
			int iVert = s_ppxSelection[iModuleIndex]->Current();
			if(pxVertConv[iVert]!=-1)
			{
				NewSelection->Add(pxVertConv[iVert]);
			}	
		}
	}
	if(s_ppxSelection[iModuleIndex]->NumSelected() && ! NewSelection->NumSelected())
	{
		s_iNumSelectedModules--;	
	}

	//replace the selection data
	delete s_ppxSelection[iModuleIndex];
	s_ppxSelection[iModuleIndex] = NewSelection;

	if(s_xHighlitVertex.iModuleIndex == iModuleIndex)
	{
		//just clear the highlighted vertex for this frame , since the module has been altered
		s_xHighlitVertex.iModuleIndex = -1;
		s_xHighlitVertex.iVertexIndex = -1;

		s_xHighlitPolygon.ModuleIndex = -1;
		s_xHighlitPolygon.PolyIndex = -1;

	}
}

void Tools_Vertex_Selection::HandleMeshChange(int iModuleIndex)
{
	Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(iModuleIndex);
	Asura_Assert(pxMesh,"Failed to get the mesh for the module");


	
	//create new Selection data
	if(pxMesh->NumberOfPolygons != s_ppxSelection[iModuleIndex]->NumItems())
	{
		VertexSelectionList* pxNewSelection = new VertexSelectionList(iModuleIndex,pxMesh->NumberOfVertices);

		if(s_ppxSelection[iModuleIndex]->NumSelected() && ! pxNewSelection->NumSelected())
		{
			s_iNumSelectedModules--;	
		}

		//replace the selection data
		delete s_ppxSelection[iModuleIndex];
		s_ppxSelection[iModuleIndex] = pxNewSelection;

		if(s_xHighlitVertex.iModuleIndex == iModuleIndex)
		{
			//just clear the highlighted vertex for this frame , since the module has been altered
			s_xHighlitVertex.iModuleIndex = -1;
			s_xHighlitVertex.iVertexIndex = -1;

			s_xHighlitPolygon.ModuleIndex = -1;
			s_xHighlitPolygon.PolyIndex = -1;

		}
		ClearUndo();
	}
}



void Tools_Vertex_Selection::DeleteModule(int iModuleIndex)
{
	Asura_Assert(iModuleIndex>=0 && iModuleIndex<s_iNumberOfModules,"");

	DeselectObject(iModuleIndex);

	delete s_ppxSelection[iModuleIndex];
	s_ppxSelection[iModuleIndex] = s_ppxSelection[s_iNumberOfModules-1];

	s_iNumberOfModules--;
	ClearUndo();

}

////////////////////////////////////////////////////////////////////////////////////////
bool Tools_Vertex_Selection::GetVertexUnderMouse(ModuleVertexPair& xVertex)
{
	return Tools_LOS::FindVertUnderCursor(xVertex.iVertexIndex,xVertex.iModuleIndex,0,s_bShowLooseVertices);
}

bool Tools_Vertex_Selection::GetHighlitVertex(ModuleVertexPair& xVertex)
{
	if(s_xHighlitVertex.iModuleIndex<0) return false;
	xVertex = s_xHighlitVertex;
	return true;
}
