
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Inventory_Group.h
// Author : Andy Tate
// Date   : 25-Oct-2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
	#pragma once
#endif   // ifdef ASURA_USE_PRAGMA_ONCE

#ifndef __AVP_INVENTORY_GROUP_H__
#define __AVP_INVENTORY_GROUP_H__

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Blueprint/Asura_Blueprint.h"
#include "Core/Asura_HashTree.h"


////////////////////////////////////////////////////////////////////////////////
// Forward class declarations...
////////////////////////////////////////////////////////////////////////////////

class Asura_Chunk_Stream;
class Asura_Message;
class AVP_Inventory_Item;
class AVP_Inventory_System;
class AVP_ClientEntity_Actor;
class AVP_ServerEntity_Actor;


////////////////////////////////////////////////////////////////////////////////
// Class declaration...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Inventory_Group
// Author       : Andy Tate
// Date         : 25-Oct-2006
//
// Description  : Class to handle the manipulation of a particular type of
//				  inventory items.
////////////////////////////////////////////////////////////////////////////////

class AVP_Inventory_Group
{
	friend class AVP_Inventory_Group_Enumerator;

public:
	enum GroupType
	{
		NONE,
		WEAPON,
		VISION_MODE,

		NUM_GROUPS
	};

	// Public functions...
	AVP_Inventory_Group(AVP_Inventory_System& xParentSystem, Asura_Char const* const szName, const bool bPermanentlyActive);
	virtual ~AVP_Inventory_Group();

	// Inventory group functions...
	bool	AddItem(const Asura_Hash_ID uHash, AVP_Inventory_Item* pxNewItem);
	bool	DestroyItemIfExists(const Asura_Hash_ID uHash);
	void	DestroyAllItems(void);

	// Chunk processing functions...
	virtual	void	ReadFromChunkStream(Asura_Chunk_Stream& xStream);
	virtual	void	WriteToChunkStream(Asura_Chunk_Stream& xStream) const;

	virtual void PostLoadInitialise();

	// Virtual manipulation functions...
	virtual	bool	ChangeToLastUsedItem(void)					{ return(SetCurrentItem(m_uLastUsedItemHash)); }
	virtual	bool	ChangeToNextItem(const bool bAllowWrap)		{ return(SetCurrentItem(GetNextItem(m_uCurrentItemHash, bAllowWrap))); }
	virtual	bool	ChangeToPreviousItem(const bool bAllowWrap)	{ return(SetCurrentItem(GetPreviousItem(m_uCurrentItemHash, bAllowWrap))); }

	virtual void	Activate(void);
	virtual void	Deactivate(void);

	virtual bool	HandleMessage(const Asura_Message* pxMessage);
	virtual	void	Update(void);
	virtual	void	Render(void) const;

	// Query functions...
	Asura_Hash_ID	FindLowestPriorityItem(void) const;
	Asura_Hash_ID	FindHighestPriorityItem(void) const;

	Asura_Hash_ID	FindNextLowestPriorityItem(const Asura_Hash_ID uHash) const;
	Asura_Hash_ID	FindNextHighestPriorityItem(const Asura_Hash_ID uHash) const;

	Asura_Hash_ID	FindNextLowestPriorityItem(void) const	{ return(FindNextLowestPriorityItem(m_uCurrentItemHash)); }
	Asura_Hash_ID	FindNextHighestPriorityItem(void) const	{ return(FindNextHighestPriorityItem(m_uCurrentItemHash)); }

	// Accessor functions...
	bool	IsPermanentlyActive(void) const	{ return(GetCurrentState() == PERMANENTLY_ACTIVE); }

	void	SetAllowSelectionOfEmptyItems(const bool bSet)	{ m_bAllowSelectionOfEmptyItems = bSet; }

	void	SetIgnoredByChunkStream(const bool bSet)	{ m_bIgnoredByChunkStream = bSet; }
	bool	IsIgnoredByChunkStream(void) const			{ return m_bIgnoredByChunkStream; }

	AVP_Inventory_System&		GetParentSystem(void)		{ return(m_xParentSystem); }
	const AVP_Inventory_System&	GetParentSystem(void) const	{ return(m_xParentSystem); }

	const Asura_Char*	GetName(void) const					{ return(m_szName); }
	Asura_Hash_ID		GetHashInParentSystem(void) const	{ return(m_uHashInParentSystem); }
	
	GroupType			GetGroupType(void) const			{ return(static_cast<GroupType>(m_eGroupType)); }
	void				SetGroupType(GroupType eType)		{ m_eGroupType = eType; }

	void	SetTweenDuration(const float fDuration)	{ m_fTweenDuration = fDuration; }
	float	GetTweenDuration(void) const			{ return(m_fTweenDuration); }

	Asura_Hash_ID	GetCurrentItem(void) const	{ return(m_uCurrentItemHash); }
	bool			SetCurrentItem(const Asura_Hash_ID uHash, const bool bInstant = false);

	Asura_Hash_ID	GetDefaultItem(void) const									{ return(m_uDefaultItemHash); }
	void			SetDefaultItem(const Asura_Hash_ID uHash)					{ m_uDefaultItemHash = uHash; }
	void			SetCurrentItemToDefaultItem(const bool bInstant = false)	{ SetCurrentItem(m_uDefaultItemHash, bInstant); }
	

	bool SwapCurrentItemForPickup(const u_int uPickupHash, const float fQuantity = 0.0f, const float fSecondaryQuantity = 0.0f);
	bool AddPickup               (const u_int uPickupHash, const float fQuantity = 0.0f, const float fSecondaryQuantity = 0.0f);

	AVP_Inventory_Item*			GetCurrentInventoryItem(void)		{ return(GetItem(m_uCurrentItemHash)); }
	const AVP_Inventory_Item*	GetCurrentInventoryItem(void) const	{ return(GetItem(m_uCurrentItemHash)); }

	AVP_Inventory_Item*			GetItem(const Asura_Hash_ID uHash)			{ AVP_Inventory_Item** ppxItem = m_xItemTree.GetDataByHash(uHash); return((ppxItem == NULL) ? NULL : *ppxItem); }
	const AVP_Inventory_Item*	GetItem(const Asura_Hash_ID uHash) const	{ AVP_Inventory_Item* const* ppxItem = m_xItemTree.GetDataByHash(uHash); return((ppxItem == NULL) ? NULL : *ppxItem); }

	u_int			GetNumItems(void) const	{ return(m_xItemTree.GetNumberOfNodes()); }
	u_int			GetNumSelectableItems(void) const;
	u_int			GetNumInactiveItems(void) const;
	Asura_Hash_ID	GetNextItem(const Asura_Hash_ID uCurrentHash, const bool bAllowWrap, const bool bAllowUnselectable = false ) const;
	Asura_Hash_ID	GetPreviousItem(const Asura_Hash_ID uCurrentHash, const bool bAllowWrap) const;
	Asura_Hash_ID	GetNextItem(const bool bAllowWrap) const		{ return(GetNextItem(m_uCurrentItemHash, bAllowWrap)); }
	Asura_Hash_ID	GetPreviousItem(const bool bAllowWrap) const	{ return(GetPreviousItem(m_uCurrentItemHash, bAllowWrap)); }

	bool	IsAnyItemActive(void) const		{ return(GetCurrentState() != NO_ITEM_ACTIVE); }
	bool	IsCurrentItemActive(void) const	{ return(GetCurrentState() == ITEM_ACTIVE); }

	bool	IsItemSelectable(const Asura_Hash_ID uHash) const;
	bool	HasDualSlotWeapon(void) const;

	AVP_Inventory_Item*	FindItemByBlueprintHash(Asura_Hash_ID uBlueprintHash) const;

	Asura_Hash_ID	GetPreviousItemBlueprintHash() const { return m_uPreviousItemBlueprintHash; }
	float			GetPreviousItemQuantity() const { return m_fPreviousItemQuantity; }
	float			GetPreviousItemSecondaryQuantity() const { return m_fPreviousItemSecondaryQuantity; }

protected:
	// Protected enumerated types...
	enum State
	{
		NO_ITEM_ACTIVE,
		DEACTIVATING_CURRENT_ITEM,
		SWAP_PENDING_ITEM_TO_CURRENT_ITEM,
		SWAP_PICKUP_ITEM_WITH_CURRENT_ITEM,
		ACTIVATING_CURRENT_ITEM,
		ITEM_ACTIVE,

		PERMANENTLY_ACTIVE,

		MAX_STATES
	};

	// Protected variables...
	AVP_Inventory_System&						m_xParentSystem;		// A reference to the parent inventory system.
	const Asura_Char*							m_szName;				// A pointer to the name of this group.
	Asura_Hash_ID								m_uHashInParentSystem;	// The hash-ID that can be used to access this group from the parent-system;

	float										m_fTweenDuration;		// The number of seconds taken to tween between items.
	Asura_Hash_ID								m_uLastUsedItemHash;	// The hash-ID of the last item used.
	Asura_Hash_ID								m_uCurrentItemHash;		// The hash-ID of the item currently in use.
	Asura_Hash_ID								m_uPendingItemHash;		// The hash-ID of the item we're about to change to.
	Asura_Hash_ID								m_uPickupItemBlueprintHash;		// The hash-ID of the item we're about to pick up.
	Asura_Hash_ID								m_uPreviousItemBlueprintHash; // Previous item pickup hash, in case of using battery we use it to recreate the previous item
	float										m_fPreviousItemQuantity;
	float										m_fPreviousItemSecondaryQuantity;
	Asura_Hash_ID								m_uDefaultItemHash;		// The hash-ID of the default item (if we have one).
	float										m_fQuantity;			// Temp info about pickup about to be added to group
	float										m_fSecondaryQuantity;	// Temp info about pickup about to be added to group
	Asura_TemplateHashTree<AVP_Inventory_Item*>	m_xItemTree;			// A tree containing the items we can use.

	// Protected functions...
	bool	RequestStateChange(const State eNewState);

	// State update functions...
	virtual void	OnStateChange(const u_int uOldState, const u_int uNewState);

	virtual AVP_Inventory_Item*	CreateItemFromBlueprint(const Asura_Hash_ID uBlueprintHash, const Asura_Hash_ID uNameHash);
	virtual AVP_Inventory_Item*	CreateItemFromType( const int iType, const Asura_Hash_ID uBlueprintHash, const Asura_Hash_ID uNameHash );

	// Static traversal functions...
	static bool	IsPriorityGreaterThan(const u_int uPriority1, const Asura_Hash_ID uHash1, const u_int uPriority2, const Asura_Hash_ID uHash2);
	static bool	IsPriorityLessThan(const u_int uPriority1, const Asura_Hash_ID uHash1, const u_int uPriority2, const Asura_Hash_ID uHash2);

	// Accessor functions...
	State	GetCurrentState(void) const	{ return(static_cast<State>(m_eCurrentState)); }

	virtual bool GetCanSetNewItem(const bool bInstant) const { return true; }

private:

	void ResetPickupItemData(void);

	// Private variables...
	union
	{
		u_int		m_uFlags;								// Single access-point for the flags.

		struct
		{
			u_int	m_ePreviousState				: 4,	// The previous state of this group.
					m_eCurrentState					: 4,	// The current state of this group.
					m_eNewState						: 4,	// The state to change to.
					m_eGroupType					: 4,	// Weapon / Vision-Mode etc
					m_bHasNewState					: 1,	// Flag to say that we need to change state.

					m_bAllowSelectionOfEmptyItems	: 1,	// Flag to allow selection of items which are empty.
					m_bIgnoredByChunkStream			: 1,	// Ignored in read/write to chunk stream is set
													: 0;	// 9 spare-bits
		};
	};

	float			m_fTimeInState;							// The number of seconds spent in this state.

	AVP_Inventory_Group(const AVP_Inventory_Group& xOther);
	AVP_Inventory_Group& operator=(const AVP_Inventory_Group& xOther);

	static const u_int uCURRENT_CHUNK_VERSION = 4;
};

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Inventory_Group_Enumerator
// Author       : Andy Tate
// Date         : 22-Jan-2008
//
// Description  : Class to handle enumeration of the specified inventory-group.
////////////////////////////////////////////////////////////////////////////////

class AVP_Inventory_Group_Enumerator : public Asura_Blueprint_ParameterEnumerator
{
public:
	// Public functions...
	AVP_Inventory_Group_Enumerator(AVP_Inventory_Group& xGroup, const bool bSetFirstItemAsDefault = true, u_int uMaxItems = 0xFFFFFFFF )	: m_xGroup(xGroup), m_bSetFirstItemAsDefault(bSetFirstItemAsDefault), m_pxFirstItem(NULL), m_uMaxItems(uMaxItems)	{}
//	virtual ~AVP_Inventory_Group_Enumerator();

	// Overridden enumeration function...
	virtual void	BeginEnumeration(void);
	virtual bool	Enumerate(const u_int uIndex, char const* const szName, const Asura_Value& xValue);
	virtual void	EndEnumeration(const bool bSuccess);


protected:
	// Protected variables...
	AVP_Inventory_Group&	m_xGroup;					// A reference to the group we're enumerating on.
	bool					m_bSetFirstItemAsDefault;	// A flag to say whether we need to set the first item to be the default one for this group following successful enumeration.
	AVP_Inventory_Item*		m_pxFirstItem;				// A pointer to the first-item enumerated.
	u_int					m_uMaxItems;				// maximum number of items to add to the group

	// Protected functions...


private:
	// Private variables...

	// Private functions...
	AVP_Inventory_Group_Enumerator(void);
	AVP_Inventory_Group_Enumerator(const AVP_Inventory_Group_Enumerator& xOther);

	AVP_Inventory_Group_Enumerator&	operator=(const AVP_Inventory_Group_Enumerator& xOther);

};   // End of class 'AVP_Inventory_Group_Enumerator'.


#endif   // ifndef __AVP_INVENTORY_GROUP_H__


/// End of file. ///
