//
// Tools_Prompted_Selection.cpp
//
// Created by Richard Rice - 21/05/03
// 
// Copyright (C) 2003 Rebellion, All Rights Reserved.
//

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

#include "Core/Asura_UserInput.h"
#include "Core/Asura_String.h"
#include "Core/Asura_Timers.h"
#include "Interface/Asura_Overlay_System.h"
#include "Interface/Asura_Interface.h"
#include "Mesh/Asura_Mesh.h"
#include "Rendering/Asura_Viewport.h"
#include "Rendering/Asura_Text_Output.h"
#include "Rendering/Asura_Module.h"

#include "Objects/Tools_Object.h"
#include "Objects/Tools_Object_System.h"
#include "Misc/list_tem.hpp"
#include "Misc/Tools_LOS.h"
#include "Misc/Tools_Render.h"
#include "Misc/Tools_Polygon_Selection.h"


void (*Tools_Prompted_Selection::s_pfnModuleCallback)(int iModuleIndex) = 0;
void (*Tools_Prompted_Selection::s_pfnPolygonCallback)(int iModuleIndex,int iPolygonIndex) = 0;
void (*Tools_Prompted_Selection::s_pfnVertexCallback)(int iModuleIndex,int iVertexIndex) = 0;
void (*Tools_Prompted_Selection::s_pfnObjectCallback)(Tools_Object* pxObject) = 0;
void (*Tools_Prompted_Selection::s_pfnEdgeCallback)(Tools_LOS_EdgeOutput xEdge) = 0;

bool (*Tools_Prompted_Selection::s_pfnVertexFilter)(int iModuleIndex,int iVertexIndex) = 0;

bool (*Tools_Prompted_Selection::s_pfnCustomPickCallback)(bool) = NULL;
void (*Tools_Prompted_Selection::s_pfnCustomRenderCallback)(u_int) = NULL;

bool Tools_Prompted_Selection::s_bButtonDebounced = false;
bool Tools_Prompted_Selection::s_bSelecting = false;
int Tools_Prompted_Selection::s_iModuleIndex = -1;
int Tools_Prompted_Selection::s_iPolygonIndex = -1;
int Tools_Prompted_Selection::s_iVertexIndex = -1;
Tools_Object* Tools_Prompted_Selection::s_pxObject = 0;
Tools_LOS_EdgeOutput Tools_Prompted_Selection::s_xEdge;
bool Tools_Prompted_Selection::s_bEdgeSelect_AllowDiagonalInQuad = false;

static List<Asura_String> g_xPromptStrings;


void Tools_Prompted_Selection::Initialise()
{
	s_pfnModuleCallback = 0;
	s_pfnPolygonCallback = 0;
	s_pfnVertexCallback = 0;
	s_pfnObjectCallback = 0;
	s_pfnEdgeCallback = 0;
	s_pfnVertexFilter = 0;
    s_pfnCustomPickCallback = NULL;
    s_pfnCustomRenderCallback = NULL;
}

void Tools_Prompted_Selection::Shutdown()
{
	EndSelection();
}

void Tools_Prompted_Selection::Update()
{
	if(!s_bSelecting) return;

	s_iModuleIndex = -1;
	s_pxObject = 0;
	s_xEdge.m_axEdge[0].m_iModuleIndex = -1;
	bool bSelectionValid = false;
	if (Asura_Interface::UsingMenusOrOverlays()) return;


	//make sure the button has been debounced before accepting input
	if(!Asura_UserInput::KeyPressed(ASURA_KEYID_MOUSEBUTTON1))
	{
		s_bButtonDebounced = true;
	}

	//find out what the cursor is over
	if(s_pfnModuleCallback)
	{					  
  		bSelectionValid = Tools_LOS::FindModuleUnderCursor(s_iModuleIndex);
	}
	else if(s_pfnPolygonCallback)
	{
		Asura_Vector_3 xJunk;
		bSelectionValid = Tools_LOS::FindPolyAndPositionUnderCursor(s_iPolygonIndex,s_iModuleIndex,xJunk);
	}
	else if(s_pfnVertexCallback)
	{
		bSelectionValid = Tools_LOS::FindVertUnderCursor(s_iVertexIndex,s_iModuleIndex,s_pfnVertexFilter);
	}
	else if(s_pfnObjectCallback)
	{
		s_pxObject = Tools_Object_System::FindObjectUnderCursor();
		bSelectionValid = (s_pxObject != 0);
	}
	else if(s_pfnEdgeCallback)
	{
		bSelectionValid = Tools_LOS::FindEdgeUnderCursor(s_xEdge, s_bEdgeSelect_AllowDiagonalInQuad);
	}
    else if( s_pfnCustomPickCallback )
    {
        bSelectionValid = s_pfnCustomPickCallback( false );
    }

	if(s_bButtonDebounced && bSelectionValid && Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_MOUSEBUTTON1))
	{
		EndSelection();

		if(s_pfnModuleCallback)
		{
			s_pfnModuleCallback(s_iModuleIndex);
		}
		else if(s_pfnPolygonCallback)
		{
			s_pfnPolygonCallback(s_iModuleIndex,s_iPolygonIndex);
		}
		else if(s_pfnVertexCallback)
		{
			s_pfnVertexCallback(s_iModuleIndex,s_iVertexIndex);
		}
		else if(s_pfnObjectCallback)
		{
			s_pfnObjectCallback(s_pxObject);
		}
		else if(s_pfnEdgeCallback)
		{
			s_pfnEdgeCallback(s_xEdge);
		}
        else if( s_pfnCustomPickCallback )
        {
            s_pfnCustomPickCallback( true );
        }

		return;
	}

	if(Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_ESCAPE))
	{
		EndSelection();
		return;
	}
}

void Tools_Prompted_Selection::Render()
{
	if(!s_bSelecting) return;

	float fAlpha = Asura_Maths::Sine( Asura_Timers::GetLocalUnscaledTime() * 2.0f );
	fAlpha = 150.0f * fAlpha * fAlpha + 105.0f;
	u_int uColour = ( 0xffffff) | (Asura_Maths::FloatToInt( fAlpha ) << 24);

    if( s_pfnCustomRenderCallback )
    {
        s_pfnCustomRenderCallback( uColour );
    }
    else
    {
	    if(s_iModuleIndex>=0)
	    {
		    //render the outline of the selection
    	   
    		
		    Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(s_iModuleIndex);
    		
		    if(s_pfnModuleCallback)
		    {
		        Tools_Render::RenderMeshOutline( s_iModuleIndex, uColour );
		    }
		    else if(s_pfnPolygonCallback)
		    {
			    if(s_iPolygonIndex>=0 && s_iPolygonIndex<pxMesh->NumberOfPolygons)
			    {
				    Tools_Render::RenderPolygonOutline(s_iPolygonIndex,s_iModuleIndex,uColour,true);
			    }
		    }
		    else if(s_pfnVertexCallback)
		    {
			    if(s_iVertexIndex>=0 && s_iVertexIndex<pxMesh->NumberOfVertices)
			    {
				    Tools_Render::RenderVertexOutline(s_iModuleIndex,s_iVertexIndex,uColour);
			    }
		    }
	    }
	    if(s_xEdge.m_axEdge[0].m_iModuleIndex>=0)
	    {
		    Tools_Render::RenderEdge(s_xEdge.m_axEdge[0].m_iModuleIndex,s_xEdge.m_axEdge[0].m_aiVertexIndex[0],s_xEdge.m_axEdge[0].m_aiVertexIndex[1],uColour);
	    }
	    if(s_pxObject)
	    {
		    if(s_pfnObjectCallback)
		    {
			    if(Tools_Object_System::ObjectList.contains(s_pxObject))
			    {
				    Asura_Mesh* pxMesh = s_pxObject->GetLODMesh();
				    if(pxMesh)
				    {
					    Tools_Render::RenderMeshOutline(pxMesh,&s_pxObject->Position,&s_pxObject->Orientation,uColour);
				    }
			    }
		    }
	    }
    }

	//render the prompt
	float fPrintX = Asura_Viewport::GetWidth()/2.0f;
	float fPrintY = Asura_Viewport::GetHeight()/2.0f;
	Asura_Text_Output::ConvertPixelsToPrintCoords(fPrintX,fPrintY);
	fPrintX-=0.5f;
	fPrintY-= (float) g_xPromptStrings.size()/2.0f;

	for(LIF<Asura_String> xStringLIF(&g_xPromptStrings);!xStringLIF.done();xStringLIF.next())
	{
		Asura_Text_Output::Print(fPrintX,fPrintY++,0xff00ff00,ASURA_TEXT_FORMAT_CENTREJUSTIFIED,xStringLIF().GetString());
	}
	Asura_Text_Output::Print(fPrintX,fPrintY++,0xff00ff00,ASURA_TEXT_FORMAT_CENTREJUSTIFIED,"Press escape to cancel");
}

void Tools_Prompted_Selection::ChooseModule(const char* pszPrompt,void (*pfnModuleCallback)(int iModuleIndex))
{
	InitialiseSelection(pszPrompt);
	s_pfnModuleCallback = pfnModuleCallback;
}

void Tools_Prompted_Selection::ChoosePolygon(const char* pszPrompt,void (*pfnPolygonCallback)(int iModuleIndex,int iPolygonIndex))
{
	InitialiseSelection(pszPrompt);
	s_pfnPolygonCallback = pfnPolygonCallback;
}

void Tools_Prompted_Selection::ChooseVertex(const char* pszPrompt,void (*pfnVertexCallback)(int iModuleIndex,int iVertexIndex),bool (*pfnVertexFilter)(int iModuleIndex,int iVertexIndex))
{
	InitialiseSelection(pszPrompt);
	s_pfnVertexCallback = pfnVertexCallback;
	s_pfnVertexFilter = pfnVertexFilter;
}

void Tools_Prompted_Selection::ChooseObject(const char* pszPrompt,void (*pfnObjectCallback)(Tools_Object* pxObject))
{
	InitialiseSelection(pszPrompt);
	s_pfnObjectCallback = pfnObjectCallback;
}

void Tools_Prompted_Selection::ChooseEdge(const char* pszPrompt,void (*pfnEdgeCallback)(Tools_LOS_EdgeOutput xEdge), bool bAllowDiagonalInQuad)
{
	InitialiseSelection(pszPrompt);
	s_pfnEdgeCallback = pfnEdgeCallback;
	s_bEdgeSelect_AllowDiagonalInQuad = bAllowDiagonalInQuad;
}


void Tools_Prompted_Selection::ChooseCustom( const char* szPrompt, bool (*pfnCustomPickCallback)(bool), void (*pfnCustomRenderCallback)(u_int) )
{
    Asura_Assert( pfnCustomPickCallback && pfnCustomRenderCallback, "" );

	InitialiseSelection( szPrompt );

    s_pfnCustomPickCallback = pfnCustomPickCallback;
    s_pfnCustomRenderCallback = pfnCustomRenderCallback;
}


void Tools_Prompted_Selection::InitialiseSelection(const char* pszPrompt)
{
	s_pfnModuleCallback = 0;
	s_pfnPolygonCallback = 0;
	s_pfnVertexCallback = 0;
	s_pfnObjectCallback = 0;
	s_pfnVertexFilter = 0;
	s_pfnEdgeCallback = 0;
    s_pfnCustomPickCallback = NULL;
    s_pfnCustomRenderCallback = NULL;
	s_iModuleIndex = -1;
	s_iPolygonIndex = -1;
	s_iVertexIndex = -1;
	s_xEdge.m_axEdge[0].m_iModuleIndex = -1;
	s_bEdgeSelect_AllowDiagonalInQuad = false;
	s_pxObject = 0;
	s_bButtonDebounced = false;
	s_bSelecting = true ;

	while(g_xPromptStrings.size()) g_xPromptStrings.delete_first_entry();

	if(pszPrompt)
	{
		char szBuffer[500];
	
		//split the text into however many lines
		const char* pcFrom = pszPrompt;
		while(*pcFrom)
		{
			char* pcTo = szBuffer;
			while(*pcFrom && *pcFrom != '\n')
			{
				*pcTo++ = *pcFrom++;
			}
			*pcTo++ = 0;
			g_xPromptStrings.add_entry(szBuffer);

			if(*pcFrom == '\n') pcFrom++;
		}
	}
}

void Tools_Prompted_Selection::EndSelection()
{
	s_bSelecting = false;
}
