//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_FaceHugger_Movement.h
//
// Copyright (C) 2008 Rebellion. All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// 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 __AVP_BEHAVIOUR_FACEHUGGER_MOVEMENT_H__
#define __AVP_BEHAVIOUR_FACEHUGGER_MOVEMENT_H__ 1

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

// I N C L U D E S ///////////////////////////////////////////////////////////

// asura
#include "Core/Asura_TemplateTree.h"

// avp axon
#include "Behaviour/Axon_Project_Behaviour.h"
#include "Core/AVP_Navigation.h"

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////

class AVP_Brain_Actor_FaceHugger;
class AVP_Brain_Actor;
using namespace AVP_Navigation;

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_Predator_Movement
//
//////////////////////////////////////////////////////////////////////////////

class AVP_Behaviour_FaceHugger_Movement : public Axon_Project_Behaviour
{
	typedef Axon_Project_Behaviour PARENT;

public:
	AVP_Behaviour_FaceHugger_Movement( AVP_Brain_Actor* pxBrain );

	enum ExMovementMode
	{
		EMM_IDLE = -1,
		EMM_SLOW = 0,
		EMM_MEDIUM,
		EMM_FAST,		
	};


	bool GetToPosition(const Asura_Vector_3& xDestination, bool bRefineRoot = false);
	bool GetToPosition(const Asura_Vector_3& xDestination, const Asura_Vector_3& xAvoidPosition, float fMinDistance, float fMaxDistance, const Asura_Vector_3& xPrefDirection);
	bool GetToPosition(const Asura_Vector_3& xDestination, AVP_Navigation::AStarFunctorBase& xFunctor, float fArriveRange, bool bRefineRoot = false);
	void SetMovementMode(ExMovementMode eMoveMode);
	void SetAvoidLight();

	float GetLengthLeftOnPath() const;


	static int GetAnimStateFromMovementMode( ExMovementMode eMovementMode );

protected:
	virtual bool HandleMessage( const Asura_Message* pxMessage );
	virtual bool Activate();
	virtual void Deactivate();
	virtual void Update( const float fTimeslice );
	virtual void PerFrameUpdate( const float fTimeslice );

#ifndef ASURA_NO_DEBUG_OUTPUT
	virtual void RenderDebugInfo();
#endif

	AVP_Brain_Actor_FaceHugger* GetActorBrain() const;

private:
	enum State
	{
		UNSET,
		TRAVERSING_STANDARD_LINK,
		TRAVERSING_JUMP_LINK,
		MOVING_TO_DESTINATION,
		RESOLVE_STUCK_BY_JUMPING,
		FALLING,
		FINISHED,
		NUM_STATES
	};

	void SwitchToState( const State eNextState );
	void UpdateFollowPoint();
	void UpdatePositionOnRoute();
	void UpdateStuckDetection( const float fTimeslice );
	void CalculateAvoidanceSteering( const Asura_Vector_3& xFollowPointSteering, Asura_Vector_3& xSteering ) const;
	Asura_Vector_3 MergeSteering(const Asura_Vector_3& xToDirection, const Asura_Vector_3& xAvoidanceDirection) const;
	void UpdateMovementLimit();
	void UpdateMovementMode();
	bool NeedToRestartAfterFalling( float fTimeslice );

	bool FindNearestPointOnRoute( const AVP_Navigation::NavData& xNavData, const Asura_Vector_3& xCurrentPosition, const Asura_Vector_3& xActorUp,
								  float fLookAheadDistance, Asura_Vector_3& xNearestPosition, u_short& usNearestRouteSegmentIndex );
	void ClearWPDistanceCache();
	float FindDistanceOfWPFromStart(u_short usWPNumber);
	void FindNextJumpIndex(); 
	void UpdateStuckDetection( const float fTimeslice, bool bLargeAvoidanceSteering );
	bool AttemptJumpToUnStuck();
	void RequestJumpLink();
	void RequestJumpMove( Asura_Hash_ID uMoveHashID, const Asura_Vector_3& xDestPos, const Asura_Vector_3& xDestNormal);

	void CalculateJumpDestinationOrientation(Asura_Matrix_3x3& xOrientation, Asura_Vector_3 xDestinationPosition, Asura_Vector_3 xDestinationNormal) const; 

	State m_eCurrentState;
	float m_fTimeInState;
	float  m_fArrivalRange;

	Asura_Vector_3 m_xPositionOnRoute;
	Asura_Vector_3 m_xFollowPoint;
	u_short m_usFollowPointWPIndex;
	Asura_Vector_3 m_xDestination;
	Asura_Vector_3 m_xAvoidPosition;
	float m_fAvoidDistance;
	bool m_bAvoiding;
	bool m_bStuck;
	ExMovementMode m_eLimitMoveMode;
	ExMovementMode m_eRequestedMoveMode;
	ExMovementMode m_eActualMoveMode;
	float m_fRouteTraversedDistance;
	float m_fRouteTotalDistance;
	u_short m_usNextValidForJumpIndex;
	u_short m_usLastValidForJumpIndex;
	Asura_Vector_3 m_xNextJumpPoint;
	Asura_TemplateTree< u_short, float > m_xWPDistanceFromStartCache;

	float m_fTimeInStuckOnPath;
	float m_fFramesInStuckOnPath;
	float m_fTimeCheckOrientationAndPositionStuck;
	float m_fFramesCheckOrientationAndPositionStuck;
	float m_fMaxRouteTraversedDistance;
	float m_fLastMaxRouteFraction;	
	Asura_Matrix_3x3 m_xLastOrientation;
	Asura_Vector_3 m_xLastPosition;
	bool m_bTryToUnstuckByJumping;
	bool m_bAvoidLight;
#ifndef ASURA_NO_DEBUG_OUTPUT
	Asura_Vector_3 m_xFollowSteering;
	Asura_Vector_3 m_xAvoidanceSteering;
	Asura_Vector_3 m_xFinalSteering;
#endif

};

class AVP_Behaviour_FaceHugger_GS2_Movement : public Axon_Project_Behaviour
{
	typedef Axon_Project_Behaviour PARENT;

public:
	AVP_Behaviour_FaceHugger_GS2_Movement( AVP_Brain_Actor* pxBrain );
	bool GetToPosition( const Asura_Vector_3& xPosition );

	virtual void ReadFromChunkStream( Asura_Chunk_Stream& xStream );
	virtual void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;

protected:
	virtual void PerFrameUpdate( const float fTimeslice );

private:
	AVP_Brain_Actor_FaceHugger* GetActorBrain() const;
	
	bool m_bIsMovePending;
	Asura_Vector_3 m_xPosition;
	int m_iRetries;

	enum { CURRENT_CHUNK_VERSION = 0 };
};

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////

#endif //__AVP_BEHAVIOUR_FACEHUGGER_MOVEMENT_H__
