//
// Tools_Corona_Object.cpp
//
// Created by Richard Rice - 21/02/2003
// 
// Copyright (C) 2003 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "Lighting/Tools_Corona_Object.h"
#include "Debugging/Asura_Assert.h"

#include "Interface/Asura_Overlay_System.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Overlay.h"
#include "Mesh/Asura_Mesh.h"
#include "Camera/Asura_Camera.h"
#include "Mesh/Asura_Mesh_System.h"
#include "Rendering/Asura_Text_Output.h"


#include "Tools_Overlays.h"
#include "Interface/Tools_ColourPicker.h"
#include "Load&Save/Tools_SaveAsura.h"
#include "Lighting/Tools_LightSets.h"
#include "Lighting/Tools_Mode_PhotonMapping.h"
#include "Texturing/Tools_PickTexture.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Objects/Tools_Object_System.h"
#include "Objects/Tools_ObjectSystem_Param.h"

List<Tools_Corona_Object*> Tools_Corona_Object::s_xCoronaList;

TOOLS_DECLARE_SHARED_PARAM(Asura_String,	0x0F3ED989,	Corona_TextureDesc)
TOOLS_DECLARE_SHARED_PARAM(int,		0x428E7DF7,	Corona_TextureInt)
TOOLS_DECLARE_SHARED_PARAM(float,	0xB56570EE,	Corona_Red)
TOOLS_DECLARE_SHARED_PARAM(float,	0xF137E420,	Corona_Green)
TOOLS_DECLARE_SHARED_PARAM(float,	0xF741839D,	Corona_Blue)
TOOLS_DECLARE_SHARED_PARAM(float,	0x4799FB15,	Corona_Radius)
TOOLS_DECLARE_SHARED_PARAM(bool,	0xA1822B29,	Corona_UseOrient)
TOOLS_DECLARE_SHARED_PARAM(bool,	0x307F620B,	Corona_DontFadeWithDistance)
TOOLS_DECLARE_SHARED_PARAM(bool,	0x08742378,	Corona_DontFadeNear)
TOOLS_DECLARE_SHARED_PARAM(bool,	0xB1AFEA58,	Corona_UseModuleLinking)
TOOLS_DECLARE_SHARED_PARAM(float,	0x357D955C, Corona_VolumetricDepthScale)

static const Asura_Hash_ID g_uHash_LightSource_LightSet0 = 0xBD2D1016; 
static const Asura_Hash_ID g_uHash_LightSource_LightSetLast = g_uHash_LightSource_LightSet0+TOOLS_MAX_LIGHT_SETS-1; 
static Tools_ObjectSystem_SharedValue<bool> g_axParam_LightSource_LightSet[TOOLS_MAX_LIGHT_SETS];



Tools_Corona_Object::Tools_Corona_Object(int iCoronaIndex)
:Tools_Object(TOT_Corona)
{
	m_iCoronaIndex = iCoronaIndex;
	m_xUserCorona.Initialise();
	m_bChanged = false;

	Asura_String mesh_name = "ToolsShape_CutsceneTrackPoint";
	Mesh = Asura_Mesh_System::GetMesh(mesh_name);


	Asura_StaticCorona* pxCorona = Asura_StaticCorona_System::GetCorona(m_iCoronaIndex);	
	Asura_Assert(pxCorona,"");
	if(!pxCorona) return;

	//copy the settings from the corona system
	m_xUserCorona = *pxCorona;

	Position = pxCorona->m_xPosition;

	//get a matrix from the light's direction
	Asura_Maths::OrientationFromDirection(Orientation,pxCorona->m_xDirection);

	m_uTemplateGuid = pxCorona->m_uTemplateGuid;
	m_uID = pxCorona->m_uID;


	UpdateToolsName();

	s_xCoronaList.add_entry(this);

}

Tools_Corona_Object::~Tools_Corona_Object()
{
	s_xCoronaList.delete_entry(this);
}

void Tools_Corona_Object::_CreateCorona()
{
	Tools_Corona_Object* pxObject = CreateCorona();
	if(pxObject)
	{
		Tools_Object_System::SelectObject(pxObject);
	}
}

Tools_Corona_Object* Tools_Corona_Object::CreateCorona()
{
	int iIndex = Asura_StaticCorona_System::AllocateCorona();
	if(iIndex>=0)
	{
		Asura_StaticCorona* pxCorona = Asura_StaticCorona_System::GetCorona(iIndex);
		Asura_Assert(pxCorona,"");

		const Asura_Vector_3* pxCameraPosition = Asura_Camera::GetPosition();
		const Asura_Matrix_3x3* pxCameraOrientation = Asura_Camera::GetOrientation();


		//initialise corona
		pxCorona->GenerateID();
		if(Tools_SaveAsura::GetFileType() == AsuraFile_Template)
		{
			//lights created while editing template files need to be marked as such.
			pxCorona->m_uID |= TOOLS_CORONA_TEMPLATECORONA;
		}

		if(Tools_Object_System::ShouldCreateNewObjectsInMissionFile() && Tools_SaveAsura::IsUsingMissionLighting())
		{
			pxCorona->m_uID |= TOOLS_CORONA_MISSIONCORONA;
		}


		pxCorona->m_xPosition = *pxCameraPosition;
		pxCorona->m_xDirection = Asura_Vector_3(pxCameraOrientation->e13,pxCameraOrientation->e23,pxCameraOrientation->e33); 
		pxCorona->m_iTextureID = ASURA_TEXTURE_NONE;
		pxCorona->m_uLightSets = Tools_LightSets::GetLightSetsForNewObject(pxCorona->m_xPosition);
		pxCorona->UpdateCorona();

		//create the tools object
		Tools_Corona_Object* pxToolsCorona = new Tools_Corona_Object(iIndex);

		pxToolsCorona->SetModified();

		return pxToolsCorona;
	}
	return 0;
}



void Tools_Corona_Object::UpdatePositionInAsuraData(bool /*bUpdateLinkedObjects*/)
{
	m_xUserCorona.m_xPosition = Position;
	m_xUserCorona.m_xDirection = Asura_Vector_3(Orientation.e13,Orientation.e23,Orientation.e33);
	m_bChanged = true;
}

void Tools_Corona_Object::Destroy()
{
	SetModified();
	Asura_StaticCorona_System::DeallocateCorona(m_iCoronaIndex);

	Tools_Object::Destroy();
}

void Tools_Corona_Object::OnSelection()
{
	Tools_Object::OnSelection();
	CreatePropertiesOverlay();
}

void Tools_Corona_Object::OnDeselection()
{
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_SELECTEDOBJECT);
	Tools_Object::OnDeselection();
}

void Tools_Corona_Object::UpdateWhileSelected()
{
}

void Tools_Corona_Object::Update()
{
	if(m_bChanged)
	{
		Asura_StaticCorona* pxCorona = Asura_StaticCorona_System::GetCorona(m_iCoronaIndex);
		if(pxCorona)
		{
			*pxCorona = m_xUserCorona;
			pxCorona->UpdateCorona();
		}

		SetModified();
		m_bChanged = false;
		
	}
}



void Tools_Corona_Object::CreatePropertiesOverlay()
{
	Asura_Overlay* pxOverlay;
	pxOverlay = new Asura_Overlay("Corona Properties",false);
	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f,3.0f);
	
	Asura_Dialog* pxDialog;


	pxDialog = new Asura_Function_Dialog("Rename",xOffset,Rename,(int)this);
	pxDialog->SetHelpText("Rename this corona.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::LargeSpacing();

	//Tab control
	static char* s_aszTabs[2] = {"Main","Light Sets"};
	Asura_Tabs_Dialog* pxTabsDialog = new Asura_Tabs_Dialog(xOffset,s_aszTabs,2);
	pxOverlay->AddDialog(pxTabsDialog);
	xOffset.y += Asura_Dialog::LargeSpacing();

	float fTabsStartY = xOffset.y;
	float fTabsEndY = xOffset.y;

	pxOverlay->SetCurrentParentDialog(pxTabsDialog);	


	//Main Tab
	pxTabsDialog->SelectTab(0);

	pxDialog = new Asura_Function_Dialog("Texture : ",&g_xParam_Corona_TextureDesc,xOffset,_SelectTexture,(int)this);
	pxDialog->SetHelpText("Select texture.");
	pxOverlay->AddDialog(pxDialog);

	xOffset.x += 18.0f;
	Tools_ColourPicker_Dialog* pxColourPickerDialog = new Tools_ColourPicker_Dialog("Corona Colour",xOffset,Asura_Vector_2(4.0f,3.0f),&g_xParam_Corona_Red,&g_xParam_Corona_Green,&g_xParam_Corona_Blue,1.0f,&m_bChanged);
	pxColourPickerDialog->EnableHDR(true);
	pxOverlay->AddDialog(pxColourPickerDialog);
	xOffset.x -= 18.0f;

	xOffset.y+=Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog("Radius", xOffset, &g_xParam_Corona_Radius, 0.0f, 100.0f, 0.01f, "%.2f");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_SharedTickbox_Dialog("Use Orient",xOffset,&g_xParam_Corona_UseOrient);
	pxDialog->SetHelpText("Causes the corona to fade out if not viewed head on.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_SharedTickbox_Dialog("Dont Fade With Distance",xOffset,&g_xParam_Corona_DontFadeWithDistance);
	pxDialog->SetHelpText("Stops corona from fading out when far away.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_SharedTickbox_Dialog("Dont Fade Near",xOffset,&g_xParam_Corona_DontFadeNear);
	pxDialog->SetHelpText("Stops corona from fading out very close to the camera.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();

#if defined (ASURA_USE_NEW_VISIBILITY_SYSTEM)
	pxDialog = new Asura_SharedTickbox_Dialog("Use Visibility System",xOffset,&g_xParam_Corona_UseModuleLinking);
	pxDialog->SetHelpText("Causes the corona to make use of the visibility system for culling.");
#else
	pxDialog = new Asura_SharedTickbox_Dialog("Use Module Linking",xOffset,&g_xParam_Corona_UseModuleLinking);
	pxDialog->SetHelpText("Causes the corona to make use of module linking for culling.");
#endif

	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();

#ifdef ASURA_TARGET_SM3
	pxDialog = new Asura_Numerical_Dialog("Volumetric Depth Scale", xOffset, &g_xParam_Corona_VolumetricDepthScale, 0.0f, 10.0f, 0.01f, "%.02f");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::DefaultSpacing();
#endif


	//End of main tab
	if(xOffset.y > fTabsEndY) fTabsEndY = xOffset.y;

	//Light set tab
	pxTabsDialog->SelectTab(1);
	xOffset.y = fTabsStartY;

	//add a checkbox for each light set
	for(u_int i=0;i<TOOLS_MAX_LIGHT_SETS;i++)
	{
		const char* szSetName = Tools_LightSets::GetLightSetNameByIndex(i);
		if(!szSetName) continue;

		g_axParam_LightSource_LightSet[i].SetParamID(g_uHash_LightSource_LightSet0+i);

		pxDialog = new Asura_SharedTickbox_Dialog(szSetName,xOffset,&g_axParam_LightSource_LightSet[i]);
		pxDialog->SetHelpText("Enables this light for this light set.");
		pxOverlay->AddDialog(pxDialog);
		xOffset.y+=Asura_Dialog::DefaultSpacing();
	}

	//End of light set tab
	if(xOffset.y > fTabsEndY) fTabsEndY = xOffset.y;

	//End of tabs
	pxOverlay->SetCurrentParentDialog(0);
	static u_int s_uSelectedTab = 0;
	pxTabsDialog->SetSelectedTabPointer(&s_uSelectedTab);
	xOffset.y = fTabsEndY + 1.0f;


	//set things up so that right clicking on the overlay will be equivalent to right clicking on the object
	//RAR 06/11/2007
	pxOverlay->SetContextMenuCallback(Tools_Object_System::AddContextMenuItemsFromOverlay, this);

	pxOverlay->m_uID = TOOLS_OVERLAY_SELECTEDOBJECT;
	Asura_Overlay_System::SubmitNewOverlay(pxOverlay,false);

}

void Tools_Corona_Object::UpdateToolsName()
{

	if(!m_xUserCorona.m_xName.IsBlank())
	{
		//take the name set by user
		m_xName = m_xUserCorona.m_xName;
	}
	else
	{
		//generate a default name
		char szBuffer[20];
		Asura_PrintfToBfr(szBuffer,"Corona %d",20,true,m_iCoronaIndex);
		m_xName = szBuffer;
	}
}


void Tools_Corona_Object::SelectTexture()
{
	int iSelected = Tools_PickTexture::PickTexture("Select Corona Texture",m_xUserCorona.m_iTextureID,PICKTEXTURE_ALLTEXTURES);
	if(iSelected != ASURA_TEXTURE_NONE)
	{
		//set the texture on all selected coronas
		g_xParam_Corona_TextureInt.SetValue(iSelected);
	}
}


bool Tools_Corona_Object::IsSelectable()
{
	//coronas that are members of templates can't be touched
	if(m_uTemplateGuid != ASURA_GUID_UNREGISTERED) return false;

	if(Tools_SaveAsura::GetFileType() == AsuraFile_Template)
	{
		//while editing template files ,don't allow selection of the test environment lights
		if(!(m_uID & TOOLS_CORONA_TEMPLATECORONA)) return false;
	}


	return Tools_Object::IsSelectable();
}


Tools_Corona_Object* Tools_Corona_Object::GetCoronaObjectFromID(u_int uID)
{
	for(LIF<Tools_Corona_Object*> xObjectLIF(&s_xCoronaList);!xObjectLIF.done();xObjectLIF.next())
	{
		if(xObjectLIF()->m_uID == uID)
		{
			return xObjectLIF();
		}
	}
	return 0;
}


void Tools_Corona_Object::Copy(const Tools_Object* pxObject)
{
	const Tools_Corona_Object* pxFrom = (const Tools_Corona_Object*) pxObject;

	//copy from the other corona , leaving position/orientation/name unchanged
	Asura_String xNameCopy = m_xUserCorona.m_xName;
	m_xUserCorona = pxFrom->m_xUserCorona;
	m_xUserCorona.m_xPosition = Position;
	m_xUserCorona.m_xDirection = Asura_Vector_3(Orientation.e13,Orientation.e23,Orientation.e33);
	m_xUserCorona.m_xName = xNameCopy;

	//update the asura data
	Asura_StaticCorona* pxCorona = Asura_StaticCorona_System::GetCorona(m_iCoronaIndex);
	if(pxCorona)
	{
		*pxCorona = m_xUserCorona;
		pxCorona->UpdateCorona();
	}

	SetModified();
	m_bChanged = false;

}

Tools_Object* Tools_Corona_Object::CreateObjectOfThisType() const
{
	return CreateCorona();
}

void Tools_Corona_Object::Rename()
{
	if(Tools_Object_System::AskForName(m_xUserCorona.m_xName,"Rename Corona",this,true))
	{
		UpdateToolsName();
		m_bChanged = true;
	}
}

bool Tools_Corona_Object::IsHidden()
{

	//Light sets can be hidden by the 'hide by type' overlay
	if(Tools_Object_System::IsHideByLightSetEnabled())
	{
		if(!(m_xUserCorona.m_uLightSets & Tools_Object_System::GetVisibleLightSets())) return true;
	}

	if(Tools_LightSets::ShouldHideObjectsInOtherSets())
	{
		if(!Tools_LightSets::IsMemberOfCurrentLightSets(m_xUserCorona.m_uLightSets)) return true;
	}


	return Tools_Object::IsHidden();
}


bool Tools_Corona_Object::GetParameter(Asura_Hash_ID uParamID,class Tools_Parameter* pxParam) const
{
	if(uParamID>=g_uHash_LightSource_LightSet0 && uParamID<=g_uHash_LightSource_LightSetLast)
	{
		u_int uBit = 1 << (uParamID - g_uHash_LightSource_LightSet0);
		pxParam->SetBool((m_xUserCorona.m_uLightSets & uBit) ? true : false);
	}
	else
	{
		switch(uParamID)
		{
			case g_uHash_Corona_Red :
				pxParam->SetFloat(m_xUserCorona.m_fRed);
				break;

			case g_uHash_Corona_Green :
				pxParam->SetFloat(m_xUserCorona.m_fGreen);
				break;

			case g_uHash_Corona_Blue :
				pxParam->SetFloat(m_xUserCorona.m_fBlue);
				break;


			case g_uHash_Corona_Radius :
				pxParam->SetFloat(m_xUserCorona.m_fRadius);
				break;

			case g_uHash_Corona_UseOrient :
				pxParam->SetBool((m_xUserCorona.m_uFlags & AsuraStaticCoronaFlag_UseDirectionEffect)!=0);
				break;

			case g_uHash_Corona_DontFadeWithDistance :
				pxParam->SetBool((m_xUserCorona.m_uFlags & AsuraStaticCoronaFlag_DontFadeWithDistance)!=0);
				break;

			case g_uHash_Corona_DontFadeNear :
				pxParam->SetBool((m_xUserCorona.m_uFlags & AsuraStaticCoronaFlag_DontFadeNear)!=0);
				break;

			case g_uHash_Corona_UseModuleLinking :
				pxParam->SetBool((m_xUserCorona.m_uFlags & AsuraStaticCoronaFlag_UseModuleLinking)!=0);
				break;

			case g_uHash_Corona_VolumetricDepthScale :
				pxParam->SetFloat(m_xUserCorona.m_fVolumetricDepthScale);
				break;

			case g_uHash_Corona_TextureDesc :
				//get the text to use for the texture selection control
				if(m_xUserCorona.m_iTextureID == ASURA_TEXTURE_NONE)
				{
					pxParam->SetString("<Not Set>");
				}
				else
				{
					const Asura_String* pxName = Asura_Texture_Management::GetTextureName(m_xUserCorona.m_iTextureID);
					if(pxName)
					{
						//get the name without path/extension
						Asura_String xFilename;
						pxName->SplitFilename(0,&xFilename,0);
						pxParam->SetString(xFilename.GetString());
					}
					else
					{
						pxParam->SetString("<Unknown>");
					}

				}
				break;

			default :
				return false;
		}
	}
	return true;
}

bool Tools_Corona_Object::SetParameter(Asura_Hash_ID uParamID,const class Tools_Parameter* pxParam)
{
	if(uParamID>=g_uHash_LightSource_LightSet0 && uParamID<=g_uHash_LightSource_LightSetLast)
	{
		u_int uBit = 1 << (uParamID - g_uHash_LightSource_LightSet0);
		bool bSet = pxParam->GetBool();
		if(bSet)
			m_xUserCorona.m_uLightSets |= uBit;
		else
			m_xUserCorona.m_uLightSets &=~ uBit;

	}
	else
	{
		switch(uParamID)
		{
			case g_uHash_Corona_Red :
				m_xUserCorona.m_fRed = pxParam->GetFloat();
				break;

			case g_uHash_Corona_Green :
				m_xUserCorona.m_fGreen = pxParam->GetFloat();
				break;

			case g_uHash_Corona_Blue :
				m_xUserCorona.m_fBlue = pxParam->GetFloat();
				break;

			case g_uHash_Corona_Radius :
				m_xUserCorona.m_fRadius = pxParam->GetFloat();
				break;

			case g_uHash_Corona_UseOrient :
				if(pxParam->GetBool())
				{
					m_xUserCorona.m_uFlags |= AsuraStaticCoronaFlag_UseDirectionEffect;
				}
				else
				{
					m_xUserCorona.m_uFlags &=~ AsuraStaticCoronaFlag_UseDirectionEffect;
				}
				break;

			case g_uHash_Corona_DontFadeWithDistance :
				if(pxParam->GetBool())
				{
					m_xUserCorona.m_uFlags |= AsuraStaticCoronaFlag_DontFadeWithDistance;
				}
				else
				{
					m_xUserCorona.m_uFlags &=~ AsuraStaticCoronaFlag_DontFadeWithDistance;
				}
				break;

			case g_uHash_Corona_DontFadeNear :
				if(pxParam->GetBool())
				{
					m_xUserCorona.m_uFlags |= AsuraStaticCoronaFlag_DontFadeNear;
				}
				else
				{
					m_xUserCorona.m_uFlags &=~ AsuraStaticCoronaFlag_DontFadeNear;
				}
				break;

			case g_uHash_Corona_UseModuleLinking :
				if(pxParam->GetBool())
				{
					m_xUserCorona.m_uFlags |= AsuraStaticCoronaFlag_UseModuleLinking;
				}
				else
				{
					m_xUserCorona.m_uFlags &=~ AsuraStaticCoronaFlag_UseModuleLinking;
				}
				break;

			case g_uHash_Corona_TextureInt :
				m_xUserCorona.m_iTextureID = pxParam->GetInt();
				break;

			case g_uHash_Corona_VolumetricDepthScale :
				m_xUserCorona.m_fVolumetricDepthScale = pxParam->GetFloat();
				break;


			default :
				return false;
		}
	}
	m_bChanged = true;
	return true;
}

void Tools_Corona_Object::SetModified() const
{
	if(m_uID & TOOLS_CORONA_MISSIONCORONA)
		Tools_SaveAsura::SetMissionLightingModified();
	else
		Tools_SaveAsura::SetLightingModified();
}


void Tools_Corona_Object::PrintInfo(float& x, float& y)
{
	Tools_Object::PrintInfo(x,y);

	if(Tools_SaveAsura::IsEditingMission())
	{
		Asura_Text_Output::Print(x,y++,0xffffffff,0,"Mission : %s",(m_uID & TOOLS_CORONA_MISSIONCORONA) ? "Yes" : "No");
	}

}