// World.h : Declaration of the cWorld

#ifndef __WORLD_H_
#define __WORLD_H_
#include "resource.h"       // main symbols
#include "DecalFiltersCP.h"
#include "DecalNetImpl.h"
#include "WorldObject.h"
#include "..\inject\inject.h"
#include <deque>

// remark out next line to turn off logging.
//#define Logging 1

#define HookDestroyObj 101

extern const IID EVTID_AcHooks ;

// Template class used to connect ACHooks events
template<UINT nID, class cImpl >class IACHooksEventsImpl
:public IDispEventImpl<nID, cImpl, &EVTID_AcHooks, 
&LIBID_Decal, 1, 0 >
{
public:	HRESULT advise(IUnknown *pUnk){return DispEventAdvise(pUnk);}
		HRESULT unadvise(IUnknown *pUnk){return DispEventUnadvise(pUnk);}
};


// Gouru: added structure to store slot and slot type. Containers have two types of slots
//	we need to track, slots than can contain other containers, and slots that contain items
struct CSlot {
	CSlot()
		: slot(0)
		, type(0)
	{} ;
	CSlot(long slot, long type)
		: slot(slot)
		, type(type)
	{} ;
	long slot ;
	long type ;			// 0x00 = item, 0x01 = container
};

enum eDIR {
	eRight = 1,
	eLeft = -1 
};

class cWorldData  
{
public:
	cWorldData()
		: m_Slot(0,0)
	{
		m_bIdentified = false;
		m_dwGUID = 0;
		m_dwContainer = 0;
		m_dwIcon = 0;
		m_dwModel = 0;
		m_dwRealModel = 0;
		m_fScale = 1.0f;
		m_dwValue = -1;
		m_dwFlags1 = 0;
		m_dwFlags2 = 0;
		m_dwObjectFlags1 = 0;
		m_dwObjectFlags2 = 0;
		m_dwLandblock = 0;
		m_fxOffset = 0.0f;
		m_fyOffset = 0.0f;
		m_fzOffset = 0.0f;
		m_fxHeading = 0.0f;
		m_fyHeading = 0.0f;
		m_fzHeading = 0.0f;
		m_fwHeading = 0.0f;
		m_DamageBonus = 0.0f;
		m_nItemSlots = 0;
		m_nPackSlots = 0;
		m_nUsesLeft = 0;
		m_nTotalUses = 0;
		m_nStackCount = 0;
		m_nStackMax = 0;
		m_dwTradeNoteVendor = 0;
		m_dwAssociatedSpell = 0;
		m_tExpires = 0;
		m_dwWielder = 0;		// container if wielded, zero if not
		m_dwWieldingSlot = 0;
		m_dwMonarch = 0 ;
		m_dwMaterial = 0 ;
		m_dwCoverage2 = 0 ;
		m_dwCoverage3 = 0 ;
		m_dwEquipType = 0 ;

		m_fApproachDistance = 0.0f ;
		m_Burden=0;
		m_Workmanship=0.0;
		m_IconOutline=0;
		m_MissileType=0;
		m_TotalValue=0;
		m_UsageMask=0;
		m_HouseOwner=0;
		m_HookMask=0;
		m_HookType=0;
		m_bTag = false;
		m_HasIdData = false ;
		m_ArmorLevel = -1 ;
		m_MagicDef = -1 ;
		m_Spellcraft = -1 ;
		m_MaximumMana = -1 ;
		m_LoreReq = -1 ;
		m_RankReq = -1 ;
		m_SkillReq = -1 ;
		m_WieldReqType = -1 ;
		m_WieldReqId = -1 ;
		m_WieldReq = -1 ;
		m_TinkerCount = -1 ;
		m_SkillReqId = -1 ;
		m_SpecialProps = -1 ;
		m_ManaCMod = -1 ;
		m_SpellCount = 0 ;
		for (int x=0; x<10; x++) m_Spell[x] = -1 ;
		m_WeapSpeed = -1 ;
		m_EquipSkill = -1 ;
		m_DamageType = -1 ;
		m_MaxDamage = -1 ;
		m_Variance = -1.0 ;
		m_DefenseBonus = -1.0 ;
		m_AttackBonus = -1.0 ;
		m_Range = -1.0 ;
		m_SlashProt = -1.0 ;
		m_PierceProt = -1.0 ;
		m_BludProt = -1.0 ;
		m_ColdProt = -1.0 ;
		m_FireProt = -1.0 ;
		m_ElectProt = -1.0 ;
	}

	~cWorldData()
	{
	}

	bool m_bIdentified;
	long m_dwGUID;
	long m_dwContainer;
	long m_dwValue;
	long m_tExpires;
	long m_dwFlags1;
	long m_dwFlags2;
	long m_dwObjectFlags1;
	long m_dwObjectFlags2;
	long m_dwIcon;
	long m_dwModel;
	long m_dwRealModel;
	float m_fScale;
	long m_flags;
	std::string m_strName;
	std::string m_strSecondaryName ;
	eObjectType m_eType;
	long m_dwLandblock;
	long m_LandblockRow ;		// landblock row (0-255)
	long m_LandblockCol ;		// landblock col (0-255)
	float m_fxOffset;
	float m_fyOffset;
	float m_fzOffset;
	float m_fxHeading;
	float m_fyHeading;
	float m_fzHeading;
	float m_fwHeading;
	float m_fApproachDistance ;
	float m_DamageBonus ;
	BYTE m_nItemSlots;
	BYTE m_nPackSlots;
	WORD m_nUsesLeft;
	WORD m_nTotalUses;
	WORD m_nStackCount;
	WORD m_nStackMax;
	long m_dwTradeNoteVendor;
	long m_dwAssociatedSpell;
	long m_dwWielder;
	long m_dwWieldingSlot;
	long m_dwCoverage ;
	CSlot m_Slot ;
	long m_dwMonarch ;
	long m_dwMaterial ;
	long m_dwCoverage2 ;
	long m_dwCoverage3 ;
	long m_dwEquipType ;
	long m_Burden ;
	float m_Workmanship ;
	long m_IconOutline ;
	long m_MissileType ;
	long m_TotalValue ;
	long m_UsageMask ;
	long m_HouseOwner ;
	long m_HookMask ;
	long m_HookType ;
	bool m_HasIdData ;
	long m_ArmorLevel ;
	long m_MagicDef ;
	long m_Spellcraft ;
	long m_MaximumMana ;
	long m_LoreReq ;
	long m_RankReq ;
	long m_SkillReq ;
	long m_WieldReqType ;
	long m_WieldReqId ;
	long m_WieldReq ;
	long m_TinkerCount ;
	long m_SkillReqId ;
	long m_SpecialProps ;
	float m_ManaCMod ;
	long m_SpellCount ;
	long m_Spell[10] ;
	std::string m_Inscription ;
	std::string m_RaceReq ;
	long m_WeapSpeed ;
	long m_EquipSkill ;
	long m_DamageType ;
	long m_MaxDamage ;
	float m_Variance ;
	float m_DefenseBonus ;
	float m_AttackBonus ;
	float m_Range ;
	float m_SlashProt ;
	float m_PierceProt ;
	float m_BludProt ;
	float m_ColdProt ;
	float m_FireProt ;
	float m_ElectProt ;
	float m_AcidProt ;

	CComPtr< IWorldObject > m_p;
	bool m_bTag;
};

// Use stdext::hash_map for VC7+, std::map for VC6
#if _MSC_VER > 1300 // VC 7.1
class cWorldDataMap : public stdext::hash_map< DWORD, cWorldData * >
#elif _MSC_VER > 1200 // VC 7.0
class cWorldDataMap : public std::hash_map< DWORD, cWorldData * >
#else // VC6
class cWorldDataMap : public std::map< DWORD, cWorldData * >
#endif 
{
public:
	cWorldDataMap()
	{
		m_player = 0;
	};

	~cWorldDataMap()
	{
		for (iterator iData = begin(); iData != end(); iData++)
		{
			if (iData->second)
				delete iData->second;
		}
	};

	long player() { return m_player; };
	void player(long guid) { m_player = guid; };
private:
	long m_player;
};

typedef std::map< long, CSlot > cGuidAlias;

/////////////////////////////////////////////////////////////////////////////
// cWorld
class ATL_NO_VTABLE cWorld : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<cWorld, &CLSID_World>,
	public IConnectionPointContainerImpl<cWorld>,
	public IDispatchImpl<IWorld, &IID_IWorld, &LIBID_DecalFilters>,
	public IProvideClassInfo2Impl<&CLSID_World, &DIID_IWorldEvents, &LIBID_DecalFilters>,
	public IACHooksEventsImpl<HookDestroyObj, cWorld>, 
	public INetworkFilterImpl<cWorld>,
	public CProxyIWorldEvents<cWorld>
{
public:
 	cWorld();

public:
DECLARE_REGISTRY_RESOURCEID(IDR_WORLD)
DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(cWorld)
	COM_INTERFACE_ENTRY(IWorld)
	COM_INTERFACE_ENTRY(IDispatch)
	COM_INTERFACE_ENTRY(INetworkFilter2)
	COM_INTERFACE_ENTRY(IProvideClassInfo)
	COM_INTERFACE_ENTRY(IProvideClassInfo2)
	COM_INTERFACE_ENTRY(IConnectionPointContainer)
	COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()

BEGIN_CONNECTION_POINT_MAP(cWorld)
CONNECTION_POINT_ENTRY(DIID_IWorldEvents)
END_CONNECTION_POINT_MAP()

BEGIN_SINK_MAP(cWorld)
	SINK_ENTRY_EX(HookDestroyObj, EVTID_AcHooks, 1, onObjectDestroyed)
END_SINK_MAP()

public:
	cWorldData *Data(DWORD nGuid);

private:
	void MoveItems(DWORD container, CSlot Slot, eDIR direction) ;
	void MoveSlotBack(cWorldData *pData);
	bool PlayerOwns(cWorldData* pData) ;
	bool OutsideCullDistance(cWorldData* data, long row, long col) ;
	cWorldData* OuterContainer(cWorldData* obj) ;
	void DestroyObject(cWorldData* pData) ;

	void FreeData();
	void ReleaseAllPendingObjects() ;
	void SetHook() ;

	// AC message handlers
	void DoDestroyObj(CComPtr< IMessageIterator > pMembers) ;
	void DoAdjustStackSize(CComPtr<IMessageIterator> pMembers) ;
	void DoSetCoverage(CComPtr<IMessageIterator> pMembers) ;
	void DoSetContainer(CComPtr<IMessageIterator> pMembers) ;
	void DoGameEvent(CComPtr<IMessageIterator> pMembers) ;
	void DoSetObjectPosition(CComPtr<IMessageIterator> pMembers) ;
	void DoWieldItem(CComPtr<IMessageIterator> pMembers) ;
	void DoRemoveItem(CComPtr<IMessageIterator> pMembers) ;
	void DoCreateObject(CComPtr<IMessageIterator> pMembers) ;
	void DoMoveToInventory(CComPtr<IMessageIterator> pMembers) ;
	void DoLogin(CComPtr<IMessageIterator> pMembers) ;
	void DoInsertIntoInventory(CComPtr<IMessageIterator> pMembers) ;
	void DoSetPackContents(CComPtr<IMessageIterator> pMembers) ;
	void DoIdentifyObject(CComPtr<IMessageIterator> pMembers) ;
	void DoDropItem(CComPtr<IMessageIterator> pMembers) ;
	void DoWearItem(CComPtr<IMessageIterator> pMembers) ;
#ifdef Logging
	void DoLocalChat(CComPtr<IMessageIterator> pMembers) ;
#endif

	// map to store slot information for objects when storage information is received before
	//	the object is created
	// Gouru: changed named from m_packslots to avoid confusion with m_npackslots which 
	//	refers to slots that can store packs...
	cGuidAlias m_SlotStore ;

	long m_nNextTime;
	bool m_HookIsSet ;
	CComPtr< IDecal > m_pDecal ;
	CComPtr< IACHooks > m_pHooks ;

	void _stdcall onObjectDestroyed(long nId);

public:
	//void SetObjectOwner(cWorldData *pData);
	// IWorld
	STDMETHOD(get_Inventory)(/*[out, retval]*/ IWorldIterator **pVal);
	STDMETHOD(get_Landscape)(/*[out, retval]*/ IWorldIterator **pVal);
	STDMETHOD(get_All)(IWorldIterator **pVal);
	STDMETHOD(get_ByContainer)(long GUID, /*[out, retval]*/ IWorldIterator **pVal);
	STDMETHOD(get_ByOwner)(long GUID, /*[out, retval]*/ IWorldIterator **pVal);
	STDMETHOD(get_ByNameSubstring)(BSTR Substring, /*[out, retval]*/ IWorldIterator **pVal);
	STDMETHOD(get_ByType)(eObjectType Type, /*[out, retval]*/ IWorldIterator **pVal);
	STDMETHOD(get_ByName)(BSTR Name, /*[out, retval]*/ IWorldIterator **pVal);
	STDMETHOD(get_Object)(long GUID, /*[out, retval]*/ IWorldObject **pVal);
	STDMETHOD(Distance2D)(long GUID1, long GUID2, /*[out, retval]*/ float* pVal);
	STDMETHOD(get_NumObjectTypes)(/*[out, retval]*/ long *lVal);

	// INetworkFilterImpl
	HRESULT onTerminate();
	HRESULT onInitialize();

	// INetworkFilter
	STDMETHOD(DispatchServer)(IMessage2 *pMsg);

	cWorldDataMap m_objects;

	static	float	NorthSouth(long landblock, float yOffset) ;
	static	float	EastWest(long landblock, float xOffset) ;

#ifdef Logging
	static	void _DebugLog(LPCSTR, ...) ;
#else
	inline static void cWorld::_DebugLog(LPCSTR fmt, ...) {}
#endif
};

#endif //__WORLD_H_
