//==============================================================================
// UnitOpportunity.h
// Copyright (c) 2007 Ensemble Studios
//==============================================================================

#pragma once
#include "Poolable.h"
#include "SimTarget.h"
#include "SimTypes.h"



//==============================================================================
//==============================================================================
class BUnitOpp: public IPoolable
{
   public:
      enum
      {
         cTypeNone=0,
         cTypeMove,
         cTypeAttack,
         cTypeSecondaryAttack,
         cTypeWork,
         cTypeCapture,
         cTypeJoin,
         cTypeMines,
         cTypeChangeMode,
         cTypeGarrison,
         cTypeEvade,
         cTypeCheer,
         cTypeUngarrison,
         cTypeRetreat,
         cTypeAnimation,
         cTypeReload,
         cTypeGather,
         cTypeRepair,
         cTypeHeal,
         cTypeUnpack,
         cTypeDeath,
         cTypeInfectDeath,
         cTypeHeroDeath,
         cTypeHitch,
         cTypeUnhitch,
         cTypeThrown,
         cTypeTransport,
         cTypeDetonate,
         cTypeInfect,
         cTypeJump,
         cTypeJumpGather,
         cTypeJumpGarrison,
         cTypeJumpAttack,
         cTypePointBlankAttack,
         cTypeEnergyShield,
         cTypeJumpPull,
         cTypeInfantryEnergyShield,
         cNumberTypes
      };
      enum
      {
         cPriorityDeath=9,          //Top priority
         cPriorityLeash=8,          //Must-Do
         cPriorityTrigger=7,        //Must-Do
         cPriorityCritical=6,       //Critical priority (generated by unit)
         cPriorityCommand=5,        //User Command Level
         cPriorityHigh=4,           //High priority (generated by unit)
         cPrioritySquad=3,          //Squad Generated
         cPrioritySquadSecondary=2, //Squad secondary attack
         cPriorityLow=1,            //Low priority (generated by unit)
         cPriorityNone=0            //None (Placeholder)
      };
      enum
      {
         cInvalidID=0
      };
      
      BUnitOpp() { }
      ~BUnitOpp() { }

      //IPoolable Methods
      virtual void               onAcquire() { }
      virtual void               onRelease() { }

      //ID.
      uint                       getID() const { return (mID); }
      BUnitOppID                 generateID();
      void                       setID(uint newID) { mID = newID; }

      //Source.
      BEntityID                  getSource() const { return (mSource); }
      void                       setSource(BEntityID v) { mSource=v; }

      //Target.
      BSimTarget                 getTarget() const { return (mTarget); }
      void                       setTarget(BSimTarget v) { mTarget=v; }
      
      //Path.
      const BDynamicSimVectorArray& getPath() const { return (mPath); }
      void                       setPath(const BDynamicSimVectorArray& path);
      void                       addPointToPath(BVector point) { mPath.add(point); }

      //Type.
      BUnitOppType               getType() const { return (mType); }
      void                       setType(BUnitOppType v) { mType=v; }
      const char*                getTypeName() const;

      //Priority.
      uint8                      getPriority() const { return (mPriority); }
      void                       setPriority(uint8 v) { BDEBUG_ASSERT(v <= cPriorityDeath); mPriority=v; }
      
      //User data.
      uint16                     getUserData() const  { return (mUserData); }
      void                       setUserData(uint16 v) { mUserData = v; mUserDataSet = true; }
      bool                       getUserDataSet() const  { return ( mUserDataSet ); }
      //User data2.
      uint8                      getUserData2() const  { return (mUserData2); }
      void                       setUserData2(uint8 v) { mUserData2=v; }

      //Wait Count
      ushort                     getWaitCount() const { return (mWaitCount); }
      void                       setWaitCount(ushort v) { mWaitCount=v; }

      //Flags.
      bool                       getEvaluated() const { return (mEvaluated); }
      void                       setEvaluated(bool v) { mEvaluated=v; }
      bool                       getExistForOneUpdate() const  { return (mExistForOneUpdate); }
      void                       setExistForOneUpdate(bool v) { mExistForOneUpdate=v; }
      bool                       getExistUntilEvaluated() const  { return (mExistUntilEvaluated); }
      void                       setExistUntilEvaluated(bool v) { mExistUntilEvaluated=v; }
      bool                       getAllowComplete() const  { return (mAllowComplete); }
      void                       setAllowComplete(bool v) { mAllowComplete=v; }
      bool                       getNotifySource() const  { return (mNotifySource); }
      void                       setNotifySource(bool v) { mNotifySource=v; }
      bool                       getLeash() const  { return (mLeash); }
      void                       setLeash(bool v) { mLeash=v; if (mLeash) setPriority(cPriorityLeash); else setForceLeash(false); }
      bool                       getForceLeash() const  { return (mForceLeash); }
      void                       setForceLeash(bool v) { mForceLeash=v; if (mForceLeash) setLeash(true); }
      bool                       getTrigger() const  { return (mTrigger); }
      void                       setTrigger(bool v) { mTrigger=v; if (mTrigger) setPriority(cPriorityTrigger); }
      bool                       getRemoveActions() const  { return (mRemoveActions); }
      void                       setRemoveActions(bool v) { mRemoveActions=v; }
      bool                       getComplete() const  { return (mComplete); }
      void                       setComplete(bool v) { mComplete=v; }
      bool                       getCompleteValue() const  { return (mCompleteValue); }
      void                       setCompleteValue(bool v) { mCompleteValue=v; }
      bool                       getPreserveDPS() const  { return ( mPreserveDPS ); }
      void                       setPreserveDPS(bool v) { mPreserveDPS=v; }      
      bool                       getMustComplete() const { return mMustComplete; }
      void                       setMustComplete(bool v) { mMustComplete=v; }


      //Init, etc.
      void                       init()
                                 {
                                    mPath.clear();
                                    mTarget.reset();
                                    mSource=cInvalidObjectID;
                                    mID=cInvalidID;
                                    mType=cTypeNone;
                                    mPriority=cPriorityNone;
                                    mUserData=0;
                                    mUserDataSet=false;
                                    mUserData2=0;
                                    mWaitCount=0;
                                    mEvaluated=false;
                                    mExistForOneUpdate=false;
                                    mExistUntilEvaluated=false;
                                    mAllowComplete=true;
                                    mNotifySource=true;
                                    mLeash=false;
                                    mForceLeash=false;
                                    mTrigger=false;
                                    mRemoveActions=true;
                                    mComplete=false;
                                    mCompleteValue=false;
                                    mPreserveDPS=false;
                                    mMustComplete=false;
                                 }
      BUnitOpp&                  operator=(const BUnitOpp& v)
                                 {
                                    setPath(v.mPath);
                                    mTarget=v.mTarget;
                                    mSource=v.mSource;
                                    mID=v.mID;
                                    mType=v.mType;
                                    mPriority=v.mPriority;
                                    mUserData=v.mUserData;
                                    mUserDataSet=v.mUserDataSet;
                                    mUserData2=v.mUserData2;
                                    mWaitCount=v.mWaitCount;
                                    mEvaluated=v.mEvaluated;
                                    mExistForOneUpdate=v.mExistForOneUpdate;
                                    mExistUntilEvaluated=v.mExistUntilEvaluated;
                                    mAllowComplete=v.mAllowComplete;
                                    mNotifySource=v.mNotifySource;
                                    mLeash=v.mLeash;
                                    mForceLeash=v.mForceLeash;
                                    mTrigger=v.mTrigger;
                                    mRemoveActions=v.mRemoveActions;
                                    mComplete=v.mComplete;
                                    mCompleteValue=v.mCompleteValue;
                                    mPreserveDPS=v.mPreserveDPS;
                                    mWaitCount=v.mWaitCount;
                                    mMustComplete=v.mMustComplete;
                                    return(*this);
                                 }
      //NOTE: == is used for standard equality.  That's not the same as the addEqual() method since that's
      //used differently.
      bool                       operator==(const BUnitOpp& v) const
                                 {
                                    //DO NOT check mEvaluated.
                                    if (mPath.getSize() != v.mPath.getSize())
                                       return (false);
                                    for (uint i=0; i < mPath.getSize(); i++)
                                    {
                                       if (mPath[i] != v.mPath[i])
                                          return (false);
                                    }
                                    if ((mTarget == v.mTarget) &&
                                       (mSource == v.mSource) &&
                                       (mID == v.mID) &&
                                       (mType == v.mType) &&
                                       (mPriority == v.mPriority) &&
                                       (mUserData == v.mUserData) &&
                                       (mUserDataSet == v.mUserDataSet) &&
                                       (mUserData2 == v.mUserData2) &&
                                       (mExistForOneUpdate == v.mExistForOneUpdate) &&
                                       (mExistUntilEvaluated == v.mExistUntilEvaluated) &&
                                       (mAllowComplete == v.mAllowComplete) &&
                                       (mNotifySource == v.mNotifySource) &&
                                       (mLeash == v.mLeash) &&
                                       (mForceLeash == v.mForceLeash) &&
                                       (mTrigger == v.mTrigger) &&
                                       (mRemoveActions == v.mRemoveActions) &&
                                       (mComplete == v.mComplete) &&
                                       (mCompleteValue == v.mCompleteValue) &&
                                       (mPreserveDPS == v.mPreserveDPS) &&
                                       (mMustComplete == v.mMustComplete)
                                       )
                                       return(true);
                                    return(false);
                                 }
      bool                       operator!=(const BUnitOpp& v) const
                                 {
                                    return (!(*this == v));
                                 }
      bool                       addEqual(const BUnitOpp* v) const
                                 {
                                    //DO NOT check mEvaluated.
                                    //DO NOT check mID.
                                    if (mPath.getSize() != v->mPath.getSize())
                                       return (false);
                                    for (uint i=0; i < mPath.getSize(); i++)
                                    {
                                       if (mPath[i] != v->mPath[i])
                                          return (false);
                                    }
                                    if ((mTarget == v->mTarget) &&
                                       (mSource == v->mSource) &&
                                       (mType == v->mType) &&
                                       (mPriority == v->mPriority) &&
                                       (mUserData == v->mUserData) &&
                                       (mUserData2 == v->mUserData2) &&
                                       (mExistForOneUpdate == v->mExistForOneUpdate) &&
                                       (mExistUntilEvaluated == v->mExistUntilEvaluated) &&
                                       (mAllowComplete == v->mAllowComplete) &&
                                       (mNotifySource == v->mNotifySource) &&
                                       (mLeash == v->mLeash) &&
                                       (mForceLeash == v->mForceLeash) &&
                                       (mTrigger == v->mTrigger) &&
                                       (mRemoveActions == v->mRemoveActions) &&
                                       (mComplete == v->mComplete) &&
                                       (mCompleteValue == v->mCompleteValue) &&
                                       (mPreserveDPS == v->mPreserveDPS) &&
                                       (mMustComplete == v->mMustComplete)
                                       )
                                       return(true);
                                    return(false);
                                 }

      DECLARE_FREELIST(BUnitOpp, 5);

      bool save(BStream* pStream, int saveType) const;
      bool load(BStream* pStream, int saveType);

   protected:
      BDynamicSimVectorArray     mPath;
      BSimTarget                 mTarget;
      BEntityID                  mSource;
      BUnitOppID                 mID;
      BUnitOppType               mType;
      uint16                     mUserData;
      uint8                      mPriority;     //If we actually just keep this at 8 values, we can obviously whack down the memory a bit.  I'm leaving it at 1 BYTE on purpose for now.      
      uint8                      mUserData2;
      ushort                     mWaitCount;
      
      bool                       mEvaluated:1;
      bool                       mExistForOneUpdate:1;
      bool                       mExistUntilEvaluated:1;
      bool                       mAllowComplete:1;
      bool                       mNotifySource:1;
      bool                       mLeash:1;
      bool                       mForceLeash:1;
      bool                       mTrigger:1;
      bool                       mRemoveActions:1;
      bool                       mComplete:1;
      bool                       mCompleteValue:1;
      bool                       mPreserveDPS:1;
      bool                       mMustComplete:1;
      bool                       mUserDataSet:1;
};

typedef BSmallDynamicSimArray<BUnitOpp*> BUnitOppList;

