#ifndef _CKNOCKBACKCONTROLLER
#define _CKNOCKBACKCONTROLLER

#include "types.h"

#include "Kyoto/Animation/CPASAnimState.hpp"

class CDamageInfo;
class CPatterned;

enum EKnockBackType {
  kKBT_Radius,
  kKBT_Direct,
};
enum EKnockBackVariant {
  kKBV_Small,
  kKBV_Medium,
  kKBV_Large,
};
enum EKnockBackWeaponType {
  kKBWT_Invalid = -1,
  kKBWT_Power,
  kKBWT_PowerCharged,
  kKBWT_PowerComboed,
  kKBWT_PowerComboedDirect,
  kKBWT_Wave,
  kKBWT_WaveCharged,
  kKBWT_WaveComboed,
  kKBWT_WaveComboedDirect,
  kKBWT_Ice,
  kKBWT_IceCharged,
  kKBWT_IceComboed,
  kKBWT_IceComboedDirect,
  kKBWT_Plasma,
  kKBWT_PlasmaCharged,
  kKBWT_PlasmaComboed,
  kKBWT_Missile,
  kKBWT_Bomb,
  kKBWT_PowerBomb,
  kKBWT_Phazon,
};
enum EKnockBackCharacterState {
  kKBCS_Alive,
  kKBCS_Dead,
  kKBCS_FrozenAlive,
  kKBCS_FrozenDead,
};
enum EKnockBackAnimationState {
  kKBAS_Invalid = -1,
  kKBAS_None,
  kKBAS_Flinch,
  kKBAS_KnockBack,
  kKBAS_Hurled,
  kKBAS_Fall,
};
enum EKnockBackAnimationFollowUp {
  kKBAFU_Invalid = -1,
  kKBAFU_None,
  kKBAFU_Freeze,
  kKBAFU_Shock,
  kKBAFU_Burn,
  kKBAFU_PhazeOut,
  kKBAFU_Death,
  kKBAFU_ExplodeDeath,
  kKBAFU_IceDeath,
  kKBAFU_BurnDeath,
  kKBAFU_LaggedBurnDeath,
};

class CKnockBackController {
  friend class CPatterned;

public:
  struct KnockBackParms {
    EKnockBackAnimationState x0_animState;
    EKnockBackAnimationFollowUp x4_animFollowup;
    float x8_followupDuration;
    float xc_intoFreezeDur;
  };

  explicit CKnockBackController(EKnockBackVariant variant);
  void SetKnockBackVariant(EKnockBackVariant v) { x0_variant = v; }
  void DeferKnockBack(EWeaponType tp) {
    x14_deferWeaponType = tp;
    x68_deferRemTime = 0.05f;
  }
  void sub80233d40(int i, float f1, float f2);
  void SetAutoResetImpulse(bool b);
  void SetImpulseDurationIdx(int i);
  void SetAnimationStateRange(EKnockBackAnimationState a, EKnockBackAnimationState b);/* {
    x18_minAnimState = a;
    x1c_maxAnimState = b;
  }*/
  void Update(float dt, CStateManager& mgr, CPatterned& parent);
  void KnockBack(const CVector3f& backVec, CStateManager& mgr, CPatterned& parent,
                 const CDamageInfo& info, EKnockBackType type, float magnitude);

  void ApplyImpulse(float dt, CPatterned& parent);
  bool TickDeferredTimer(float dt);
  EKnockBackCharacterState GetKnockBackCharacterState(const CPatterned& parent) const;
  void ValidateState(const CPatterned& parent);
  float CalculateExtraHurlVelocity(CStateManager& mgr, float magnitude, float kbResistance) const;
  void DoKnockBackAnimation(const CVector3f& backVec, CStateManager& mgr, CPatterned& parent,
                            float magnitude);
  void ResetKnockBackImpulse(const CPatterned& parent, const CVector3f& backVec,
                             float magnitude);
  void DoDeferredKnockBack(CStateManager& mgr, CPatterned& parent);
  EKnockBackWeaponType GetKnockBackWeaponType(const CDamageInfo& info, EWeaponType wType,
                                              EKnockBackType type);
  void SelectDamageState(const CPatterned& parent, const CDamageInfo& info, EWeaponType wType,
                         EKnockBackType type);

  void SetSeverity(pas::ESeverity v) { x7c_severity = v; }
  void SetEnableFreeze(bool b) { x81_25_enableFreeze = b; }
  bool GetEnableFreeze() const { return x81_25_enableFreeze; }
  void SetEnableShock(bool b) { x81_26_enableShock = b; }
  void SetEnableBurn(bool b) { x81_27_enableBurn = b; }
  void SetEnableBurnDeath(bool b) { x81_28_enableBurnDeath = b; }
  void SetEnableExplodeDeath(bool b) { x81_29_enableExplodeDeath = b; }
  void SetEnableLaggedBurnDeath(bool b) { x81_30_enableLaggedBurnDeath = b; }
  void SetX81_31(bool b) { x81_31_ = b; }
  void SetX82_24(bool b) { x82_24_ = b; }
  void SetLocomotionDuringElectrocution(bool b) { x82_26_locomotionDuringElectrocution = b; }
  const KnockBackParms& GetActiveParms() const { return x4_activeParms; }
  EKnockBackVariant GetVariant() const { return x0_variant; }
  float GetFlinchRemTime() const { return x64_flinchRemTime; }
  // void SetAvailableState(EKnockBackAnimationState s, bool b) {
  //   x80_availableStates.set(size_t(s), b);
  // }
  // bool TestAvailableState(EKnockBackAnimationState s) const {
  //   return x80_availableStates.test(size_t(s));
  // }

private:
  EKnockBackVariant x0_variant;
  KnockBackParms x4_activeParms;
  EWeaponType x14_deferWeaponType;
  EKnockBackAnimationState x18_minAnimState;
  EKnockBackAnimationState x1c_maxAnimState;
  uint x20_impulseDurationIdx;
  rstl::reserved_vector< rstl::pair< float, float >, 5 > x24_;
  CVector3f x50_impulseDir;
  float x5c_impulseMag;
  float x60_impulseRemTime;
  float x64_flinchRemTime;
  float x68_deferRemTime;
  uint x6c_;
  uint x70_;
  uint x74_;
  uint x78_;
  pas::ESeverity x7c_severity;
  uchar x80_availableStates;
  bool x81_24_autoResetImpulse : 1;
  bool x81_25_enableFreeze : 1;
  bool x81_26_enableShock : 1;
  bool x81_27_enableBurn : 1;
  bool x81_28_enableBurnDeath : 1;
  bool x81_29_enableExplodeDeath : 1;
  bool x81_30_enableLaggedBurnDeath : 1;
  bool x81_31_ : 1;
  bool x82_24_ : 1;
  bool x82_25_inDeferredKnockBack : 1;
  bool x82_26_locomotionDuringElectrocution : 1;
};
CHECK_SIZEOF(CKnockBackController, 0x84)

#endif // _CKNOCKBACKCONTROLLER
