/*********************************************************************//**
*	BaseMoveable
*	Abstraktni trida definuje specialni typ funkci, ktere se mohou
*	pohybovat po predem dane draze.
*	
*	author: Michal Jirous
*	date: 23.04.2009
*	file: ent_basemoveable.cpp
**********************************************************************/

#include "ent_basemoveable.h"
#include "level_decals.h"

CBaseMoveable::CBaseMoveable() : CBaseFunction()
{
	m_fVelocityScalar = 0.0f;
	m_iStatus = STATUS_STOPPED;
	m_pSortBoundingBox = &m_RenderBounds;
	m_bCollisionBlocked = false;
	
}


void CBaseMoveable::setParameters( parameters_t &parametersMap )
{
	CBaseEntity::setParameters( parametersMap );
 
	m_Store_ModelOrigin = origin;
	m_Store_Target = origin;
	m_Store_StartOrigin = origin;
}

bool CBaseMoveable::renderCullTest( RenderData &renderData )
{
	m_bRenderSelf = false;
	if( renderData.frustum->isBoundsInsideFrustum( m_RenderBounds ) )
		m_bRenderSelf = true;
	return (m_bRenderSelf || decalSystem.containDecals(m_SolidModel));
}

void CBaseMoveable::render( RenderData &renderData )
{
	m_Interpolation.drawRun( renderData.frameTimes.period_percentage );
	Point translation( m_Interpolation.current - m_Store_ModelOrigin );
	glPushMatrix();
	glTranslatef( translation.x, translation.y, translation.z );

	(*renderData.cameraPosition) -= translation;
	setRenderMode();

	basicSolidRender( renderData );

	unsetRenderMode();
	(*renderData.cameraPosition) += translation;

	glPopMatrix();
}


bool CBaseMoveable::collisionDetection( CollisionData &collData )
{
	if( !m_bCollisionBlocked && collData.model.m_DynamicBounds.compare( *m_pSortBoundingBox ) )
	{
		return collDet( collData );
	}
	return false;
}

bool CBaseMoveable::collDet(  CollisionData &collData )
{
	//target = origin
	Point translation( origin - m_Store_ModelOrigin );
	collData.model.translateAll( -translation );
	bool c = basicSolidCollisionDetection( collData );
	collData.model.translateAll( translation );
	return c;
}


bool CBaseMoveable::forceCollisionDetection( CollisionData &collData )
{
	if( !m_bCollisionBlocked && collData.model.m_DynamicBounds.compare( m_CollisionBounds ) )
	{
		return collDet( collData );
	}
	return false;
}


bool CBaseMoveable::rayTrace( RayTraceData &rayData )
{
	Point r;
	if( m_CollisionBounds.lineIntersect( rayData.ray.m_vecDirection, rayData.ray, r ) )
	{
		Point translation( origin - m_Store_ModelOrigin );
		rayData.ray -= translation;
		rayData.vzdaleny -= translation;
	
		bool c = basicSolidRayTracing( rayData );

		rayData.ray += translation;
		rayData.vzdaleny += translation;

		return c;
	}
	return false;
}


void CBaseMoveable::update( float seconds )
{
	CBaseFunction::update( seconds );
	//m_pSortBoundingBox ukazuje na bounding box modelu
	m_RenderBounds = *m_pSortBoundingBox;	//nastavime zakladni hodnoty render bounds
	if( m_iStatus == STATUS_MOVING )
	{
		origin += m_NextMovement;	//next movement je tady aktualnim vektorem pohybu, ktery se ma provest
		(*m_pSortBoundingBox).translate( m_NextMovement );

		m_RenderBounds.updateData( *m_pSortBoundingBox );	//nyni uz by mel byt tento bounding box posunuty, takze render bounds protahne
	}
	
	m_CollisionBounds = *m_pSortBoundingBox;	//zakladem ja aktualni bounding box modelu

	m_Interpolation.update( origin );
	
	Vector diff = m_Target - origin;
	float size = diff.absolute();	//vzdalenost k cili
	if( fabs(size) > 0.0f )
	{
		if( m_iStatus == STATUS_STOPPED )
		{
			m_iStatus = STATUS_MOVING;
			onStartMoving();
		}

		diff.normalize();
		m_NextMovement = diff * std::min( size, m_fVelocityScalar );	//nastavime vektor pohybu
		m_CollisionBounds.translate( m_NextMovement );	//protahneme bounding box do budoucnosti
		m_CollisionBounds.updateData( *m_pSortBoundingBox );
	}
	else
	{
		if( m_iStatus == STATUS_MOVING )
		{
			m_iStatus = STATUS_STOPPED;
			onReachTarget();
		}

		m_NextMovement.clear();
	}
	
	
	
}


void CBaseMoveable::restart()
{
	CBaseFunction::restart();
	(*m_pSortBoundingBox).translate( m_Store_StartOrigin - origin );
	origin = m_Store_StartOrigin;
	m_iStatus = STATUS_STOPPED;
	m_NextMovement.clear();	//zadny pohyb
	update( 0.03f );	//vypocita nam to pocatecni vektor pohybu
}

void CBaseMoveable::compile()
{
	CBaseFunction::compile();
	m_iStatus = STATUS_STOPPED;
	m_Store_StartOrigin = origin;
	m_Store_Target = m_Target;
	//update( 0.03f );	//vypocita nam to pocatecni vektor pohybu
}

#include "game.h"

void CBaseMoveable::updateBackTime()
{
	CBaseFunction::updateBackTime();

	//ulozime pozici
	m_BackTimeData.push_front( BackTimeData() );
	m_BackTimeData.front().event_time = game.getGameTime();
	m_BackTimeData.front().type = EVENT_POSITION;
	(*((Point*)&(m_BackTimeData.front().values.position))) = origin;

	//ulozime cil
	m_BackTimeData.push_front( BackTimeData() );
	m_BackTimeData.front().event_time = game.getGameTime();
	m_BackTimeData.front().type = EVENT_TARGET;
	(*((Point*)&(m_BackTimeData.front().values.position))) = m_Target;

	//ulozime next movement vektor
	m_BackTimeData.push_front( BackTimeData() );
	m_BackTimeData.front().event_time = game.getGameTime();
	m_BackTimeData.front().type = EVENT_VELOCITY;
	(*((Point*)&(m_BackTimeData.front().values.position))) = m_NextMovement;

	//a ulozime si taky jeste status
	m_BackTimeData.push_front( BackTimeData() );
	m_BackTimeData.front().event_time = game.getGameTime();
	m_BackTimeData.front().type = EVENT_STATUS;
	m_BackTimeData.front().values.event = m_iStatus;	
}


void CBaseMoveable::goBackInTime()
{
	CBaseFunction::goBackInTime();

	//musime si vytahnout posledni zaznamy
	Point oldOrigin;
	Vector oldNextMovement;
	int oldStatus;
	Point oldTarget;

	int valuesCount = 0;
	for( std::list<BackTimeData>::reverse_iterator riter = m_BackTimeData.rbegin(); riter != m_BackTimeData.rend() && valuesCount != 4; ++riter )
	{
		if( (*riter).type == EVENT_BORDER )	//na border bych tu nemel narazit
			return;

		if( (*riter).type == EVENT_POSITION )
		{
			valuesCount++;
			oldOrigin = Point( (*riter).values.position );
		}
		else if( (*riter).type == EVENT_TARGET )
		{
			valuesCount++;
			oldTarget = Point( (*riter).values.position );
		}
		else if( (*riter).type == EVENT_VELOCITY )
		{
			valuesCount++;
			oldNextMovement = Point( (*riter).values.position );
		}
		else if( (*riter).type == EVENT_STATUS )
		{
			valuesCount++;
			oldStatus = (*riter).values.event;
		}
	}

	//zbyva spocitat bounding boxy
	(*m_pSortBoundingBox).translate( oldOrigin - origin );
	m_RenderBounds = *m_pSortBoundingBox;
	m_Interpolation.current = m_Interpolation.target = m_Interpolation.start = origin;	//zadna interpolace
	
	m_CollisionBounds = *m_pSortBoundingBox;
	m_CollisionBounds.translate( oldNextMovement );
	m_CollisionBounds.updateData( *m_pSortBoundingBox );
	
	m_NextMovement = oldNextMovement;
	m_Target = oldTarget;
	m_iStatus = oldStatus;
	origin = oldOrigin;
}
