///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Animation_BodyRig.h
// Author : Will Plano
// Date   : 31/01/2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __AVP_ANIMATION_BODYRIG_H__
#define __AVP_ANIMATION_BODYRIG_H__

#include "Animation/Asura_Animation_BoneDataModifier.h"
#include "Core/Asura_Maths.h"

class Asura_PosAndOriInterpolator;

class AVP_ClientEntity_Actor;
class AVP_ClientActor_Vertebrate;
class AVP_Direction_Interpolator;

class AVP_Animation_BodyRig : public Asura_Animation_BoneDataModifier
{
public:
	AVP_Animation_BodyRig( AVP_ClientEntity_Actor& xOwnerActor );
	virtual	~AVP_Animation_BodyRig();

	void	Update();

	// Asura_Animation_BoneDataModifier functions
	virtual void	UpdateTimers( const float fTime );
	virtual void	UpdateBoneData( const int iFirstBone, const int iLastBone );

	void	SetAimAnimations( const Asura_Hash_ID uAimDownUpHash, const Asura_Hash_ID uAimDownUpDragHash, const Asura_Hash_ID uAimRightLeftHash, const Asura_Hash_ID uAimRightLeftDragHash, const Asura_Hash_ID uStrafeDragHash, const float fTweemTime ); // this will start tweening to the new animations straight away
	void	SetTurnAnimations( const Asura_Hash_ID uTurn45LeftAnimHash, const Asura_Hash_ID uTurn45RightAnimHash, const Asura_Hash_ID uTurn90LeftAnimHash, const Asura_Hash_ID uTurn90RightAnimHash, const Asura_Hash_ID uTurn180LeftAnimHash, const Asura_Hash_ID uTurn180RightAnimHash ) { m_uTurn45LeftAnimHash = uTurn45LeftAnimHash; m_uTurn45RightAnimHash = uTurn45RightAnimHash;  m_uTurn90LeftAnimHash = uTurn90LeftAnimHash; m_uTurn90RightAnimHash = uTurn90RightAnimHash; m_uTurn180LeftAnimHash = uTurn180LeftAnimHash; m_uTurn180RightAnimHash = uTurn180RightAnimHash;}
	
	void	GetAimDirection( Asura_AVector3& xOutDirection ) const;
	void	SetAimDirection( const Asura_AVector3& xDirection, const float fTime );
	void	ResetAimDirection( const Asura_AVector3& xDirection );

	void	GetLookAtPosition( Asura_AVector3& xOutPosition ) const;
	void	SetLookAtPosition( const Asura_AVector3& xPosition, const float fTime );
	void	ResetLookAtPosition( const Asura_AVector3& xPosition );

	float	GetMaxAimRightLeft() const			{ return m_fMaxAimRightLeft; }
	void	SetMaxAimRightLeft( float fMax )	{ m_fMaxAimRightLeft = fMax; }

	float	GetEyeSquint() const				{ return m_fEyeSquint; }
	void	SetEyeSquint( const float fSquint )	{ m_fEyeSquint = fSquint; }

	float	GetEyeRestClose() const				{ return m_fEyeRestClose; }
	void	SetEyeRestClose( const float fClose )	{ m_fEyeRestClose = fClose; }

	void	SetBlinkDuration( const float fBlinkDuration )	{ m_fHalfBlinkDuration = 0.5f * fBlinkDuration; }
	void	SetBlinkRate( const float fMinBlinksPerMinute, const float fMaxBlinksPerMinute )	{ m_fMinBlinkTime = 60.0f / fMaxBlinksPerMinute; m_fMaxBlinkTime = 60.0f / fMinBlinksPerMinute; }
	void	Blink();

	void	RequestTurn( const float fTurnAngle );
	bool	IsTurning();

	float	GetTurnAnimAngVel() const { return m_fCurrentTurnAngVel; }

	void	SetTargetAimRightLeftDragValue( const float fVal ) { m_fTargetAimRightLeftDragValue = fVal; }
	void	SetTargetAimDownUpDragValue( const float fVal ) { m_fTargetAimDownUpDragValue = fVal; }
	void	SetTargetStrafeDragValue( const float fVal ) { m_fTargetStrafeDragValue = fVal; }

protected:

private:
	typedef Asura_Animation_BoneDataModifier PARENT;

	enum BlinkState
	{
		BLINK_OPEN,
		BLINK_CLOSING,
		BLINK_OPENING,

		NUM_BLINK
	};

	enum LookState
	{
		LOOKSTATE_TWEENIN,
		LOOKSTATE_CAMERA,
		LOOKSTATE_TWEENOUT,
		LOOKSTATE_FWD,

		NUM_LOOKSTATE
	};

	AVP_Animation_BodyRig();
	AVP_Animation_BodyRig( const AVP_Animation_BodyRig& );
	AVP_Animation_BodyRig& operator=(const AVP_Animation_BodyRig& xOther);

	void UpdateNeckBone();
	void UpdateEyeBones();

	void UpdateTurning();
	void UpdateAimAnims();

	void UpdateBlinking();
	void UpdateLookAtCamera();

	void PlayTurnAnim(const Asura_Hash_ID uTurnAnimHash, const bool bHUD, const float fAngVelScale );
	void StopTurnAnim();

	void CalculateEyeDirectionData( float& fLeftRightOut, float& fUpDownOut, float& fFocusOut );

#ifndef ASURA_NO_DEBUG_OUTPUT
	void RenderDebugOutput();
#endif

	AVP_ClientEntity_Actor&				m_xOwnerActor;

	AVP_Direction_Interpolator*			m_pxAimDirInterpolator;		// Worldspace, If we're setting the look/aim directions via update messages over the network, then we'd better slerpolate them. ( Yeah, I invented a new word, do you like it? )
	Asura_PosAndOriInterpolator*		m_pxLookAtPosInterpolator;

	Asura_Hash_ID						m_uRLAimGroupHash;			// The group for our right to left aim anims to go into.
	Asura_Hash_ID						m_uDUAimGroupHash;			// The group for our down to up aim anims to go into.
	Asura_Hash_ID						m_uRLDragGroupHash;
	Asura_Hash_ID						m_uDUDragGroupHash;
	Asura_Hash_ID						m_uStrafeDragGroupHash;

	Asura_Hash_ID						m_uTurn45LeftAnimHash;
	Asura_Hash_ID						m_uTurn45RightAnimHash;
	Asura_Hash_ID						m_uTurn90LeftAnimHash;
	Asura_Hash_ID						m_uTurn90RightAnimHash;
	Asura_Hash_ID						m_uTurn180LeftAnimHash;
	Asura_Hash_ID						m_uTurn180RightAnimHash;
	Asura_Hash_ID						m_uTurnAACAHash;			// The hash-ID of the animation controller.
	float								m_fCurrentTurnAngle;
	float								m_fCurrentTurnAngVel;

	Asura_Hash_ID						m_uAimDownUpAACAHash;		// The hash-ID of the animation controller.
	Asura_Hash_ID						m_uAimDownUpDragAACAHash;		// The hash-ID of the animation controller.
	Asura_Hash_ID						m_uAimRightLeftAACAHash;	// The hash-ID of the animation controller.
	Asura_Hash_ID						m_uAimRightLeftDragAACAHash;	// The hash-ID of the animation controller.
	Asura_Hash_ID						m_uStrafeDragAACAHash;	// The hash-ID of the animation controller.

	Asura_Hash_ID						m_uAimDownUpAnimHash;		// The hash-ID of the animation.
	Asura_Hash_ID						m_uAimDownUpDragAnimHash;		// The hash-ID of the animation.
	Asura_Hash_ID						m_uAimRightLeftAnimHash;	// The hash-ID of the animation.
	Asura_Hash_ID						m_uAimRightLeftDragAnimHash;	// The hash-ID of the animation.
	Asura_Hash_ID						m_uStrafeDragAnimHash;	// The hash-ID of the animation.

	Asura_AVector3						m_xAimDirection;			// Worldspace, do not use these variables if we're using Slerpolators as they won't be kept up to date.
	Asura_AVector3						m_xLookAtPosition;

	Asura_Quat							m_xNeckParentRestPoseQuatOS;
	Asura_Quat							m_xEyeParentRestPoseQuatOS;

	Asura_Euler_3						m_xCurrentNeckEuler;

	float								m_fIdleTimer;				// This timer counts up when our velocity is zero and is reset when it's not.

	float								m_fCurrentAimRightLeftDragValue;
	float								m_fCurrentAimDownUpDragValue;
	float								m_fCurrentStrafeDragValue;

	float								m_fTargetAimRightLeftDragValue;
	float								m_fTargetAimDownUpDragValue;
	float								m_fTargetStrafeDragValue;

	float								m_fLookDownToUpParametric;
	float								m_fLookDownToUpDragParametric;
	float								m_fLookRightToLeftParametric;
	float								m_fLookRightToLeftDragParametric;
	float								m_fStrafeDragParametric;

	float								m_fMaxAimDownUp;
	float								m_fMaxAimRightLeft;

	float								m_fNeckBlend;

	float								m_fMaxNeckDownUp;
	float								m_fMaxNeckRightLeft;
	float								m_fMaxNeckTilt;

	float								m_fNeckTilt;

	float								m_fHeadRightLeftAngSpeed;
	float								m_fHeadDownUpAngSpeed;
	float								m_fHeadTiltAngSpeed;

	float 								m_fHeadRandomVelocityX;
	float 								m_fHeadRandomVelocityY;
	float 								m_fHeadRandomDisplacementX;
	float 								m_fHeadRandomDisplacementY;

	float								m_fEyeNaturalFocusAngle;
	//	Eyelid stuff
	float								m_fEyeCurrentClose;
	float								m_fEyeRestClose;
	float								m_fEyeSquint;
	float								m_fEyeBalance;

	// Blink stuff
	float								m_fHalfBlinkDuration;
	float								m_fMinBlinkTime;
	float								m_fMaxBlinkTime;
	float								m_fBlinkTimer;
	BlinkState							m_eBlinkState;

	// Look at camera stuff
	float								m_fLookAtCameraParameter;
	float								m_fLookTweenTime;
	float								m_fMinLookAtCameraTime;
	float								m_fMaxLookAtCameraTime;
	float								m_fMinLookFwdTime;
	float								m_fMaxLookFwdTime;
	float								m_fLookTimer;
	LookState							m_eLookState;

	int									m_iNeckBoneIndex;
	int									m_iLeftEyeBoneIndex;
	int									m_iRightEyeBoneIndex;
	
#if defined(ASURA_SUPPORT_COMMAND_CONSOLE)
	static u_int s_uConsoleVarReferenceCount;
#endif
};

#endif
