//////////////////////////////////////////////////////////////////////////////
//
// Asura_PosAndOriInterpolator.h
//
// Copyright (c) 2004 Rebellion. All rights reserved.
//
// Description:
//
//     class to manage interpolating position and orientation for entities.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef ___ASURA_POSANDORIINTERPOLATOR_H___
#define ___ASURA_POSANDORIINTERPOLATOR_H___ 1

#include "Core/Asura_Maths.h"
#include "Entity/Asura_Entity_Renderable.h"	// for timelag type enum

class Asura_PosAndOriInterpolator
{

public:
	
	Asura_PosAndOriInterpolator();
	~Asura_PosAndOriInterpolator();
#if _DEBUG
	static u_int s_uNumPosAndOriInterpolators;
#endif

	void GetCurrentPosition(Asura_Vector_3& xOutputPos, Asura_Vector_3& xOutputVel) const;
	//void GetCurrentVelocity(Asura_Vector_3& xOutputVel) const;
	void GetCurrentOrientation(Asura_Matrix_3x3& xOutputMat) const;
	void GetCurrentAngularVelocity(Asura_Euler_3& xEuler) const;
	void ProcessNewData(const Asura_Vector_3& xPosition, 
						const Asura_Quat& xOrientation,
                        float fServerTimestamp,
						const Asura_Vector_3* pxActualVel = NULL );

	bool IsMoving() const;

	void TeleportTo(const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation);
	const Asura_Vector_3& GetLastReportedPosition() const;
	const Asura_Quat& GetLastReportedOrientation() const;
	float GetLastReportedServerTime() const; // Note: this includes the "process new data increment".

	void InitialiseMovingObject(const Asura_Vector_3& xPosition, 
								const Asura_Quat& xOrientQuat,
								const Asura_Vector_3& xVelocity,
								float fServerTime);

	void SetTimeLagType(Asura_Entity_Renderable::TimeLagType eType) { m_eTimeLagType = eType; }
	void SetCollisionObject(const class Asura_Collision_Object* pxCollObj, Asura_Handle iDynamicsHandleToIgnore = ASURA_INVALID_HANDLE)
	{ 
		m_pxCollisionObject = pxCollObj; 
		m_iDynamicsHandleToIgnore = iDynamicsHandleToIgnore;
	}

	void SetUseCubicSplineInterpolation(bool bEnable);
	bool IsUsingCubicSplineInterpolation() { return m_pxSpline != NULL; }

	void	SetProcessNewDataIncrement	(const float fIncrement)	{ m_fProcessNewDataIncrement = fIncrement; }
	float	GetProcessNewDataIncrement	(void) const				{ return(m_fProcessNewDataIncrement); }

private:
	
	struct Asura_PosAndOriArrayEntry
	{
		Asura_Vector_3 m_xPosition;
		Asura_Quat m_xQuat;
		float m_fServerTime;
	};

	static const u_int uTOTALENTRIES = 2;
	Asura_PosAndOriArrayEntry m_axEntries[uTOTALENTRIES];
	int m_iLatestEntry;
	float m_fProcessNewDataIncrement;

	mutable Asura_Vector_3 m_xCurrentPos;
	mutable Asura_Vector_3 m_xCurrentVel;
	mutable float m_fCurPosTime;

	Asura_Entity_Renderable::TimeLagType m_eTimeLagType;
	class Asura_HermiteSpline* m_pxSpline;
	float m_fSplineStart;
	float m_fSplineEnd;
	const class Asura_Collision_Object* m_pxCollisionObject;
	Asura_Handle m_iDynamicsHandleToIgnore;

	// *pVelOutput is only written to if moving.
	void GetPosAndVel(Asura_Vector_3& xPosOutput, Asura_Vector_3& xVelOutput, float fTime, float fMaxExtrapolation) const;
	void CalculateCubicSpline(const Asura_Vector_3& xPos0, const Asura_Vector_3& xPos1, const Asura_Vector_3& xVel0, const Asura_Vector_3& xVel1, float fStartTime, float fEndTime);
	void InvalidateCache();
};

// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

#endif // #ifndef ___ASURA_POSANDORIINTERPOLATOR_H___
