
//! \file DtCigiBaseDiGuyCtrlExt.h
//! \brief Contains makVrv::DtCigiBaseDiGuyCtrlExt class
//! \ingroup vrvCigi

#pragma once

#include <makCigiExtensions/makCigiExtensions.h>

#include <CigiBaseVariableSizePckt.h>

#include <string>

namespace makCigiExt
{

   const int CIGI_DI_GUY_CTRL_EXT_PACKET_ID = 202;

   // This is the size of the FIXED portion of the packet
   const int CIGI_DI_GUY_CTRL_EXT_PACKET_SIZE = 32;

   const int CIGI_DI_GUY_CTRL_EXT_PACKET_ID_V4 = 0xf000;

   // This is the size of the FIXED portion of the packet
   const int CIGI_DI_GUY_CTRL_EXT_PACKET_SIZE_V4 = 32;

   //=========================================================
   //! The base class for all DiGuy Control (extended) packets.
   //!
   class DT_DLL_MAKCIGIEXTENSIONS DtCigiBaseDiGuyCtrlExt :
      public CigiBaseVariableSizePckt
   {
   public:
      //=========================================================
      //! The enumeration for the Animation Paused/Not Paused flag
      //!
      enum AnimationStateGrp
      {
         Unpaused=0,
         Paused=1
      };

      //=========================================================
      //! The enumeration for the Weapon State flag
      //!
      enum WeaponStateGrp
      {
         Stowed=0, 
         Deployed=1 
      };

      //=========================================================
      //! The enumeration for the Posture flags
      //!
      enum PostureGrp
      {
         Standing=0, 
         Sitting=1, 
         Crouched=2, 
         Prone=3
      };

      //=========================================================
      //! The enumeration for the Health flag
      //!
      enum HealthStateGrp
      {
         Alive=0,
         Dead=1
      };

      //==> Management

      //=========================================================
      //! General Constructor
      //!
      DtCigiBaseDiGuyCtrlExt(void);

      //=========================================================
      //! General Destructor
      //!
      virtual ~DtCigiBaseDiGuyCtrlExt(void);

      //=========================================================
      //! Copy Constructor
      //!
      DtCigiBaseDiGuyCtrlExt(const DtCigiBaseDiGuyCtrlExt &BaseIn);

      //=========================================================
      //! Assignment operator
      //!
      DtCigiBaseDiGuyCtrlExt& operator=(const DtCigiBaseDiGuyCtrlExt& BaseIn);

      //==> Buffer Packing/Unpacking

      //=========================================================
      //! A pure virtual Pack function.  
      //! This function is not implemented in this class.
      //! \param Base - A pointer to the instance of the packet 
      //!          to be packed. (Downcast to CigiBasePacket)
      //! \param Buff - A pointer to the current pack point.
      //! \param Spec - A pointer to special data.
      //!
      //! \return This returns CIGI_SUCCESS or an error code 
      //!   defined in CigiErrorCodes.h
      //!
      virtual int Pack(CigiBasePacket * Base, Cigi_uint8 * Buff, void *Spec) const = 0;

      //=========================================================
      //! A pure virtual Unpack function.
      //! This function is not implemented in this class.
      //! \param Buff - A pointer to the current pack point.
      //! \param Swap - N/A for V1 & V2
      //! \param Spec - A pointer to special data.
      //!
      //! \return This returns CIGI_SUCCESS or an error code 
      //!   defined in CigiErrorCodes.h
      //!
      virtual int Unpack(Cigi_uint8 * Buff, bool Swap, void *Spec) = 0;

      //=========================================================
      //! A virtual function to determine the size that the
      //!  packet will take up when packed.
      //! \param refPacket - A pointer to the packet being checked.
      //!
      //! \return The size that the packet will take up when packed
      //!
      virtual int GetTruePacketSize(CigiBaseVariableSizePckt &refPacket)
      { return(PacketSize + refPacket.GetVariableDataSize()); }

      //==> Accessing Member Variable Values functions

      //+> EntityID

      //=========================================================
      //! Sets the Entity ID with bound checking control
      //! \param EntityIDIn - Uniquely identifies the specific entity
      //!   0 - The ownship
      //!   All other values - An Application defined entity
      //! \param bndchk - Enables (true) or disables (false) bounds checking
      //!
      //! \return This returns CIGI_SUCCESS or an error code 
      //!   defined in CigiErrorCodes.h
      //!
      int SetEntityID(const Cigi_uint16 EntityIDIn, bool bndchk=true)
      {
         myEntityID = EntityIDIn;
         return(CIGI_SUCCESS);
      }

      //=========================================================
      //! Gets the Entity ID value
      //! \return EntityID uniquely identifies the specific entity
      //!   0 - The ownship
      //!   All other values - An Application defined entity
      //!
      Cigi_uint16 GetEntityID(void) const { return(myEntityID); }

      //+> PostureEn

      //=========================================================
      //! Sets the PostureEn with bound checking control
      //! \param PostureEnIn - Specifies if the posture data is valid
      //!   and to be used.
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetPostureEn(const bool PostureEnIn, bool bndchk=true)
      {
         myPostureEn = PostureEnIn;
         return(CIGI_SUCCESS);
      }

      //=========================================================
      //! Gets the PostureEn value.
      //! \return the current PostureEn.
      bool GetPostureEn(void) const { return(myPostureEn); }

      //+> Posture

      //=========================================================
      //! Sets the Posture with bound checking control
      //! \param PostureIn - Specifies the DiGuy's posture
      //! 0 Standing 
      //! 1 Sitting
      //! 2 Crouched 
      //! 3 Prone
      //! \param bndchk - Enables (true) or disables (false) bounds checking
      //!
      //! \return This returns CIGI_SUCCESS or an error code 
      //!   defined in CigiErrorCodes.h
      //!
      int SetPosture(const PostureGrp PostureIn, bool bndchk=true);

      //=========================================================
      //! Gets the Posture value
      //! \return Posture specifies the DIGuy's posture
      //! 0 Standing 
      //! 1 Sitting
      //! 2 Crouched 
      //! 3 Prone
      //!
      PostureGrp GetPosture(void) const { return(myPosture); }

      //+> WeaponStateEn

      //=========================================================
      //! Sets the WeaponStateEn with bound checking control
      //! \param WeaponStateEnIn - Specifies if the weaponState data is valid
      //!   and to be used.
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetWeaponStateEn(const bool WeaponStateEnIn, bool bndchk=true)
      {
         myWeaponStateEn = WeaponStateEnIn;
         return(CIGI_SUCCESS);
      }

      //=========================================================
      //! Gets the WeaponStateEn value.
      //! \return the current WeaponStateEn.
      bool GetWeaponStateEn(void) const { return(myWeaponStateEn); }

      //+> WeaponState

      //=========================================================
      //! Sets the WeaponState with bound checking control
      //! \param WeaponStateIn - Specifies the DiGuy's weaponState
      //! 0 Stowed 
      //! 1 Deployed
      //! \param bndchk - Enables (true) or disables (false) bounds checking
      //!
      //! \return This returns CIGI_SUCCESS or an error code 
      //!   defined in CigiErrorCodes.h
      //!
      int SetWeaponState(const WeaponStateGrp WeaponStateIn, bool bndchk=true);

      //=========================================================
      //! Gets the WeaponState value
      //! \return WeaponState specifies the DIGuy's weaponState
      //! 0 Stowed 
      //! 1 Deployed
      //!
      WeaponStateGrp GetWeaponState(void) const { return(myWeaponState); }

      //+> AnimationStateEn

      //=========================================================
      //! Sets the AnimationStateEn with bound checking control
      //! \param AnimationStateEnIn - Specifies if the animationState data is valid
      //!   and to be used.
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetAnimationStateEn(const bool AnimationStateEnIn, bool bndchk=true)
      {
         myAnimationStateEn = AnimationStateEnIn;
         return(CIGI_SUCCESS);
      }

      //=========================================================
      //! Gets the AnimationStateEn value.
      //! \return the current AnimationStateEn.
      bool GetAnimationStateEn(void) const { return(myAnimationStateEn); }

      //+> AnimationState

      //=========================================================
      //! Sets the AnimationState with bound checking control
      //! \param AnimationStateIn - Specifies the DiGuy's animation state
      //! 0 Unpaused 
      //! 1 Paused
      //! \param bndchk - Enables (true) or disables (false) bounds checking
      //!
      //! \return This returns CIGI_SUCCESS or an error code 
      //!   defined in CigiErrorCodes.h
      //!
      int SetAnimationState(const AnimationStateGrp AnimationStateIn, bool bndchk=true);

      //=========================================================
      //! Gets the AnimationState value
      //! \return AnimationState specifies the DIGuy's animation state
      //! 0 Unpaused 
      //! 1 Paused
      //!
      AnimationStateGrp GetAnimationState(void) const { return(myAnimationState); }

      //+> HealthStateEn

      //=========================================================
      //! Sets the HealthStateEn with bound checking control
      //! \param HealthStateEnIn - Specifies if the healthState data is valid
      //!   and to be used.
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetHealthStateEn(const bool HealthStateEnIn, bool bndchk=true)
      {
         myHealthStateEn = HealthStateEnIn;
         return(CIGI_SUCCESS);
      }

      //=========================================================
      //! Gets the HealthStateEn value.
      //! \return the current HealthStateEn.
      bool GetHealthStateEn(void) const { return(myHealthStateEn); }

      //+> HealthState

      //=========================================================
      //! Sets the HealthState with bound checking control
      //! \param HealthStateIn - Specifies the DiGuy's health state
      //! 0 Alive 
      //! 1 Dead
      //! \param bndchk - Enables (true) or disables (false) bounds checking
      //!
      //! \return This returns CIGI_SUCCESS or an error code 
      //!   defined in CigiErrorCodes.h
      //!
      int SetHealthState(const HealthStateGrp HealthStateIn, bool bndchk=true);

      //=========================================================
      //! Gets the HealthState value
      //! \return HealthState specifies the DIGuy's health state
      //! 0 Alive 
      //! 1 Dead
      //!
      HealthStateGrp GetHealthState(void) const { return(myHealthState); }

      //+> AnimationSpeedEn

      //=========================================================
      //! Sets the AnimationSpeedEn with bound checking control
      //! \param AnimationSpeedEnIn - Specifies if the animationSpeed data is valid
      //!   and to be used.
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetAnimationSpeedEn(const bool AnimationSpeedEnIn, bool bndchk=true)
      {
         myAnimationSpeedEn = AnimationSpeedEnIn;
         return(CIGI_SUCCESS);
      }

      //=========================================================
      //! Gets the AnimationSpeedEn value.
      //! \return the current AnimationSpeedEn.
      bool GetAnimationSpeedEn(void) const { return(myAnimationSpeedEn); }

      //+> Animation Speed

      //=========================================================
      //! Sets the AnimationSpeed
      //! \param AnimationSpeedIn - Specifies the animation speed
      //! If 0., DI-Guy picks the speed (which is the recommended usage)
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetAnimationSpeed(const double AnimationSpeedIn, bool bndchk=true);

      //=========================================================
      //! Gets the AnimationSpeed
      //! \return The speed of the Di-Guy action animation
      //!
      double GetAnimationSpeed(void) const { return(myAnimationSpeed); }

      //+> ScaleEn

      //=========================================================
      //! Sets the ScaleEn with bound checking control
      //! \param ScaleEnIn - Specifies if the Scale data is valid
      //!   and to be used.
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetScaleEn(const bool ScaleEnIn, bool bndchk=true)
      {
         myScaleEn = ScaleEnIn;
         return(CIGI_SUCCESS);
      }

      //=========================================================
      //! Gets the ScaleEn value.
      //! \return the current ScaleEn.
      bool GetScaleEn(void) const { return(myScaleEn); }

      //+> Scale

      //=========================================================
      //! Sets the Scale
      //! \param XScaleIn - Specifies the X Scale Factor
      //! \param YScaleIn - Specifies the Y Scale Factor
      //! \param ZScaleIn - Specifies the Z Scale Factor
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetScale(float XScaleIn, float YScaleIn, float ZScaleIn, bool bndchk=true);

      //=========================================================
      //! Gets the Scale
      //! \param[out] XScaleOut - The X Scale value
      //! \param[out] YScaleOut - The Y Scale value
      //! \param[out] ZScaleOut - The Z Scale value
      //!
      void GetScale(float& XScaleOut, float& YScaleOut, float& ZScaleOut ) const;

      //+> WeightEn

      //=========================================================
      //! Sets the WeightEn with bound checking control
      //! \param WeightEnIn - Specifies if the Weight data is valid
      //!   and to be used.
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetWeightEn(const bool WeightEnIn, bool bndchk=true)
      {
         myWeightEn = WeightEnIn;
         return(CIGI_SUCCESS);
      }

      //=========================================================
      //! Gets the WeightEn value.
      //! \return the current WeightEn.
      bool GetWeightEn(void) const { return(myWeightEn); }

      //+> Weight

      //=========================================================
      //! Sets the Weight
      //! \param WeightIn - Specifies the Weight
      //! \param bndchk - Enables (true) or disables (false) bounds checking.
      //!
      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetWeight(const float WeightIn, bool bndchk=true);

      //=========================================================
      //! Gets the Weight
      //! \return The Weight
      //!
      float GetWeight(void) const { return(myWeight); }

      //+> Animation

      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetAnimation(const std::string &AnimationIn, bool bndchk=true);

      //! \return The current size of the animation string.
      //!
      int GetAnimationSize(void) const { return(myAnimationSize); }

      //=========================================================
      //! Gets the Animation (Action) string
      //! \return The current animation
      const std::string & GetAnimation(void) const { return(myAnimation); }

      //+> Head Appearance

      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetHeadAppearance(const std::string &HeadAppearanceIn, bool bndchk=true);

      //! \return The current size of the head appearance string, padded to a multiple of
      //! 8 bytes (0 filled)
      //!
      int GetHeadAppearanceSize(void) const { return(myHeadAppearanceSize); }

      //=========================================================
      //! Gets the Head Appearance string
      //! \return The current Head Appearance
      const std::string & GetHeadAppearance(void) const { return(myHeadAppearance); }

      //+> Item Appearance

      //! \return This returns CIGI_SUCCESS or an error code
      //!   defined in CigiErrorCodes.h
      int SetItemAppearance(const std::string &ItemAppearanceIn, bool bndchk=true);

      //! \return The current size of the Item appearance string, padded to a multiple of
      //! 8 bytes (0 filled)
      //!
      int GetItemAppearanceSize(void) const { return(myItemAppearanceSize); }

      //=========================================================
      //! Gets the Item Appearance string
      //! \return The current Item Appearance
      const std::string & GetItemAppearance(void) const { return(myItemAppearance); }

   protected:
      static int CalculatePaddedStringSize( int StringSizeIn );
      static void BufferToString( PackPointer& CDta, std::string& StringOut );


   protected:

      Cigi_uint16 myEntityID;
      PostureGrp myPosture;
      WeaponStateGrp myWeaponState;
      int myAnimationSize;      // This is the string size padded to a multiple of 8
      std::string myAnimation;
      int myHeadAppearanceSize; // This is the string size padded to a multiple of 8
      std::string myHeadAppearance;
      int myItemAppearanceSize; // This is the string size padded to a multiple of 8
      std::string myItemAppearance;
      double myAnimationSpeed;
      AnimationStateGrp myAnimationState;
      HealthStateGrp myHealthState;
      float myXScale;
      float myYScale;
      float myZScale;
      float myWeight;

      bool myPostureEn;
      bool myWeaponStateEn;
      bool myAnimationStateEn;
      bool myAnimationSpeedEn;
      bool myHealthStateEn;
      bool myScaleEn;
      bool myWeightEn;

      //=========================================================
      //! MaxStringCharCnt<br>
      //! The maximum number of bytes not including NULLs for
      //! each string
      //!

      //! The minimum size is 32 + 8 (for three nulls plus padding)
      //! The maximum size is 248, leaving 216 for three strings (including
      //! 3 nulls). Each string is limited to a max length of 71 + null
      static const int MaxStringCharCnt = 71;  
   };
}

