//
// Asura_Chunk_Corona.cpp
//
// Created by Richard Rice - 24/02/03
// 
// Copyright (C) 2003 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "ChunkSystem/Asura_Chunk_Corona.h"
#include "Debugging/Asura_Assert.h"

#include "Core/Asura_TextureManagement.h"
#include "SpecialFX/Asura_StaticCorona_System.h"
#include "SpecialFX/Asura_Corona_System.h"

#include "FileAccess/Asura_FileAccess.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "ChunkSystem/Asura_Chunk_Macros.h"

#ifdef ASURA_TOOLS
#include "Load&Save/Tools_SaveAsura.h"
#endif


#define ASURA_CHUNK_CORONA_VERSION 4
// Version 1 - Added template information , and ID
//		(RAR 19/8/04)
// Version 2 - Added name
//		(RAR 08/07/2005)
// Version 3 - Added light sets
//		(RAR 01/06/2006)
// Version 4 - Added volumetric depth scale
//      (DMR 11/07/2007)

bool Asura_Chunk_Corona::Process(Asura_Handle iFileHandle) const
{
	Asura_Assert(Version<=ASURA_CHUNK_CORONA_VERSION,"Unknown chunk version");

	int iFirstCorona = Asura_StaticCorona_System::AllocateOnLoad(m_iNumberOfCoronas);
	
	if(Version > 0)
	{
		#ifdef ASURA_TOOLS
		u_int uNextID;
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,uNextID,u_int);
		Asura_StaticCorona::s_uNextID = Asura_Maths::Max(Asura_StaticCorona::s_uNextID, uNextID);
		#else
		Asura_FileAccess::SkipData(iFileHandle,4);
		#endif
	}

	for(int i=0;i<m_iNumberOfCoronas;i++)
	{
		Asura_StaticCorona* pxCorona = Asura_StaticCorona_System::GetCorona(i+iFirstCorona);
		Asura_Assert(pxCorona,"");

		if(Version >= 1)
		{
			#ifdef ASURA_TOOLS
			ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_uID,u_int);
			ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_uTemplateGuid,Asura_Guid);
			ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_iTemplateVersion,int);
			#else
			Asura_FileAccess::SkipData(iFileHandle,12);
			#endif
		}
		#ifdef ASURA_TOOLS
		else
		{
			pxCorona->GenerateID();			
		}
		#endif

		#ifdef ASURA_TOOLS
		Asura_Assert(!pxCorona->IsMissionCorona() || Tools_SaveAsura::IsUsingMissionLighting(),"Found a corona flagged as belonging to a mission while not editing a mission file (or while editing a mission that uses the common LIT file).\nThis will be lost when the file is next saved.");
		#endif
		


		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_fRed,float);
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_fGreen,float);
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_fBlue,float);
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_fRadius,float);
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_iTextureID,int);
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_xPosition,Asura_Vector_3);
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_xDirection,Asura_Vector_3);
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_uFlags,u_int);

		if(Version >= 2)
		{
			#ifdef ASURA_TOOLS
			//read name
			ASURA_CHUNK_FILEEXTRACT_STRING(iFileHandle,pxCorona->m_xName);
			#else
			//skip name
			Asura_FileAccess::ReadString(iFileHandle);
			#endif
		}

		if(Version >= 3)
		{
			#ifdef ASURA_TOOLS
			ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_uLightSets,u_int);
			#else
			Asura_FileAccess::SkipData(iFileHandle,4);
			#endif
		}
		#ifdef ASURA_TOOLS
		else
		{
			pxCorona->m_uLightSets = 0xffffffff;
		}
		#endif

		if(Version >= 4)
		{
			ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxCorona->m_fVolumetricDepthScale,float);
		}
		else
		{
			pxCorona->m_fVolumetricDepthScale = Asura_Corona_System::GetDefaultVolumetricDepthScale();
		}


		//convert the texture index
		if(pxCorona->m_iTextureID != ASURA_TEXTURE_NONE)
		{
			pxCorona->m_iTextureID = Asura_Texture_Management::ConvertIndex(pxCorona->m_iTextureID);
		}

		//and create the corona
		pxCorona->UpdateCorona();
		
	}
	return true;
}

#ifdef ASURA_TOOLS
int Asura_Chunk_Corona::ImportFromChunkBuffer(const char* pcChunkBuffer,u_int uSavedID,u_int uNewID) const
{
	Asura_Assert(Version<=ASURA_CHUNK_CORONA_VERSION,"Unknown chunk version");
	if(Version < 1)
	{
		Asura_Assert(0,"Unexpected corona version");
		return -1;
	}

	
	//skip next ID
	pcChunkBuffer += sizeof(int);

	for(int i=0;i<m_iNumberOfCoronas;i++)
	{
		u_int uID;
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,uID,u_int);

		Asura_Guid uTemplateGuid;
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,uTemplateGuid,Asura_Guid);


		//is this the corona we want?
		bool bWantThisCorona = false;
		if(uSavedID)
		{
			bWantThisCorona = (uSavedID == uID);
		}
		else
		{
			//importing all coronas... but need to ignore those that are members of templates
			bWantThisCorona = (uTemplateGuid == ASURA_GUID_UNREGISTERED);
		}

		if(bWantThisCorona)
		{
			int iIndex = Asura_StaticCorona_System::AllocateCorona();
			if(iIndex == -1) return -1;

			Asura_StaticCorona* pxCorona = Asura_StaticCorona_System::GetCorona(iIndex);

			if(uNewID && uSavedID)
			{
				pxCorona->m_uID = uNewID;
			}
			else
			{
				pxCorona->GenerateID();
			}
			pxCorona->m_uTemplateGuid = uTemplateGuid;
			
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_iTemplateVersion,int);
		
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_fRed,float);
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_fGreen,float);
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_fBlue,float);
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_fRadius,float);
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_iTextureID,int);
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_xPosition,Asura_Vector_3);
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_xDirection,Asura_Vector_3);
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_uFlags,u_int);

			if(Version>=2)
			{
				ASURA_CHUNK_EXTRACT_STRING(pcChunkBuffer,pxCorona->m_xName);
			}

			if(Version>=3)
			{
				ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_uLightSets,u_int);
			}
			else
			{
				pxCorona->m_uLightSets = 0xffffffff;
			}

			if(Version >= 4)
			{
				ASURA_CHUNK_EXTRACT(pcChunkBuffer,pxCorona->m_fVolumetricDepthScale,float);
			}
			else
			{
				pxCorona->m_fVolumetricDepthScale = 0.0f;
			}

			//convert the texture index
			if(pxCorona->m_iTextureID != ASURA_TEXTURE_NONE)
			{
				pxCorona->m_iTextureID = Asura_Texture_Management::ConvertIndex(pxCorona->m_iTextureID);
			}

			//and create the corona
			pxCorona->UpdateCorona();
			if(uSavedID)
			{
				return iIndex;
			}
		}
		else
		{
			//skip past the rest of the data for this corona
			pcChunkBuffer	+=	sizeof(int) //template version
							+	sizeof(float)*4 //colours and radius
							+	sizeof(int)	//texture ID
							+	sizeof(Asura_Vector_3)*2 //position and direction
							+	sizeof(u_int); // flags

			if(Version>=2)
			{
				//skip name
				pcChunkBuffer += (strlen(pcChunkBuffer)+4)&~3;
			}

			if(Version>=3)
			{
				//skip light sets
				pcChunkBuffer += sizeof(u_int);
			}

			if(Version>=4)
			{
				//skip volumetric depth scale
				pcChunkBuffer += sizeof(float);
			}

		}
		
	}
	return -1;
}

#endif

#ifdef ASURA_TOOLS
void Asura_Chunk_Corona::Create(Asura_SaveBlock* pxSaveBlock,bool bTemplateFile, bool bMissionFile)
{
	if(!Asura_StaticCorona_System::GetNumberOfCoronas()) return;

	const int iCoronaChunkSize =  sizeof(float)*4			//red,green,blue,radius
								+ sizeof(int)				//textureID
								+ sizeof(Asura_Vector_3)*2	//position,direction
								+ sizeof(u_int)				//flags
								+ sizeof(u_int)				//ID
								+ sizeof(Asura_Guid)		//template guid
								+ sizeof(int)				//template version
								+ sizeof(u_int) 			//light sets
								+ sizeof(float);			//volumetric depth scale


	int iChunkSize = sizeof(Asura_Chunk_Corona);
	iChunkSize += sizeof(u_int); //NextID

	//count the coronas to be saved
	int iNumCoronas = 0;
	for(int i=0;i<Asura_StaticCorona_System::GetArraySize();i++)
	{
		if(!Asura_StaticCorona_System::IsValidCorona(i)) continue;
		Asura_StaticCorona* pxCorona = Asura_StaticCorona_System::GetCorona(i);

		if(Tools_Level_Export::IsExport())
		{
			//For exports , only save the current light set. RAR 01/06/2006
			if(!pxCorona->IsMemberOfCurrentLightSet()) continue;
		}

		//If using mission files , then the coronas will be split across two files
		//(except during exports)
		if(!Tools_Level_Export::IsExport())
		{
			if(bMissionFile != pxCorona->IsMissionCorona()) continue;
		}
		
		if(bTemplateFile)
		{
			if(pxCorona->m_uID & TOOLS_CORONA_TEMPLATECORONA)
			{
				iChunkSize += pxCorona->m_xName.GetSizeInInts()*4;
				iNumCoronas++;
			}
		}
		else
		{
			if(!(pxCorona->m_uID & TOOLS_CORONA_TEMPLATECORONA))
			{
				iChunkSize += pxCorona->m_xName.GetSizeInInts()*4;
				iNumCoronas++;
			}
		}

	}
	iChunkSize += iNumCoronas*iCoronaChunkSize;

	if(!iNumCoronas) return;




	Asura_Chunk_Corona* pxChunk = (Asura_Chunk_Corona*) pxSaveBlock->GetAccessPointer(iChunkSize);

	pxChunk->ID = ASURA_CHUNK_CORONA;
	ASURA_CHUNK_VERIFY(pxChunk->ID, int);
	pxChunk->Size = iChunkSize;
	ASURA_CHUNK_VERIFY(pxChunk->Size, int);
	pxChunk->Version = ASURA_CHUNK_CORONA_VERSION;
	ASURA_CHUNK_VERIFY(pxChunk->Version, int);
	pxChunk->Flags = 0;
	ASURA_CHUNK_VERIFY(pxChunk->Flags, int);

	pxChunk->m_iNumberOfCoronas = iNumCoronas;
	ASURA_CHUNK_VERIFY(pxChunk->m_iNumberOfCoronas, int);

	char* pcChunkBuffer = (char*)(pxChunk+1);

	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,Asura_StaticCorona::s_uNextID,u_int);

	//RAR 08/03/2006 For recentreing during level exports :
	const Asura_Vector_3& xPositionOffset = Tools_Level_Export::GetExportCentre();
	
	for(int i=0;i<Asura_StaticCorona_System::GetArraySize();i++)
	{
		if(!Asura_StaticCorona_System::IsValidCorona(i)) continue;

		Asura_StaticCorona* pxCorona = Asura_StaticCorona_System::GetCorona(i);
		Asura_Assert(pxCorona,"");

		if(Tools_Level_Export::IsExport())
		{
			//For exports , only save the current light set. RAR 01/06/2006
			if(!pxCorona->IsMemberOfCurrentLightSet()) continue;
		}

		//If using mission files , then the coronas will be split across two files
		//(except during exports)
		if(!Tools_Level_Export::IsExport())
		{
			if(bMissionFile != pxCorona->IsMissionCorona()) continue;
		}

		if(!bTemplateFile)
		{
			if(pxCorona->m_uID & TOOLS_CORONA_TEMPLATECORONA) continue;
		}
		else
		{
			if(!(pxCorona->m_uID & TOOLS_CORONA_TEMPLATECORONA)) continue;
		}


		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_uID,u_int);
		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_uTemplateGuid,Asura_Guid);
		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_iTemplateVersion,int);

		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_fRed,float);
		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_fGreen,float);
		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_fBlue,float);
		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_fRadius,float);
		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_iTextureIDForSave,int);

		ASURA_CHUNK_FILL(pcChunkBuffer,pxCorona->m_xPosition - xPositionOffset,Asura_Vector_3);
		ASURA_CHUNK_ARRAY_VERIFY(*(pcChunkBuffer - sizeof(Asura_Vector_3)), float,3);
		ASURA_CHUNK_FILL(pcChunkBuffer,pxCorona->m_xDirection,Asura_Vector_3);
		ASURA_CHUNK_ARRAY_VERIFY(*(pcChunkBuffer - sizeof(Asura_Vector_3)), float,3);

		ASURA_CHUNK_BITFIELD_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_uFlags,u_int);

		ASURA_CHUNK_FILL_STRING(pcChunkBuffer,pxCorona->m_xName);

		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_uLightSets,u_int);

		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,pxCorona->m_fVolumetricDepthScale,float);


	}

	Asura_Assert((int)pcChunkBuffer-(int)pxChunk == iChunkSize,"Incorrect chunk size");
}
#endif //ASURA_TOOLS
