/******************************************************************
  
  Module:  gameobject.h
  
  Author: Sean Craig
  
  Description:  Class declarations for game object, the base object
   class in the Titan game. 

  
  Copyright 2005 Sony Online Entertainment.  All rights reserved.
  
*******************************************************************/

#ifndef GAMEOBJECT_H
#define GAMEOBJECT_H

//-------------------------------------------------------- Includes
#include "SyRefID.h"
#include "netpacket.h"
#include "script_func.h"
#include "SyEmbeddedHashList.h"

//-------------------------------------------------------- Typedefs


//---------------------------------------------- Class Declarations
class cGameObjectRegistry;
class Titan;
class cIntel;
class cStats;
class cInventory;
class cGraphic;
class cPhysics;
class cScript;
class SyHavokRigidBody;

static const int GAMEOBJECT_CLASSID  =  0xFFFF0001;

class cPosition : public SyPropObject
{
public:
  /* Property Class Support */
  static int           InitPropClass(){return 0;};   // TODO
  static SyPropObject* Creator(){ return 0; };  // TODO

  // public interface
 
  void            SetLocation(const SyVect3 &loc){mLocation = loc;};
  void            SetHPR(const SyVect3 &hpr){mHPR = hpr;};
  void            SetHeading(const float heading) {mHPR(0) = heading;};
  void            SetPitch(const float pitch) {mHPR(1) = pitch;};
  void            SetRoll(const float roll) {mHPR(2) = roll;};

  const SyVect3 & GetLocation() const {return mLocation;};
  const SyVect3 & GetHPR() const {return mHPR;};
  float           GetHeading() const {return mHPR(0);};
  float           GetPitch() const {return mHPR(1);};
  float           GetRoll() const {return mHPR(2);};


protected:

  SyVect3       mLocation;
  SyVect3       mHPR;
};



class cGameObject : public SyPropObject
{
public:

  typedef enum
  {
    OBJ_PLAYER,
    OBJ_NPC,
    OBJ_ITEM, // in the world
    OBJ_MARKER,
    OBJ_PROJECTILE,
    OBJ_PROP,
    OBJ_DUMMY,
    NUM_OBJ_TYPES
  } tObjectType;


                    cGameObject();
                   ~cGameObject();

  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();  // TODO

  // public interface

  tGameObjectID     Create(cGameObjectRegistry *owner,tGameObjectID id,tObjectType newtype); // creates and sets up subobjects
  void              SetName(const char *newname){mName.Init(newname);};
  tObjectType       GetType(){return mType;};

  void              Init(); // call Create, set up variables and subobjects, then call Init
  void              PostInit(); // has to be called after net create
  void              Exit(); // opposite of init

  void              Reload(); // after level transition
  void              Reset(); // for example, when respawning
  void              UpdateBeforePhysics(float time);  // once/frame
  void              UpdatePhysics(float time);        // once/frame
  void              UpdateAfterPhysics(float time);   // once/frame
  bool              CheckForDelete();
  void              MarkForDelete();

  void              Prerender(); // after update, before render

  void              Activate(cGameObject *activater);
  void              Open();

  cIntel     *      GetIntel() const {return mIntel;};
  cStats     *      GetStats() const {return mStats;};
  cInventory *      GetInventory() const {return mInventory;};
  cGraphic   *      GetGraphic() const {return mGraphic;};
  cPhysics   *      GetPhysics() const {return mPhysics;};
  cScript    *      GetScript() const {return mScript;};

  const SyVect3 &   GetLocation() const {return mPosition.GetLocation();};
  const SyVect3 &   GetHPR() const {return mPosition.GetHPR();};
  float             GetHeading() const {return mPosition.GetHeading();};
  float             GetPitch() const {return mPosition.GetPitch();};
  float             GetRoll() const {return mPosition.GetRoll();};
  void              Nudge();

  void              UpdateExtents();
  float             GetMinX() const {return mMinX;};
  float             GetMaxX() const {return mMaxX;};

  void              SetLocation(const SyVect3 &loc){mPosition.SetLocation(loc);mLocDirty=true;mActorDirty = true;};
  bool              SetSafeLocation(const SyVect3 &loc); // finds a safe location near this spot
  void              SetHPR(const SyVect3 &hpr){mActorDirty=true;mLocDirty=true;mPosition.SetHPR(hpr);};
  void              SetHeading(float radians)  {mActorDirty=true;mLocDirty=true;return mPosition.SetHeading(radians);};
  void              SetPitch(float radians){mActorDirty=true;mLocDirty=true;return mPosition.SetPitch(radians);};
  void              SetRoll(float radians) {mActorDirty=true;mLocDirty=true;return mPosition.SetRoll(radians);};
  

  void              SetID(tGameObjectID id){mID = id;}; // be careful don't leave a dangling reference in the registry.
  tGameObjectID     GetID() const {return mID;};
  tGameID           GetNameID() const;
  const char *      GetName() const {return mName.AsChar();};

  cGameObjectRegistry *GetRegistry() const {return mOwner;};
  Titan *           GetTitan() const;

  float             GetDistance(cGameObject* other) const;
  float             GetDistance(const SyVect3& other_loc) const;
  float             GetHeadingTowards(cGameObject* other) const;
  float             GetHeadingTowards(const SyVect3& other_loc) const;
  float             GetPitchTowards(cGameObject* other) const;
  float             GetPitchTowards(const SyVect3 &other_loc) const;
  float             GetDistanceInDirection(const SyVect3& other_loc, const SyVect3& dir, float width=1.0f, SyVect3* pHitPoint=NULL) const;

  void              FixUp(cGameObjectRegistry *owner); // fixes up internal pointers
  int               Reset( SyObjFile& File ); // resets to state in the file 
  int               GetState( SyObjFile& File ); 

  bool              IsRemote(){return mRemote;};
  bool              IsLocal(){return !IsRemote();};
  void              SetRemote(bool bRemote);
  bool              IsInScope() { return mbInScope; }

  bool              NetworkNeedToSendPacket(); // returns true if we've moved since we sent our last packet.
  void              NetworkReceiveBroadcast(const char *packet,int size); // the owning peer of this object has broadcast an update
  void              NetworkReceiveMessage(const char *packet,int size); // someone's making a request of the owner 
  
  void              SetCarriedBy(tGameObjectID id);
  tGameObjectID     GetCarriedBy() const { return mCarriedByID; }

  // property Ids for use in property editor, see SyPropObject::AddProperty() for numbering convention
  static const SyPropID PropId_ID           = 0x0000;
  static const SyPropID PropId_Type         = 0x0001;
  static const SyPropID PropId_Intel        = 0x0002;
  static const SyPropID PropId_Stats        = 0x0003;
  static const SyPropID PropId_Inventory    = 0x0004;
  static const SyPropID PropId_Graphic      = 0x0005;
  static const SyPropID PropId_Physics      = 0x0006;
  static const SyPropID PropId_Name         = 0x0007;
  static const SyPropID PropId_HPR          = 0x0008;
  static const SyPropID PropId_Location     = 0x0009;
  static const SyPropID PropId_Script       = 0x000a;
#ifdef HAVOK_ENABLED
  SyHavokRigidBody* GetRigidBody() const { return mRigidBody; }
  void              SetRigidBody(cPhysics*physics);
#endif

  bool              IsActorDirty() const {return mActorDirty;};
  void              ClearActorDirty(){mActorDirty = false;};

protected:

  void              NetworkUpdate(float time); 
  void              UpdateOwnership(); // test to see if object should be switched to a peer 
  void              UpdateScope(); // check to see if an object 

  void              EnterScope();
  void              ExitScope();

private:
  tGameObjectID     mID;  // all game objects must have a unique one of these
  SyString          mName;  // some game objects are named as well
  tObjectType       mType;       
  
  bool              mRemote; // true if this object is controlled by another peer in a network game
  bool              mbInScope; // there is a "simulation bubble" around the camera.  Objects outside of this bubble are 'out of scope' and not simulated.
  bool              mLocDirty;
  bool              mActorDirty;
  bool              mbMarkedForDelete;
  float             mPositionUpdateTime;
  float             mMaxX;
  float             mMinX;



  cNetPositionPacket mLastPacket; // last position packet sent

  cGameObjectRegistry       * mOwner;

  cPosition                   mPosition;    
  cIntel                    * mIntel;  // controller input, AI, or network event handler
  cStats                    * mStats;  // game statistics, health, etc.
  cInventory                * mInventory; // item objects contained by this object
  cGraphic                  * mGraphic; // visual representation of object
#ifdef HAVOK_ENABLED
  SyHavokRigidBody          * mRigidBody;
#endif
  cPhysics                  * mPhysics; // controls motion of object
  cScript                   * mScript;  // various event handlers

  tGameObjectID             mCarriedByID;

private:
  friend class cGameObjectRegistry;

  SyEmbeddedHashLink<cGameObject> mIDHashLink;   // link to objects in same hash bucket
  SyEmbeddedListLink<cGameObject> mIDListLink;  // link to all objects in world

  SyEmbeddedHashLink<cGameObject> mNameLink;  // link to objects in world, with same hash by name
  SyEmbeddedListLink<cGameObject> mTypeLink;  // link to other objects of the same time 
  
  SyEmbeddedListLink<cGameObject> mMinLink;  // link to other objects of the same time 
  SyEmbeddedListLink<cGameObject> mMaxLink;  // link to other objects of the same time 
  SyEmbeddedListLink<cGameObject> mOpenLink;  // link to other objects of the same time 
};

//------------------------------------------- Function Declarations

void RegPropClasses_GameObj();
//--------------------------------------------------------- Globals
//------------------------------------------------ Inline Functions

#endif
