#pragma once

#include <GR/GRTypes.h>

#include <Interface/IAnimationManager.h>

#include <list>

#include <Math/Iterator/IteratorChain.h>

#include "PacTypes.h"



class XRenderer;
class PlayState;

class Unit
{

  public:

    enum eUnitEvent
    {
      ET_INVALID,
      ET_INIT,
      ET_BLOCKED_LEFT,
      ET_BLOCKED_RIGHT,
      ET_BLOCKED_UP,
      ET_BLOCKED_DOWN,
      ET_FALL_START,
      ET_FALL_END,
      ET_DIE,
      ET_CARRY,
      ET_DROP,
      ET_MOVED_LEFT,
      ET_MOVED_RIGHT,
      ET_MOVED_UP,
      ET_MOVED_DOWN,
      ET_ENTER_PLATFORM,
      ET_LEAVE_PLATFORM,
      ET_GET_CAUGHT
    };


    Pac::eUnitTypes           m_Type;

    std::list<Unit*>          m_CarriedUnits;

    bool                      m_RemoveMe,
                              m_Jumping,
                              m_OnGround,
                              m_FaceLeft,
                              m_Floating,
                              m_IsPlatform,
                              m_IsNasty,
                              m_NoAutoAdjustFacing,
                              m_DisplayHit,
                              m_CoordinatesWrapAround,
                              m_DisplayBlinking,
                              m_DisplayBlinkingFast,
                              m_HasKey;

    math::Iterator::Chain                   m_DisplayBlinkingChain;
    math::Iterator::Chain                   m_DisplayBlinkingChainFast;
    math::Iterator::Chain::tIteratorPos     m_DisplayBlinkingChainPos;
    math::Iterator::Chain::tIteratorPos     m_DisplayBlinkingChainFastPos;

    std::string               m_Image;
    std::string               m_Animation;

    GR::tPoint                m_Position;
    GR::tPoint                m_StartPosition;
    GR::tPoint                m_Speed;
    GR::tPoint                m_DisplayOffset;

    int                       m_JumpSpeed;
    int                       m_FallSpeed;
    int                       m_FallSpeedDelay;
    int                       m_HP;
    int                       m_PlayerIndex;
    int                       m_Invincibility;
    int                       m_MoveSpeed;
    int                       m_MoveSpeedFract;

    GR::f32                   m_LifeTime;
    GR::f32                   m_HitDisplayTime;

    GR::tRect                 m_MovementBounds;
    GR::tRect                 m_CollisionBounds;

    tAnimationPos             m_AnimPos;

    GR::u32                   m_ExtraData;
    GR::u32                   m_ExtraData2;

    Unit*                     m_pOnUnit;

    int                       m_TileOffset;
    GR::tPoint                m_TilePos;
    Pac::eDir                 m_MoveDir;


    Unit();
    virtual ~Unit();


    virtual void              Display( const GR::tPoint& ptOffset, XRenderer& Renderer );
    virtual void              Update( PlayState& State, const GR::f32 fElapsedTime );
    virtual void              UpdateFixed( PlayState& State );

    GR::tRect                 MovementBounds();
    GR::tRect                 CollisionBounds();

    void                      SetAnimation( const std::string& Animation );
    void                      SetImage( const std::string& Image );

    virtual void              ProcessEvent( PlayState& State, const eUnitEvent& Event );

    bool                      Jump( int Power );

    static Unit*              FromType( const Pac::eUnitTypes UnitType );

    bool                      Move( PlayState& State, const GR::tPoint& Delta, bool bMovedByPlatform = false );
    void                      MoveUnblocked( PlayState& State, int DX, int DY );
    void                      MoveCarriedUnits( PlayState& State, int iDX, int iDY );

    virtual void              OnSpawned( PlayState& State );

    void                      SetHit();

};


