#include "../Gaia/RuGaia_Base.h"

#pragma unmanaged

// ************************************************************************************************************************************************************

ruRTTI_DEFINE_SUBCLASS(CRuGaia_Base, IRuCollisionHierarchy)
ruHEAP_DEFINE_SUBCLASS(CRuGaia_Base, "CRuGaia_Base", "IRuCollisionHierarchy")
ruCLASSGUID_DEFINE(CRuGaia_Base, 0xA0B62428, 0x87C1448f, 0x9EEE166F, 0x12313C68)

// ************************************************************************************************************************************************************

const char *CRuGaia_ZoneDescriptor::GetAmbientSound() const
{
	if(m_ambientSound)
	{
		return m_ambientSound;
	}

	return "";
}

void CRuGaia_ZoneDescriptor::SetAmbientSound(const char *ambientSound)
{
	if(ambientSound)
	{
		delete[] m_ambientSound;
		m_ambientSound = ruNEW char [strlen(ambientSound) + 1];
		strcpy(m_ambientSound, ambientSound);
	}
}

const char *CRuGaia_ZoneDescriptor::GetThemeMusic() const
{
	if(m_themeMusic)
	{
		return m_themeMusic;
	}

	return "";
}

void CRuGaia_ZoneDescriptor::SetThemeMusic(const char *themeMusic)
{
	if(themeMusic)
	{
		delete[] m_themeMusic;
		m_themeMusic = ruNEW char [strlen(themeMusic) + 1];
		strcpy(m_themeMusic, themeMusic);
	}
}

void CRuGaia_ZoneDescriptor::CopySettings(const CRuGaia_ZoneDescriptor &zoneDesc)
{
	delete[] m_skyGradientTextureName;
	m_skyGradientTextureName = NULL;

	delete[] m_horizonCloudTextureName;
	m_horizonCloudTextureName = NULL;

	delete[] m_overheadCloudTextureName;
	m_overheadCloudTextureName = NULL;

	m_color_Primary = zoneDesc.m_color_Primary;
	m_color_Secondary = zoneDesc.m_color_Secondary;
	m_color_Ambient = zoneDesc.m_color_Ambient;
	m_color_Specular = zoneDesc.m_color_Specular;
	m_color_Fog = zoneDesc.m_color_Fog;

	m_fog_Start = zoneDesc.m_fog_Start;
	m_fog_End = zoneDesc.m_fog_End;

	m_theta_Standard = zoneDesc.m_theta_Standard;
	m_phi_Standard = zoneDesc.m_phi_Standard;

	m_theta_Specular = zoneDesc.m_theta_Specular;
	m_phi_Specular = zoneDesc.m_phi_Specular;

	m_cloud_HorizonColor = zoneDesc.m_cloud_HorizonColor;
	m_cloud_OverheadColor = zoneDesc.m_cloud_OverheadColor;
	m_cloud_HorizonCount = zoneDesc.m_cloud_HorizonCount;
	m_cloud_OverheadCount = zoneDesc.m_cloud_OverheadCount;

	m_cloudMode = zoneDesc.m_cloudMode;

	if(zoneDesc.m_skyGradientTextureName)
	{
		INT32 len = strlen(zoneDesc.m_skyGradientTextureName);
		m_skyGradientTextureName = ruNEW char [len + 1];
		memcpy(m_skyGradientTextureName, zoneDesc.m_skyGradientTextureName, sizeof(char) * (len + 1));
	}

	if(zoneDesc.m_horizonCloudTextureName)
	{
		INT32 len = strlen(zoneDesc.m_horizonCloudTextureName);
		m_horizonCloudTextureName = ruNEW char [len + 1];
		memcpy(m_horizonCloudTextureName, zoneDesc.m_horizonCloudTextureName, sizeof(char) * (len + 1));
	}

	if(zoneDesc.m_overheadCloudTextureName)
	{
		INT32 len = strlen(zoneDesc.m_overheadCloudTextureName);
		m_overheadCloudTextureName = ruNEW char [len + 1];
		memcpy(m_overheadCloudTextureName, zoneDesc.m_overheadCloudTextureName, sizeof(char) * (len + 1));
	}

	if(zoneDesc.m_customSkyBoxName)
	{
		INT32 len = strlen(zoneDesc.m_customSkyBoxName);
		m_customSkyBoxName = ruNEW char [len + 1];
		memcpy(m_customSkyBoxName, zoneDesc.m_customSkyBoxName, sizeof(char) * (len + 1));
	}

	m_frameRateMultiplier = zoneDesc.m_frameRateMultiplier;

	if(zoneDesc.m_ambientSound)
	{
		delete[] m_ambientSound;
		m_ambientSound = ruNEW char [strlen(zoneDesc.m_ambientSound) + 1];
		strcpy(m_ambientSound, zoneDesc.m_ambientSound);
	}

	if(zoneDesc.m_themeMusic)
	{
		delete[] m_themeMusic;
		m_themeMusic = ruNEW char [strlen(zoneDesc.m_themeMusic) + 1];
		strcpy(m_themeMusic, zoneDesc.m_themeMusic);
	}
}

CRuGaia_ZoneDescriptor &CRuGaia_ZoneDescriptor::operator=(const CRuGaia_ZoneDescriptor &zoneDesc)
{
	delete[] m_name;
	m_name = NULL;

	m_id = zoneDesc.m_id;
	m_timeGroup = zoneDesc.m_timeGroup;
	m_weatherGroup = zoneDesc.m_weatherGroup;
	
	if(zoneDesc.m_name)
	{
		INT32 len = strlen(zoneDesc.m_name);
		m_name = ruNEW char [len + 1];
		memcpy(m_name, zoneDesc.m_name, sizeof(char) * (len + 1));
	}

	CopySettings(zoneDesc);

	return *this;
}

BOOL CRuGaia_ZoneDescriptor::SerializeFrom(IRuStream *stream)
{
	// Read signature and version
	INT32 signature;
	INT32 version = 1;
	stream->Read(&signature, sizeof(INT32));

	if(signature == 0xFFFFFFFF)
	{
		// Signature found, read version 
		stream->Read(&version, sizeof(INT32));
	}
	else
	{
		// No signature, this is an old model stream, so rewind
		stream->Seek(-4, ruSSM_Current);
	}

	switch(version)
	{
		case 1:
			{
				// Read zone ID
				stream->Read(&m_id, sizeof(INT32));

				// Read time group
				stream->Read(&m_timeGroup, sizeof(INT32));

				// Read weather group
				stream->Read(&m_weatherGroup, sizeof(INT32));

				// Read length of zone name including NULL
				INT32 zoneNameLength;
				stream->Read(&zoneNameLength, sizeof(INT32));

				// Read zone name
				if(zoneNameLength > 0)
				{
					m_name = ruNEW char [zoneNameLength];
					stream->Read(m_name, sizeof(char) * zoneNameLength);
				}

				// Read primary color
				stream->Read(&m_color_Primary, sizeof(DWORD));

				// Read secondary color
				stream->Read(&m_color_Secondary, sizeof(DWORD));

				// Read ambient color
				stream->Read(&m_color_Ambient, sizeof(DWORD));

				// Read specular color
				stream->Read(&m_color_Specular, sizeof(DWORD));

				// Read fog color
				stream->Read(&m_color_Fog, sizeof(DWORD));

				// Read fog start
				stream->Read(&m_fog_Start, sizeof(float));

				// Read fog end
				stream->Read(&m_fog_End, sizeof(float));

				// Read theta
				stream->Read(&m_theta_Standard, sizeof(float));

				// Read phi
				stream->Read(&m_phi_Standard, sizeof(float));

				// Read theta
				stream->Read(&m_theta_Specular, sizeof(float));

				// Read phi
				stream->Read(&m_phi_Specular, sizeof(float));

				stream->Read(&m_cloud_HorizonColor, sizeof(DWORD));

				stream->Read(&m_cloud_OverheadColor, sizeof(DWORD));

				stream->Read(&m_cloud_HorizonCount, sizeof(INT32));

				stream->Read(&m_cloud_OverheadCount, sizeof(INT32));

				// Read length of sky gradient texture name including NULL
				INT32 skyGradientTextureNameLength;
				stream->Read(&skyGradientTextureNameLength, sizeof(INT32));

				// Read sky gradient texture name
				if(skyGradientTextureNameLength > 0)
				{
					m_skyGradientTextureName = ruNEW char [skyGradientTextureNameLength];
					stream->Read(m_skyGradientTextureName, sizeof(char) * skyGradientTextureNameLength);
				}

				// Read length of horizon cloud texture name including NULL
				INT32 horizonCloudTextureNameLength;
				stream->Read(&horizonCloudTextureNameLength, sizeof(INT32));

				// Read horizon cloud texture name
				if(horizonCloudTextureNameLength > 0)
				{
					m_horizonCloudTextureName = ruNEW char [horizonCloudTextureNameLength];
					stream->Read(m_horizonCloudTextureName, sizeof(char) * horizonCloudTextureNameLength);
				}

				// Read length of overhead cloud texture name including NULL
				INT32 overheadCloudTextureNameLength;
				stream->Read(&overheadCloudTextureNameLength, sizeof(INT32));

				// Read overhead cloud texture name
				if(overheadCloudTextureNameLength > 0)
				{
					m_overheadCloudTextureName = ruNEW char [overheadCloudTextureNameLength];
					stream->Read(m_overheadCloudTextureName, sizeof(char) * overheadCloudTextureNameLength);
				}

				// Read cloud mode
				stream->Read(&m_cloudMode, sizeof(DWORD));
			}

			break;

		case 2:
			{
				// Read zone ID
				stream->Read(&m_id, sizeof(INT32));

				// Read time group
				stream->Read(&m_timeGroup, sizeof(INT32));

				// Read weather group
				stream->Read(&m_weatherGroup, sizeof(INT32));

				// Read length of zone name including NULL
				INT32 zoneNameLength;
				stream->Read(&zoneNameLength, sizeof(INT32));

				// Read zone name
				if(zoneNameLength > 0)
				{
					m_name = ruNEW char [zoneNameLength];
					stream->Read(m_name, sizeof(char) * zoneNameLength);
				}

				// Read primary color
				stream->Read(&m_color_Primary, sizeof(DWORD));

				// Read secondary color
				stream->Read(&m_color_Secondary, sizeof(DWORD));

				// Read ambient color
				stream->Read(&m_color_Ambient, sizeof(DWORD));

				// Read specular color
				stream->Read(&m_color_Specular, sizeof(DWORD));

				// Read fog color
				stream->Read(&m_color_Fog, sizeof(DWORD));

				// Read fog start
				stream->Read(&m_fog_Start, sizeof(float));

				// Read fog end
				stream->Read(&m_fog_End, sizeof(float));

				// Read theta
				stream->Read(&m_theta_Standard, sizeof(float));

				// Read phi
				stream->Read(&m_phi_Standard, sizeof(float));

				// Read theta
				stream->Read(&m_theta_Specular, sizeof(float));

				// Read phi
				stream->Read(&m_phi_Specular, sizeof(float));

				stream->Read(&m_cloud_HorizonColor, sizeof(DWORD));

				stream->Read(&m_cloud_OverheadColor, sizeof(DWORD));

				stream->Read(&m_cloud_HorizonCount, sizeof(INT32));

				stream->Read(&m_cloud_OverheadCount, sizeof(INT32));

				// Read length of sky gradient texture name including NULL
				INT32 skyGradientTextureNameLength;
				stream->Read(&skyGradientTextureNameLength, sizeof(INT32));

				// Read sky gradient texture name
				if(skyGradientTextureNameLength > 0)
				{
					m_skyGradientTextureName = ruNEW char [skyGradientTextureNameLength];
					stream->Read(m_skyGradientTextureName, sizeof(char) * skyGradientTextureNameLength);
				}

				// Read length of horizon cloud texture name including NULL
				INT32 horizonCloudTextureNameLength;
				stream->Read(&horizonCloudTextureNameLength, sizeof(INT32));

				// Read horizon cloud texture name
				if(horizonCloudTextureNameLength > 0)
				{
					m_horizonCloudTextureName = ruNEW char [horizonCloudTextureNameLength];
					stream->Read(m_horizonCloudTextureName, sizeof(char) * horizonCloudTextureNameLength);
				}

				// Read length of overhead cloud texture name including NULL
				INT32 overheadCloudTextureNameLength;
				stream->Read(&overheadCloudTextureNameLength, sizeof(INT32));

				// Read overhead cloud texture name
				if(overheadCloudTextureNameLength > 0)
				{
					m_overheadCloudTextureName = ruNEW char [overheadCloudTextureNameLength];
					stream->Read(m_overheadCloudTextureName, sizeof(char) * overheadCloudTextureNameLength);
				}

				// Read length of custom sky box name including NULL
				INT32 customSkyBoxNameLength;
				stream->Read(&customSkyBoxNameLength, sizeof(INT32));

				// Read custom sky box name
				if(customSkyBoxNameLength > 0)
				{
					m_customSkyBoxName = ruNEW char [customSkyBoxNameLength];
					stream->Read(m_customSkyBoxName, sizeof(char) * customSkyBoxNameLength);
				}

				// Write frame rate multiplier
				stream->Read(&m_frameRateMultiplier, sizeof(REAL));

				// Read cloud mode
				stream->Read(&m_cloudMode, sizeof(DWORD));
			}

			break;

		case 3:
			{
				// Read zone ID
				stream->Read(&m_id, sizeof(INT32));

				// Read time group
				stream->Read(&m_timeGroup, sizeof(INT32));

				// Read weather group
				stream->Read(&m_weatherGroup, sizeof(INT32));

				// Read length of zone name including NULL
				INT32 zoneNameLength;
				stream->Read(&zoneNameLength, sizeof(INT32));

				// Read zone name
				if(zoneNameLength > 0)
				{
					m_name = ruNEW char [zoneNameLength];
					stream->Read(m_name, sizeof(char) * zoneNameLength);
				}

				// Read primary color
				stream->Read(&m_color_Primary, sizeof(DWORD));

				// Read secondary color
				stream->Read(&m_color_Secondary, sizeof(DWORD));

				// Read ambient color
				stream->Read(&m_color_Ambient, sizeof(DWORD));

				// Read specular color
				stream->Read(&m_color_Specular, sizeof(DWORD));

				// Read fog color
				stream->Read(&m_color_Fog, sizeof(DWORD));

				// Read fog start
				stream->Read(&m_fog_Start, sizeof(float));

				// Read fog end
				stream->Read(&m_fog_End, sizeof(float));

				// Read theta
				stream->Read(&m_theta_Standard, sizeof(float));

				// Read phi
				stream->Read(&m_phi_Standard, sizeof(float));

				// Read theta
				stream->Read(&m_theta_Specular, sizeof(float));

				// Read phi
				stream->Read(&m_phi_Specular, sizeof(float));

				stream->Read(&m_cloud_HorizonColor, sizeof(DWORD));

				stream->Read(&m_cloud_OverheadColor, sizeof(DWORD));

				stream->Read(&m_cloud_HorizonCount, sizeof(INT32));

				stream->Read(&m_cloud_OverheadCount, sizeof(INT32));

				// Read length of sky gradient texture name including NULL
				INT32 skyGradientTextureNameLength;
				stream->Read(&skyGradientTextureNameLength, sizeof(INT32));

				// Read sky gradient texture name
				if(skyGradientTextureNameLength > 0)
				{
					m_skyGradientTextureName = ruNEW char [skyGradientTextureNameLength];
					stream->Read(m_skyGradientTextureName, sizeof(char) * skyGradientTextureNameLength);
				}

				// Read length of horizon cloud texture name including NULL
				INT32 horizonCloudTextureNameLength;
				stream->Read(&horizonCloudTextureNameLength, sizeof(INT32));

				// Read horizon cloud texture name
				if(horizonCloudTextureNameLength > 0)
				{
					m_horizonCloudTextureName = ruNEW char [horizonCloudTextureNameLength];
					stream->Read(m_horizonCloudTextureName, sizeof(char) * horizonCloudTextureNameLength);
				}

				// Read length of overhead cloud texture name including NULL
				INT32 overheadCloudTextureNameLength;
				stream->Read(&overheadCloudTextureNameLength, sizeof(INT32));

				// Read overhead cloud texture name
				if(overheadCloudTextureNameLength > 0)
				{
					m_overheadCloudTextureName = ruNEW char [overheadCloudTextureNameLength];
					stream->Read(m_overheadCloudTextureName, sizeof(char) * overheadCloudTextureNameLength);
				}

				// Read length of custom sky box name including NULL
				INT32 customSkyBoxNameLength;
				stream->Read(&customSkyBoxNameLength, sizeof(INT32));

				// Read custom sky box name
				if(customSkyBoxNameLength > 0)
				{
					m_customSkyBoxName = ruNEW char [customSkyBoxNameLength];
					stream->Read(m_customSkyBoxName, sizeof(char) * customSkyBoxNameLength);
				}

				// Write frame rate multiplier
				stream->Read(&m_frameRateMultiplier, sizeof(REAL));

				// Read cloud mode
				stream->Read(&m_cloudMode, sizeof(DWORD));

				// Read ambient sound
				INT32 ambientSoundLength;
				stream->Read(&ambientSoundLength, sizeof(INT32));
				m_ambientSound = ruNEW char [ambientSoundLength];
				stream->Read(m_ambientSound, ambientSoundLength);

				// Read theme music
				INT32 themeMusicLength;
				stream->Read(&themeMusicLength, sizeof(INT32));
				m_themeMusic = ruNEW char [themeMusicLength];
				stream->Read(m_themeMusic, themeMusicLength);
			}

			break;
	}

	// Error trapping
	if(m_id < 0 || m_timeGroup < 0 || m_weatherGroup < 0)
	{
		return FALSE;
	}

	return TRUE;
}

BOOL CRuGaia_ZoneDescriptor::SerializeTo(IRuStream *stream)
{
	// Write signature
	INT32 signature = 0xFFFFFFFF;
	stream->Write(&signature, sizeof(INT32));

	// Write version
	INT32 version = 3;
	stream->Write(&version, sizeof(INT32));

	// Stream identification key
	stream->Write(&m_id, sizeof(INT32));
	stream->Write(&m_timeGroup, sizeof(INT32));
	stream->Write(&m_weatherGroup, sizeof(INT32));

	// Write length of zone name including NULL
	INT32 zoneNameLength = m_name ? strlen(m_name) + 1 : 0;
	stream->Write(&zoneNameLength, sizeof(INT32));

	// Write zone name
	if(zoneNameLength > 0)
	{
		stream->Write(m_name, sizeof(char) * zoneNameLength);
	}

	// Colors
	stream->Write(&m_color_Primary, sizeof(DWORD));
	stream->Write(&m_color_Secondary, sizeof(DWORD));
	stream->Write(&m_color_Ambient, sizeof(DWORD));
	stream->Write(&m_color_Specular, sizeof(DWORD));
	stream->Write(&m_color_Fog, sizeof(DWORD));

	// Fog
	stream->Write(&m_fog_Start, sizeof(float));
	stream->Write(&m_fog_End, sizeof(float));

	// Light setup
	stream->Write(&m_theta_Standard, sizeof(float));
	stream->Write(&m_phi_Standard, sizeof(float));
	stream->Write(&m_theta_Specular, sizeof(float));
	stream->Write(&m_phi_Specular, sizeof(float));

	// Cloud setup
	stream->Write(&m_cloud_HorizonColor, sizeof(DWORD));
	stream->Write(&m_cloud_OverheadColor, sizeof(DWORD));
	stream->Write(&m_cloud_HorizonCount, sizeof(INT32));
	stream->Write(&m_cloud_OverheadCount, sizeof(INT32));

	// Write length of sky gradient texture name including NULL
	INT32 skyGradientTextureNameLength = m_skyGradientTextureName ? strlen(m_skyGradientTextureName) + 1 : 0;
	stream->Write(&skyGradientTextureNameLength, sizeof(INT32));

	// Write sky gradient texture name
	if(skyGradientTextureNameLength > 0)
	{
		stream->Write(m_skyGradientTextureName, sizeof(char) * skyGradientTextureNameLength);
	}

	// Write length of horizon cloud texture name including NULL
	INT32 horizonCloudTextureNameLength = m_horizonCloudTextureName ? strlen(m_horizonCloudTextureName) + 1 : 0;
	stream->Write(&horizonCloudTextureNameLength, sizeof(INT32));

	// Write horizon cloud texture name
	if(horizonCloudTextureNameLength > 0)
	{
		stream->Write(m_horizonCloudTextureName, sizeof(char) * horizonCloudTextureNameLength);
	}

	// Write length of overhead cloud texture name including NULL
	INT32 overheadCloudTextureNameLength = m_overheadCloudTextureName ? strlen(m_overheadCloudTextureName) + 1 : 0;
	stream->Write(&overheadCloudTextureNameLength, sizeof(INT32));

	// Write overhead cloud texture name
	if(overheadCloudTextureNameLength > 0)
	{
		stream->Write(m_overheadCloudTextureName, sizeof(char) * overheadCloudTextureNameLength);
	}

	// Write length of overhead cloud texture name including NULL
	INT32 customSkyBoxNameLength = m_customSkyBoxName ? strlen(m_customSkyBoxName) + 1 : 0;
	stream->Write(&customSkyBoxNameLength, sizeof(INT32));

	// Write overhead cloud texture name
	if(customSkyBoxNameLength > 0)
	{
		stream->Write(m_customSkyBoxName, sizeof(char) * customSkyBoxNameLength);
	}

	// Write frame rate multiplier
	stream->Write(&m_frameRateMultiplier, sizeof(REAL));

	// Write cloud mode
	stream->Write(&m_cloudMode, sizeof(DWORD));

	// Write ambient sound
	if(m_ambientSound)
	{
		INT32 ambientSoundLength = strlen(m_ambientSound) + 1;
		stream->Write(&ambientSoundLength, sizeof(INT32));
		stream->Write(m_ambientSound, ambientSoundLength);
	}
	else
	{
		INT32 ambientSoundLength = 1;
		stream->Write(&ambientSoundLength, sizeof(INT32));
		stream->Write("", ambientSoundLength);
	}

	// Write theme music
	if(m_themeMusic)
	{
		INT32 themeMusicLength = strlen(m_themeMusic) + 1;
		stream->Write(&themeMusicLength, sizeof(INT32));
		stream->Write(m_themeMusic, themeMusicLength);
	}
	else
	{
		INT32 themeMusicLength = 1;
		stream->Write(&themeMusicLength, sizeof(INT32));
		stream->Write("", themeMusicLength);
	}

	return TRUE;
}

// ************************************************************************************************************************************************************

CRuGaia_Base::~CRuGaia_Base()
{
}

// ************************************************************************************************************************************************************

#pragma managed
