#include "../../Scene/Controller/RuController_EventTrigger.h"

#pragma unmanaged

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

ruRTTI_DEFINE_SUBCLASS(CRuController_EventTrigger, IRuEntity_Controller)
ruHEAP_DEFINE_SUBCLASS(CRuController_EventTrigger, "CRuController_EventTrigger", "IRuEntity_Controller")
ruCLASSGUID_DEFINE(CRuController_EventTrigger, 0x02C2410D, 0x745B4e57, 0x967E7096, 0x5DB772FA)

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

CRuController_EventTrigger::CRuController_EventTrigger()
:	m_targetEntity(NULL),
	m_eventID(0),
	m_eventParameter0(0),
	m_eventParameter1(0),
	m_eventString(NULL)
{
	// Register as listener for self in order to handle the ruENTITYEVENT_ONDESTROY event.
	this->RegisterListener(this, NULL);
}

CRuController_EventTrigger::~CRuController_EventTrigger()
{
	// NOTE: Destruction of resources is done during the ruENTITYEVENT_ONDESTROY event.
}

IRuObject *CRuController_EventTrigger::Clone(IRuObject *clonedObject)
{
	// Create a new cloned entity if necessary
	clonedObject = clonedObject ? clonedObject : ruNEW CRuController_EventTrigger();
	CRuController_EventTrigger *controller = static_cast<CRuController_EventTrigger *>(clonedObject);

	// Chain cloning call to parent class
	IRuEntity_Controller::Clone(clonedObject);

	controller->m_eventID = m_eventID;
	controller->m_eventParameter0 = m_eventParameter0;
	controller->m_eventParameter1 = m_eventParameter1;

	if(m_eventString)
	{
		controller->SetEventString(m_eventString);
	}
	else
	{
		controller->m_eventString = NULL;
	}

	controller->m_eventDuration = m_eventDuration;

	return clonedObject;
}

BOOL CRuController_EventTrigger::SerializeFrom(IRuStream *stream)
{
	CRuGUID classGUID;

	// Read class GUID
	if(RuReadGUID(stream, classGUID) == FALSE)
	{
		return FALSE;
	}

	// Read version
	INT32 version = 1;
	stream->Read(&version, sizeof(INT32));

	// Chain serialization to base class
	IRuEntity_Controller::SerializeFrom(stream);

	switch(version)
	{
		case 1:
			{
				// Read event ID
				stream->Read(&m_eventID, sizeof(m_eventID));

				// Read event parameter 0
				stream->Read(&m_eventParameter0, sizeof(m_eventParameter0));

				// Read event parameter 1
				stream->Read(&m_eventParameter1, sizeof(m_eventParameter1));

				// Read event duration
				stream->Read(&m_eventDuration, sizeof(m_eventDuration));
			}

			break;

		case 2:
			{
				// Read event ID
				stream->Read(&m_eventID, sizeof(m_eventID));

				// Read event parameter 0
				stream->Read(&m_eventParameter0, sizeof(m_eventParameter0));

				// Read event parameter 1
				stream->Read(&m_eventParameter1, sizeof(m_eventParameter1));

				// Read event string
				INT32 eventStringLength;
				stream->Read(&eventStringLength, sizeof(INT32));
				m_eventString = ruNEW char [eventStringLength];
				stream->Read(m_eventString, eventStringLength);

				// Read event duration
				stream->Read(&m_eventDuration, sizeof(m_eventDuration));
			}

			break;
	}

	return TRUE;
}

BOOL CRuController_EventTrigger::SerializeTo(IRuStream *stream)
{
	// Write class GUID
	stream->Write(GetClassGUID().Data(), GetClassGUID().Size());

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

	// Chain serialization to base class
	IRuEntity_Controller::SerializeTo(stream);

	// Write event ID
	stream->Write(&m_eventID, sizeof(m_eventID));

	// Write event parameter 0
	stream->Write(&m_eventParameter0, sizeof(m_eventParameter0));

	// Write event parameter 1
	stream->Write(&m_eventParameter1, sizeof(m_eventParameter1));

	// Write event string
	if(m_eventString)
	{
		INT32 eventStringLength = strlen(m_eventString) + 1;
		stream->Write(&eventStringLength, sizeof(INT32));
		stream->Write(m_eventString, eventStringLength);
	}
	else
	{
		INT32 eventStringLength = strlen("") + 1;
		stream->Write(&eventStringLength, sizeof(INT32));
		stream->Write("", eventStringLength);
	}

	// Write event duration
	stream->Write(&m_eventDuration, sizeof(m_eventDuration));

	return TRUE;
}

BOOL CRuController_EventTrigger::Update(REAL elapsedTime)
{
	REAL relativeT = m_age;

	if(m_loopTime > 0.0f)
	{
		relativeT = fmod(m_age, m_loopTime);
	}

	if(m_enabled)
	{
		// Trigger check
		if(relativeT <= m_startTime)
		{
			relativeT += elapsedTime;

			// If we have hit the trigger time, raise the event
			if(relativeT > m_startTime)
			{
				if(m_targetEntity)
				{
					m_targetEntity->RaiseEvent(m_targetEntity, m_eventID, m_eventParameter0, m_eventParameter1, m_eventString, m_eventDuration);
				}
			}
		}
	}

	// Chain update call to base controller class
	return IRuEntity_Controller::Update(elapsedTime);
}

IRuObject *CRuController_EventTrigger::GetTarget()
{
	return m_targetEntity;
}

BOOL CRuController_EventTrigger::SetTarget(IRuObject *targetEntity)
{
	if(targetEntity->GetType().IsSubClassOf(CRuEntity::Type))
	{
		// If we had a previous target, unregister it
		if(m_targetEntity)
		{
			m_targetEntity->UnregisterListener(this);
		}

		// Store target reference and setup event listener
		m_targetEntity = static_cast<CRuEntity *>(targetEntity);
		m_targetEntity->RegisterListener(this, NULL);
	}

	return TRUE;
}

BOOL CRuController_EventTrigger::HandleEvent(CRuEntity *entity, INT32 eventID, INT32 eventParameter0, INT32 eventParameter1, const char *eventString, REAL eventDuration, void *userData)
{
	// Chain event handler to base class
	if(IRuEntity_Controller::HandleEvent(entity, eventID, eventParameter0, eventParameter1, eventString, eventDuration, userData) == TRUE)
	{
		return TRUE;
	}

	// Ensure that the broadcasting entity is the target entity for this controller or the controller itself
	if(entity != m_targetEntity && entity != this)
	{
		return FALSE;
	}

	// Handle event
	switch(eventID)
	{
		case ruENTITYEVENT_ONDESTROY:		// Target entity is being destroyed, unregister the controller
			{
				if(m_targetEntity)
				{
					m_targetEntity->UnregisterListener(this);
					m_targetEntity = NULL;
				}

				delete[] m_eventString;
			}

			break;
	}

	return FALSE;
}

INT32 CRuController_EventTrigger::GetEventID() const
{
	return m_eventID;
}

INT32 CRuController_EventTrigger::GetEventParameter0() const
{
	return m_eventParameter0;
}

INT32 CRuController_EventTrigger::GetEventParameter1() const
{
	return m_eventParameter1;
}

const char *CRuController_EventTrigger::GetEventString() const
{
	if(m_eventString)
	{
		return m_eventString;
	}

	return "";
}

REAL CRuController_EventTrigger::GetEventDuration() const
{
	return m_eventDuration;
}

void CRuController_EventTrigger::SetEventID(INT32 eventID)
{
	m_eventID = eventID;
}

void CRuController_EventTrigger::SetEventParameter0(INT32 eventParameter0)
{
	m_eventParameter0 = eventParameter0;
}

void CRuController_EventTrigger::SetEventParameter1(INT32 eventParameter1)
{
	m_eventParameter1 = eventParameter1;
}

void CRuController_EventTrigger::SetEventString(const char *eventString)
{
	delete[] m_eventString;

	m_eventString = ruNEW char [strlen(eventString) + 1];
	strcpy(m_eventString, eventString);
}

void CRuController_EventTrigger::SetEventDuration(REAL eventDuration)
{
	m_eventDuration = eventDuration;
}

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

#pragma managed
