//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_AVP3Alien_GetToPosition.h
//
// Copyright (C) 2007 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_AVP3ALIEN_GETTOPOSITION_H__
#define __AVP_BEHAVIOUR_AVP3ALIEN_GETTOPOSITION_H__ 1

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

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

// 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 Axon_Project_Brain;

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_AVP3Alien_GetToPosition
//
//////////////////////////////////////////////////////////////////////////////

class AVP_Behaviour_AVP3Alien_Movement : public Axon_Project_Behaviour
{
    typedef Axon_Project_Behaviour PARENT;

public:
    AVP_Behaviour_AVP3Alien_Movement( Axon_Project_Brain* pxProjectBrain );
    virtual ~AVP_Behaviour_AVP3Alien_Movement() {}

    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 );

    void SetArrivalRange( const float fArrivalRange ) { m_fArrivalRange = fArrivalRange; }

    // If you want to specify a particular route type, arrival range, etc, you must do so before calling these functions.
    bool GetToPosition( const Asura_Vector_3& xDestination );
    bool GetAwayFromPosition( const Asura_Vector_3& xPosition, const float fRange );

    // To update the destination whilst the character is traversing a route.
    bool UpdateDestination( const Asura_Vector_3& xDestinationPosition );

#ifndef ASURA_NO_DEBUG_OUTPUT
    virtual void RenderDebugInfo();
#endif

private:
    enum State
    {
        UNSET,
        MOVING_TO_POINT,
        TRANSITION_SLOW,
        TRANSITION_JUMP,
        TRANSITION_STANDARD,
        MOVING_TO_DESTINATION,
        FINISHED,
        NUM_STATES
    };
    void  SwitchToState( const State eNextState );
    void  UpdateCurrentWaypoint();
    void  UpdateFollowPoint();
    void  UpdateNearbyGuidData( const float fTimeslice );
    void  FindNearbyGuidData();
    void  CalculateCollisionAvoidanceSteering( const Asura_Vector_3& xFollowPointSteering, Asura_Vector_3& xSteering );
    void  CalculateFollowPointSteering( Asura_Vector_3& xSteering );
    // Analyse the route and work out which transitions we need to make at which route index.
    void  CalculateRouteTransitions();
    u_int GetAlienAnimState( const AVP_Navigation::MovementMode eMovementMode ) const;
    u_int GetMovementAnim( const AVP_Navigation::MovementMode eMovementMode, const bool bForceOnWall = false ) const;
    void  SwitchToTransitionState();

private:
    State          m_eCurrentState;
    float          m_fTimeInState;
    Asura_Vector_3 m_xNearestPositionOnRoute;
    Asura_Vector_3 m_xFollowPoint;
    bool           m_bPointAtDestination;
    float          m_fArrivalRange;
    // Used for detecting if we get stuck.
    // If our follow point stops moving we're obviously making no headway along the route.
    Asura_Vector_3 m_xPrevNearestPositionOnRoute;
    float          m_fSmoothedPORVelocity;

    enum { MAX_ROUTE_TRANSITIONS = 16 };
    struct TransitionData 
    {
        u_short        m_usLinkTransitionType;
        u_short        m_usRouteIndex;
        Asura_Vector_3 m_xDestinationPosition;
        Asura_Vector_3 m_xDestinationNormal;
        // If we're travelling fast we should jump if possible.
        bool           m_bPotentialJump;
    }              m_axTransitionData[ MAX_ROUTE_TRANSITIONS ];
    u_short        m_usNumTransitions;
    u_short        m_usTransitionIndex;

    // Nearby guid stuff for collision avoidance test.
    float          m_fNearbyUpdateTimer;
    // The nearby range is based on speed and the character's bounding box dimensions.
    float          m_fNearbyBaseRange;
    enum { MAX_NEARBY_GUIDS = 8 };
    struct NearbyGuidData
    {
        Asura_Guid     m_uGuid;
        Asura_Vector_3 m_xFromGuid;
        float          m_fRange;
    }              m_axNearbyGuidData[ MAX_NEARBY_GUIDS ];
    u_int          m_uNumNearbyGuids;

    float          m_fDbgNearbyRange;
    Asura_Vector_3 m_xDbgCollisionAvoidanceVector;
    Asura_Vector_3 m_xDbgRouteSteeringVector;
    Asura_Vector_3 m_xDbgFinalSteeringVector;
};

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

#endif //__AVP_BEHAVIOUR_AVP3ALIEN_GETTOPOSITION_H__
