//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//


#include "cbase.h"
#include "backpack_panel.h"
#include "item_confirm_delete_dialog.h"
#include "vgui/ISurface.h"
#include "gamestringpool.h"
#include "iclientmode.h"
#include "econ_item_inventory.h"
#include "ienginevgui.h"
#include <vgui/ILocalize.h>
#include "vgui_controls/TextImage.h"
#include "vgui_controls/CheckButton.h"
#include "vgui_controls/ComboBox.h"
#include "vgui_controls/ScalableImagePanel.h"
#include "vgui/IInput.h"
#include "econ/tool_items/tool_items.h"
#include "econ_gcmessages.h"
#include "item_style_select_dialog.h"
#include "econ_item_system.h"
#include "econ_item_tools.h"
#include "econ_ui.h"
#include "gc_clientsystem.h"
#include "econ_store.h"
#include "rtime.h"
#include "econ_item_description.h"
#include "dynamic_recipe_subpanel.h"
#include "item_slot_panel.h"
#include "crate_detail_panels.h"
#include "tf_warinfopanel.h"
#include "character_info_panel.h"
#include "trading_start_dialog.h"
#include "vgui_controls/MenuItem.h"
#include "tf_duckleaderboard.h"
#include "tf_item_inventory.h"
#include "store/store_panel.h"
#include "strange_count_transfer_panel.h"
#include "collection_crafting_panel.h"
#include "halloween_offering_panel.h"
#include "store/v2/tf_store_preview_item2.h"
#include "item_ad_panel.h"
#include "client_community_market.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>


#ifdef STAGING_ONLY
extern ConVar tf_use_card_tooltips;
extern ConVar tf_weapon_force_allow_inspect;
#endif // STAGING_ONLY

ConVar tf_trade_up_use_count( "tf_trade_up_use_count", "3", FCVAR_ARCHIVE | FCVAR_HIDDEN );


void UseConsumableItem( CEconItemView *pItem, vgui::Panel* pParent );

const ItemSortTypeData_t g_BackpackSortTypes[] =
{
	{ "#Backpack_SortBy_Header",		kGCItemSort_NoSort },
	{ "#Backpack_SortBy_Rarity",		kGCItemSort_SortByRarity },
	{ "#Backpack_SortBy_Type",			kGCItemSort_SortByType },
	{ "#Backpack_SortBy_Class",			kTFGCItemSort_SortByClass },
	{ "#Backpack_SortBy_Slot",			kTFGCItemSort_SortBySlot },
	{ "#Backpack_SortBy_Date",			kGCItemSort_SortByDate },
};

// Array of borders for rarities. Three borders for each rarity: Base, Mouseover, and Selected
const char *g_szItemBorders[][5] =
{
	{ "BackpackItemBorder",				"BackpackItemMouseOverBorder",				"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder",				"BackpackItemGreyedOutSelectedBorder"				},		// AE_NORMAL = 0
	{ "BackpackItemBorder_1",			"BackpackItemMouseOverBorder_1",			"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_1",			"BackpackItemGreyedOutSelectedBorder_1"				},		// AE_RARITY1 = 1
	{ "BackpackItemBorder_2",			"BackpackItemMouseOverBorder_2",			"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_2",			"BackpackItemGreyedOutSelectedBorder_2"				},		// AE_RARITY2 = 2
	{ "BackpackItemBorder_Vintage",		"BackpackItemMouseOverBorder_Vintage",		"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_Vintage",		"BackpackItemGreyedOutSelectedBorder_Vintage"		},		// AE_VINTAGE = 3
	{ "BackpackItemBorder_3",			"BackpackItemMouseOverBorder_3",			"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_3",			"BackpackItemGreyedOutSelectedBorder_3"				},		// AE_RARITY3
	{ "BackpackItemBorder_4",			"BackpackItemMouseOverBorder_4",			"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_4",			"BackpackItemGreyedOutSelectedBorder_4"				},		// AE_RARITY4
	{ "BackpackItemBorder_Unique",		"BackpackItemMouseOverBorder_Unique",		"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_Unique",		"BackpackItemGreyedOutSelectedBorder_Unique"		},		// AE_UNIQUE
	{ "BackpackItemBorder_Community",	"BackpackItemMouseOverBorder_Community",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_Community",	"BackpackItemGreyedOutSelectedBorder_Community"		},		// AE_COMMUNITY
	{ "BackpackItemBorder_Developer",	"BackpackItemMouseOverBorder_Developer",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_Developer",	"BackpackItemGreyedOutSelectedBorder_Developer"		},		// AE_DEVELOPER
	{ "BackpackItemBorder_SelfMade",	"BackpackItemMouseOverBorder_SelfMade",		"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_SelfMade",		"BackpackItemGreyedOutSelectedBorder_SelfMade"		},		// AE_SELFMADE
	{ "BackpackItemBorder_Customized",	"BackpackItemMouseOverBorder_Customized",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_Customized",	"BackpackItemGreyedOutSelectedBorder_Customized"	},		// AE_CUSTOMIZED
	{ "BackpackItemBorder_Strange",		"BackpackItemMouseOverBorder_Strange",		"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_Strange",		"BackpackItemGreyedOutSelectedBorder_Strange"		},		// AE_STRANGE
	{ "BackpackItemBorder_Completed",	"BackpackItemMouseOverBorder_Completed",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_Completed",	"BackpackItemGreyedOutSelectedBorder_Completed"		},		// AE_COMPLETED
	{ "BackpackItemBorder_Haunted",		"BackpackItemMouseOverBorder_Haunted",		"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_Haunted",		"BackpackItemGreyedOutSelectedBorder_Haunted"		},		// AE_HAUNTED
	{ "BackpackItemBorder_Collectors",	"BackpackItemMouseOverBorder_Collectors",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_Collectors",	"BackpackItemGreyedOutSelectedBorder_Collectors"	},		// AE_COLLECTORS

	{ "BackpackItemBorder_PaintkitWeapon",	"BackpackItemMouseOverBorder_PaintkitWeapon",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_PaintkitWeapon",	"BackpackItemGreyedOutSelectedBorder_PaintkitWeapon"	},	// AE_Paintkit
	{ "BackpackItemBorder_RarityDefault",	"BackpackItemMouseOverBorder_RarityDefault",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_RarityDefault",	"BackpackItemGreyedOutSelectedBorder_RarityDefault"		}, // AE_RARITY_DEFAULT,
	{ "BackpackItemBorder_RarityCommon",	"BackpackItemMouseOverBorder_RarityCommon",		"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_RarityCommon",		"BackpackItemGreyedOutSelectedBorder_RarityCommon"		}, // AE_RARITY_COMMON,
	{ "BackpackItemBorder_RarityUncommon",	"BackpackItemMouseOverBorder_RarityUncommon",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_RarityUncommon",	"BackpackItemGreyedOutSelectedBorder_RarityUncommon"	}, // AE_RARITY_UNCOMMON,
	{ "BackpackItemBorder_RarityRare",		"BackpackItemMouseOverBorder_RarityRare",		"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_RarityRare",		"BackpackItemGreyedOutSelectedBorder_RarityRare"		}, // AE_RARITY_RARE,
	{ "BackpackItemBorder_RarityMythical",	"BackpackItemMouseOverBorder_RarityMythical",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_RarityMythical",	"BackpackItemGreyedOutSelectedBorder_RarityMythical"	}, // AE_RARITY_MYTHICAL,
	{ "BackpackItemBorder_RarityLegendary",	"BackpackItemMouseOverBorder_RarityLegendary",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_RarityLegendary",	"BackpackItemGreyedOutSelectedBorder_RarityLegendary"	}, // AE_RARITY_LEGENDARY,
	{ "BackpackItemBorder_RarityAncient",	"BackpackItemMouseOverBorder_RarityAncient",	"BackpackItemSelectedBorder",	"BackpackItemGreyedOutBorder_RarityAncient",	"BackpackItemGreyedOutSelectedBorder_RarityAncient"		}, // AE_RARITY_ANCIENT,
};	

COMPILE_TIME_ASSERT( ARRAYSIZE(g_szItemBorders) == AE_MAX_TYPES );

enum { kNoUserData = -1 };

static bool HasPaint ( const CEconItemView *pEconItemView, const char *, int )
{
	static CSchemaAttributeDefHandle pAttrDef_PaintRGB( "set item tint RGB" );
	static CSchemaAttributeDefHandle pAttrDef_PaintRGB2( "set item tint RGB 2" );

	return pEconItemView->FindAttribute( pAttrDef_PaintRGB )
		|| pEconItemView->FindAttribute( pAttrDef_PaintRGB2 );
}

static bool HasCustomAttribute ( const CEconItemView *pEconItemView, const char *szAttrName, int )
{
	const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinitionByName( szAttrName );

	return pAttrDef
		 ? pEconItemView->FindAttribute( pAttrDef )
		 : NULL;
}

static bool HasCustomUserAttribute ( const CEconItemView *pEconItemView, const char *, int iUserData )
{
	Assert( iUserData != kNoUserData );

	CCountUserGeneratedAttributeIterator countIterator;
	pEconItemView->IterateAttributes( &countIterator );

	return countIterator.GetCount() > iUserData;
}	

static bool HasRemovableCustomName ( const CEconItemView *pEconItemView, const char *, int )
{
	if ( !pEconItemView->GetItemDefinition() )
		return false;

	if ( pEconItemView->GetQuality() == AE_UNIQUE && pEconItemView->GetItemDefinition()->GetArmoryDescString() && !V_stricmp( pEconItemView->GetItemDefinition()->GetArmoryDescString(), "stockitem" ) )
		return false;

	return pEconItemView->GetSOCData() && pEconItemView->GetSOCData()->GetCustomName();
}

static bool HasRemovableCustomDesc ( const CEconItemView *pEconItemView, const char *, int )
{
	if ( !pEconItemView->GetItemDefinition() )
		return false;

	if ( pEconItemView->GetQuality() == AE_UNIQUE && pEconItemView->GetItemDefinition()->GetArmoryDescString() && !V_stricmp( pEconItemView->GetItemDefinition()->GetArmoryDescString(), "stockitem" ) )
		return false;

	return pEconItemView->GetSOCData() && pEconItemView->GetSOCData()->GetCustomDesc();
}

enum EItemCustomizationRemoveType
{
	kCustomizationRemove_Paint,
	kCustomizationRemove_Name,
	kCustomizationRemove_Desc,
	kCustomizationRemove_CustomTexture,
	kCustomizationRemove_MakersMark,
	kCustomizationRemove_UniqueCraftIndex,
	kCustomizationRemove_StrangePart,
	kCustomizationRemove_StrangeScores,
	kCustomizationRemove_UpgradeCard,
	kCustomizationRemove_KillStreak,
	kCustomizationRemove_GiftedBy,
	kCustomizationRemove_Festivizer,
};

typedef bool (* HasRefurbishablePropertyFunc_t)( const CEconItemView *pEconItemView, const char *pArg, int iUserData );

void GetCustomDialogToken_PaintName( const CEconItemView *pEconItemView, int iUserData, CUtlConstWideString& out_String )
{
	extern const CEconItemDefinition *GetPaintItemDefinitionForPaintedItem( const IEconItemInterface *pEconItem );

	Assert( iUserData == kNoUserData );

	const CEconItemDefinition *pPaintItemDef = GetPaintItemDefinitionForPaintedItem( pEconItemView );
	if ( !pPaintItemDef )
	{
		out_String = L"";
		return;
	}

	out_String = GLocalizationProvider()->Find( pPaintItemDef->GetItemBaseName() );
}

void GetCustomDialogToken_StrangePartName( const CEconItemView *pEconItemView, int iUserData, CUtlConstWideString& out_String )
{
	extern uint32 GetScoreTypeForKillEaterAttr( const IEconItemInterface *pEconItem, const CEconItemAttributeDefinition *pAttribDef );
	extern const wchar_t *GetLocalizedStringForKillEaterTypeAttr( const CLocalizationProvider *pLocalizationProvider, uint32 unKillEaterEventType );		// return type changed from locchar_t * because the backpack panel only exists on the client

	uint32 unKillEaterBaseType = GetScoreTypeForKillEaterAttr( pEconItemView, GetKillEaterAttr_Type( iUserData ) );
	
	out_String = GetLocalizedStringForKillEaterTypeAttr( GLocalizationProvider(), unKillEaterBaseType );
}

void GetCustomDialogToken_UserAttributeName( const CEconItemView *pEconItemView, int iUserData, CUtlConstWideString& out_String )
{
	Assert( pEconItemView );

	const CEconItemAttributeDefinition *pAttrDef = GetCardUpgradeForIndex( pEconItemView, iUserData );
	if ( !pAttrDef )
	{
		out_String = L"unknown";
		return;
	}

	attrib_value_t attrVal;
	Verify( pEconItemView->FindAttribute( pAttrDef, &attrVal ) );
	CEconAttributeDescription attrDesc( GLocalizationProvider(), pAttrDef, attrVal );
	out_String = attrDesc.GetShortDescription();
}

typedef void (* GetCustomDialogLocalizationTokenFunc_t)( const CEconItemView *pEconItemView, int iUserData, CUtlConstWideString& out_String );

struct RefurbishableProperty
{
	HasRefurbishablePropertyFunc_t m_pFunc;
	GetCustomDialogLocalizationTokenFunc_t m_pGetCustomDialogLocalizationTokenFunc;
	const char *m_szArg;
	const char *m_pszSelectionUILocalizationToken;
	const char *m_szDialogTitle;
	const char *m_szDialogDesc;
	EItemCustomizationRemoveType m_eRemovalType;
	int m_iUserData;
};

// TODO: Add Gifted by Tag here
static RefurbishableProperty g_RemoveableAttributes[] =
{
	{ &HasRemovableCustomName,	NULL,								NULL,					"#RefurbishItem_RemoveNameCombo",			"#RefurbishItem_RemoveNameTitle",			"#RefurbishItem_RemoveName",			kCustomizationRemove_Name,				kNoUserData },	// does this item have a custom name?
	{ &HasRemovableCustomDesc,	NULL,								NULL,					"#RefurbishItem_RemoveDescCombo",			"#RefurbishItem_RemoveDescTitle",			"#RefurbishItem_RemoveDesc",			kCustomizationRemove_Desc,				kNoUserData },	// does this item have a custom description?
	{ &HasPaint,				&GetCustomDialogToken_PaintName,	"set item tint rgb",	"#RefurbishItem_RemovePaintCombo",			"#RefurbishItem_RemovePaintTitle",			"#RefurbishItem_RemovePaint",			kCustomizationRemove_Paint,				kNoUserData },	// is this item painted?
	{ &HasCustomAttribute,		NULL,								"custom texture hi",	"#RefurbishItem_RemoveCustomTextureCombo",	"#RefurbishItem_RemoveCustomTextureTitle",	"#RefurbishItem_RemoveCustomTexture",	kCustomizationRemove_CustomTexture,		kNoUserData },	// does this have a custom texture applied?
	{ &HasCustomAttribute,		NULL,								"makers mark id",		"#RefurbishItem_RemoveMakersMarkCombo",		"#RefurbishItem_RemoveMakersMarkTitle",		"#RefurbishItem_RemoveMakersMark",		kCustomizationRemove_MakersMark,		kNoUserData },	// was this item crafted by a specific dude?
	{ &HasCustomAttribute,		NULL,								"killstreak tier",		"#RefurbishItem_RemoveKillStreakCombo",		"#RefurbishItem_RemoveKillStreakTitle",		"#RefurbishItem_RemoveKillStreak",		kCustomizationRemove_KillStreak,		kNoUserData },	// Killstreak Effect
	{ &HasCustomAttribute,		NULL,								"gifter account id",	"#RefurbishItem_RemoveGifterCombo",			"#RefurbishItem_RemoveGifterTitle",			"#RefurbishItem_RemoveGifter",			kCustomizationRemove_GiftedBy,			kNoUserData },	// Gifted by
	{ &HasCustomAttribute,		NULL,								"is_festivized",		"#RefurbishItem_RemoveFestivizerCombo",		"#RefurbishItem_RemoveFestivizerTitle",		"#RefurbishItem_RemoveFestivizer",		kCustomizationRemove_Festivizer,		kNoUserData },	// Festivizer

	//"gifter account id",		// who gifted us this item? (will also remove "event date")
};

//-----------------------------------------------------------------------------
// Purpose: Look over this weapon to see if it has any strange stat counters to reset optionally.
//-----------------------------------------------------------------------------
static bool HasResettableScoreAttributes ( const CEconItemView *pEconItemView, const char *, int )
{
	if ( !pEconItemView )
		return false;

	for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
	{
		uint32 unScore;
		if ( pEconItemView->FindAttribute( GetKillEaterAttr_Score( i ), &unScore ) && unScore > 0 )
			return true;
	}

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int GetRemovableAttributesCount()
{
	return ARRAYSIZE( g_RemoveableAttributes )
		 + GetKillEaterAttrCount()
		 + GetMaxCardUpgradesPerItem()						// remove card upgrades
		 + 1;												// strange quality item score reset
}

RefurbishableProperty RemovableAttributes_GetAttributeDetails( int i )
{
	Assert( i >= 0 );
	Assert( i < GetRemovableAttributesCount() );

	if ( i < ARRAYSIZE( g_RemoveableAttributes ) )
		return g_RemoveableAttributes[i];
	
	// Which attribute in particular are we looking for?
	int iStrangePartIndex = i - ARRAYSIZE( g_RemoveableAttributes );
	if ( iStrangePartIndex < GetKillEaterAttrCount() )
	{
		int iKillEaterAttrIndex = (GetKillEaterAttrCount() - GetKillEaterAttrCount()) + iStrangePartIndex;

		// if we're looking at strange attributes...
		if ( GetKillEaterAttr_IsUserCustomizable( iKillEaterAttrIndex ) )
		{
			// Common properties for all strange part attributes.
			static RefurbishableProperty sStrangePartProperty = { &HasCustomAttribute, &GetCustomDialogToken_StrangePartName, NULL, "#RefurbishItem_RemoveStrangePartCombo", "#RefurbishItem_RemoveStrangePartTitle", "#RefurbishItem_RemoveStrangePart", kCustomizationRemove_StrangePart, kNoUserData };

			RefurbishableProperty partReturnProp = sStrangePartProperty;
			partReturnProp.m_szArg = GetKillEaterAttr_Score( iKillEaterAttrIndex )->GetDefinitionName();				// ...then we check for the presence of a score attribute if this slot is a strange part...
			partReturnProp.m_iUserData = iKillEaterAttrIndex;

			return partReturnProp;
		}
		
		// ...or the presence of a restriction attribute if this slot is a base slot that might have a filter
		static RefurbishableProperty sStrangeFilterProperty = { &HasCustomAttribute, &GetCustomDialogToken_StrangePartName, NULL, "#RefurbishItem_RemoveStrangeFilterCombo", "#RefurbishItem_RemoveStrangeFilterTitle", "#RefurbishItem_RemoveStrangeFilter", kCustomizationRemove_StrangePart, kNoUserData };

		RefurbishableProperty filterReturnProp = sStrangeFilterProperty;
		filterReturnProp.m_szArg = GetKillEaterAttr_Restriction( iKillEaterAttrIndex )->GetDefinitionName();
		filterReturnProp.m_iUserData = iKillEaterAttrIndex;

		return filterReturnProp;
	}

	// Look for any properties that were user-assigned. We allow users to remove them.
	int iCardUpgradeIndex = iStrangePartIndex - GetKillEaterAttrCount();
	if ( iCardUpgradeIndex < GetMaxCardUpgradesPerItem() )
	{
		// Common properties for all card upgrade attributes.
		static RefurbishableProperty sCardUpgradeProperty = { &HasCustomUserAttribute, &GetCustomDialogToken_UserAttributeName, NULL, "#RefurbishItem_RemoveSpellCombo", "#RefurbishItem_RemoveSpellTitle", "#RefurbishItem_RemoveSpellUpgrade", kCustomizationRemove_UpgradeCard, kNoUserData };

		RefurbishableProperty returnProp = sCardUpgradeProperty;
		// FIX THIS FOR CARDS / SPELLS?
		// returnProp.m_szArg = GetCustomDialogToken_UserAttributeName ?
		returnProp.m_iUserData = iCardUpgradeIndex;

		return returnProp;
	}

	// We might also be trying to reset the strange score counters.
	Assert( iStrangePartIndex == GetKillEaterAttrCount() + GetMaxCardUpgradesPerItem() );
	Assert( i == GetRemovableAttributesCount() - 1 );

	static RefurbishableProperty sStrangeScoreReset = { &HasResettableScoreAttributes, NULL, NULL, "#RefurbishItem_RemoveStrangeScoresCombo", "#RefurbishItem_RemoveStrangeScoresTitle", "#RefurbishItem_RemoveStrangeScores", kCustomizationRemove_StrangeScores, kNoUserData };
	return sStrangeScoreReset;
}

bool RemovableAttributes_DoesAttributeApply( int i, const CEconItemView *pEconItemView )
{
	static CSchemaAttributeDefHandle pAttr_CannotRestore( "cannot restore" );
	if ( pEconItemView->FindAttribute( pAttr_CannotRestore ) )
		return false;

	RefurbishableProperty attr = RemovableAttributes_GetAttributeDetails( i );

	return attr.m_pFunc( pEconItemView, attr.m_szArg, attr.m_iUserData );
}

bool RemovableAttributes_DoAnyAttributesApply( const CEconItemView *pEconItemView )
{
	static CSchemaAttributeDefHandle pAttr_CannotRestore( "cannot restore" );
	if ( pEconItemView->FindAttribute( pAttr_CannotRestore ) )
		return false;

	for ( int i = 0; i < GetRemovableAttributesCount(); i++ )
	{
		if ( RemovableAttributes_DoesAttributeApply( i, pEconItemView ) )
			return true;
	}

	return false;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
ConVar cl_showbackpackrarities( "cl_showbackpackrarities", "0", FCVAR_ARCHIVE, "0 = Show no backpack icon border colors. 1 = Show item rarities within the backpack. 2 = Show item rarities only for Market-listable items." );
ConVar cl_show_market_data_on_items( "cl_show_market_data_on_items", "1", FCVAR_ARCHIVE, "0 = Never. 1 = Only when showing borders for Market-listable items. 2 = Always." );

ConVar tf_explanations_backpackpanel( "tf_explanations_backpackpanel", "0", FCVAR_ARCHIVE, "Whether the user has seen explanations for this panel." );

ConVar tf_backpack_page_button_delay( "tf_backpack_page_button_delay", "0.5", FCVAR_ARCHIVE, "Amount of time the mouse cursor needs to hover over the page button to select the page." );

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBackpackPanel::CBackpackPanel( vgui::Panel *parent, const char *panelName ) : CBaseLoadoutPanel( parent, panelName )
{
	m_nQuickOpenTxn = 0;
	m_pContextMenu = NULL;
	m_pPageButtonKVs = NULL;
	m_mapSeenItems.SetLessFunc( DefLessFunc( itemid_t ) );
	m_bInitializedSeenItems = false;
	m_pNameFilterTextEntry = NULL;
	m_flFilterItemTime = 0.f;
	m_mapFilteringItems.SetLessFunc( DefLessFunc(int) );

	m_pNextPageButton = NULL;
	m_pPrevPageButton = NULL;
	m_pShowExplanationsButton = NULL;
	m_pCurPageLabel = NULL;
	m_pSortByComboBox = NULL;
	m_pShowRarityComboBox = NULL;
	m_pShowBaseItemsCheckbox = NULL;
	m_pDragToNextPageButton = NULL;
	m_pDragToPrevPageButton = NULL;
	m_flPreventDragPageSwitchUntil = 0;
	m_flStartExplanationsAt = 0;

	m_flMouseDownTime = 0;
	m_pItemDraggedFromPanel = NULL;
	m_iDraggedFromPage = 0;
	m_bMouseDownOnItemPanel = false;
	m_bDragging = false;
	m_iMouseDownX = m_iMouseDownY = 0;

	m_pMouseDragItemPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, "mousedragitempanel" ) );
	m_pCancelToolButton = NULL;
	m_pCraftButton = NULL;
	m_bShowBaseItems = false;
	m_pConfirmDeleteDialog = NULL;
	m_pToolIcon = NULL;
	m_eSelectionMode = StandardSelection;
	m_nLastToolPage = 0;
	m_pDynamicRecipePanel = NULL;
	m_pItemSlotPanel = NULL;
	m_pStrangeToolPanel = NULL;

	m_nNumActivePages = 0;

	m_pInspectPanel = new CTFItemInspectionPanel( this, "InspectionPanel" );
	m_pInspectCosmeticPanel = new CTFStorePreviewItemPanel2( this, "Resource/UI/econ/InspectionPanel_Cosmetic.res", "storepreviewitem", NULL );
	m_pCollectionCraftPanel = NULL;
	m_pHalloweenOfferingPanel = NULL;
	m_pMannCoTradePanel = NULL;

	CancelToolSelection();

	ListenForGameEvent( "gc_connected" );
}

CBackpackPanel::~CBackpackPanel()
{
	if ( m_pPageButtonKVs )
	{
		m_pPageButtonKVs->deleteThis();
		m_pPageButtonKVs = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
{
	if ( !m_pSortByComboBox && UsesRarityControls() )
	{
		m_pSortByComboBox = new vgui::ComboBox( this, "SortByComboBox", 5, false );
		m_pSortByComboBox->AddActionSignalTarget( this );
	}

	LoadControlSettings( GetResFile() );

	BaseClass::ApplySchemeSettings( pScheme );

	m_pNameFilterTextEntry = FindControl<vgui::TextEntry>( "NameFilterTextEntry" );
	if ( m_pNameFilterTextEntry )
	{
		m_pNameFilterTextEntry->AddActionSignalTarget( this );
	}

	m_pCancelToolButton = dynamic_cast<CExButton*>( FindChildByName("CancelApplyToolButton") );
	m_pCraftButton = dynamic_cast<CExButton*>( FindChildByName("CraftButton") );
	m_pToolIcon = dynamic_cast<vgui::ScalableImagePanel*>( FindChildByName("tool_icon") );

	m_pNextPageButton = dynamic_cast<CExButton*>( FindChildByName("NextPageButton") );
	m_pPrevPageButton = dynamic_cast<CExButton*>( FindChildByName("PrevPageButton") );
	m_pShowExplanationsButton = dynamic_cast<CExButton*>( FindChildByName("ShowExplanationsButton") );
	m_pDragToNextPageButton = dynamic_cast<CExButton*>( FindChildByName("DragToNextPageButton") );
	m_pDragToPrevPageButton = dynamic_cast<CExButton*>( FindChildByName("DragToPrevPageButton") );
	m_pCurPageLabel = dynamic_cast<vgui::Label*>( FindChildByName("CurPageLabel") );
	m_pShowRarityComboBox = dynamic_cast<vgui::ComboBox*>( FindChildByName( "ShowRarityComboBox" ) );
	if ( m_pShowRarityComboBox )
	{
		m_pShowRarityComboBox->AddActionSignalTarget( this );

		m_pShowRarityComboBox->AddItem( "#TF_Backpack_ShowNoBorders", NULL );
		m_pShowRarityComboBox->AddItem( "#TF_Backpack_ShowQualityBorders", NULL );
		m_pShowRarityComboBox->AddItem( "#TF_Backpack_ShowMarketableBorders", NULL );

		m_pShowRarityComboBox->ActivateItemByRow( cl_showbackpackrarities.GetInt() );
	}
	m_pShowBaseItemsCheckbox = dynamic_cast<vgui::CheckButton*>( FindChildByName( "ShowBaseItemsCheckbox" ) );
	if ( m_pShowBaseItemsCheckbox )
	{
		m_pShowBaseItemsCheckbox->AddActionSignalTarget( this );
		m_pShowBaseItemsCheckbox->SetSelected( m_bShowBaseItems );
	}

	m_pMouseDragItemPanel->SetBorder( pScheme->GetBorder("BackpackItemMouseOverBorder") );

	// Setup our combo box
	if ( m_pSortByComboBox )
	{
		m_pSortByComboBox->RemoveAll();
		vgui::HFont hFont = pScheme->GetFont( "HudFontSmallestBold", true );
		m_pSortByComboBox->SetFont( hFont );
		KeyValues *pKeyValues = new KeyValues( "data" );
		for ( int i = 0; i < ARRAYSIZE(g_BackpackSortTypes); i++ )
		{
			pKeyValues->SetInt( "sortby", i );
			m_pSortByComboBox->AddItem( g_BackpackSortTypes[i].szSortDesc, pKeyValues );
		}
		pKeyValues->deleteThis();
		m_pSortByComboBox->ActivateItemByRow( 0 );
		m_pSortByComboBox->GetMenu()->SetNumberOfVisibleItems( ARRAYSIZE(g_BackpackSortTypes) );
	}

	// Create page buttons
	const int nNumMaxPages = GetNumMaxPages();
	for ( int i=m_Pages.Count(); i<nNumMaxPages; ++i )
	{
		EditablePanel *pPage = vgui::SETUP_PANEL( new EditablePanel( this, CFmtStr( "page_%d", i ) ) );
		m_Pages.AddToTail( pPage );
	}

	if ( m_pInspectCosmeticPanel )
	{
		// Force it to load it's scheme now, because it needs to be done before we set it's visibility below
		m_pInspectCosmeticPanel->InvalidateLayout( false, true );
		m_pInspectCosmeticPanel->SetVisible( false );
	}
}

void CBackpackPanel::ApplySettings( KeyValues *inResourceData )
{
	BaseClass::ApplySettings( inResourceData );

	KeyValues *pItemKV = inResourceData->FindKey( "pagebuttons_kv" );
	if ( pItemKV )
	{
		if ( m_pPageButtonKVs )
		{
			m_pPageButtonKVs->deleteThis();
		}
		m_pPageButtonKVs = new KeyValues("pagebuttons_kv");
		pItemKV->CopySubkeys( m_pPageButtonKVs );
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::AddNewItemPanel( int iPanelIndex )
{
	BaseClass::AddNewItemPanel( iPanelIndex );

	// Store a position for our new panel
	m_ItemModelPanelPos.AddToTail();
	m_ItemModelPanelPos[iPanelIndex].x = m_ItemModelPanelPos[iPanelIndex].y = 0;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CItemModelPanel *CBackpackPanel::GetItemPanelAtPos( int x, int y )
{
	if ( !m_pItemModelPanels.Count() )
		return NULL;

	int iW = m_pItemModelPanels[0]->GetWide();
	int iH = m_pItemModelPanels[0]->GetTall();
	for ( int i = 0; i < m_ItemModelPanelPos.Count(); i++ )
	{
		if ( (x < m_ItemModelPanelPos[i].x) || (x > (m_ItemModelPanelPos[i].x + iW)) )
			continue;
		if ( (y < m_ItemModelPanelPos[i].y) || (y > (m_ItemModelPanelPos[i].y + iH)) )
			continue;
		return m_pItemModelPanels[i];
	}

	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBackpackPanel::GetPageButtonIndexAtPos( int x, int y )
{
	if ( !m_Pages.Count() )
		return -1;

	int iW = m_Pages[0]->GetWide();
	int iH = m_Pages[0]->GetTall();
	for ( int i = 0; i < m_PageButtonPos.Count(); i++ )
	{
		if ( (x < m_PageButtonPos[i].x) || (x > (m_PageButtonPos[i].x + iW)) )
			continue;
		if ( (y < m_PageButtonPos[i].y) || (y > (m_PageButtonPos[i].y + iH)) )
			continue;
		return m_Pages[i]->IsVisible() ? i : -1;
	}

	return -1;
}

//-----------------------------------------------------------------------------
// Purpose: Change the text color on the page buttons based on the context of the
//			page they represent.
//-----------------------------------------------------------------------------
void CBackpackPanel::SetPageButtonTextColorBasedOnContents()
{
	vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );

	if ( m_Pages.Count() == 0 )
		return;

	if ( !pScheme )
		return;

	const Color& colorEmpty =  pScheme->GetColor( "TanDarker", Color( 235, 226, 202, 255 ) );
	const Color& colorPartial = Color( 170, 161, 137, 255 );
	const Color& colorFull = pScheme->GetColor( "TanLight", Color( 235, 226, 202, 255 ) );
	const Color& colorSelected = pScheme->GetColor( "TFOrange", Color( 145, 73, 59, 255 ) );

	CUtlVector<int> vecPageCount;
	CUtlVector<int> vecNewPageCount;
	vecPageCount.EnsureCount( m_Pages.Count() );
	vecNewPageCount.EnsureCount( m_Pages.Count() );
	// Initialize to 0
	FOR_EACH_VEC( vecPageCount, i )
	{
		vecPageCount[i] = 0;
		vecNewPageCount[i] = 0;
	}

	CPlayerInventory *pInv = InventoryManager()->GetLocalInventory();
	Assert( pInv );
	// Tally up how many items are on each page
	if ( pInv )
	{
		for ( int i = 0 ; i < pInv->GetItemCount() ; ++i )
		{
			CEconItemView *pItem = pInv->GetItem( i );
			const int nSlot = InventoryManager()->GetBackpackPositionFromBackend( pItem->GetInventoryPosition() ) - 1;
			const int nPage = nSlot / GetNumSlotsPerPage();	 
			if ( nPage >= 0 && nPage < m_Pages.Count() )
			{
				vecPageCount[ nPage ] = vecPageCount[ nPage ] + 1;

				// Unackknowledged items technically are on the 1st page, so dont count them
				if ( m_mapSeenItems.Find( pItem->GetItemID() ) == m_mapSeenItems.InvalidIndex()
					&& IsUnacknowledged( pItem->GetInventoryPosition() ) == false && !m_bShowBaseItems && !HasNameFilter() )
				{
					vecNewPageCount[ nPage ] = vecNewPageCount[ nPage ] + 1;
				}
			}
		}
	}

	// Set the color for each page button
	FOR_EACH_VEC( m_Pages, i )
	{
		const int nNewCount = vecNewPageCount[i];
		const int nCount = vecPageCount[i];
		CExButton* pButton = dynamic_cast<CExButton*>( m_Pages[i]->FindChildByName( "Button" ) );
		if ( pButton )
		{
			Color setColor = colorEmpty;
			const Color& bgColor = GetCurrentPage() == i ? colorSelected : pButton->GetButtonDefaultBgColor();

			if ( nCount == GetNumSlotsPerPage() )
				setColor = colorFull;
			else if ( nCount > 0 )
				setColor = colorPartial;

			pButton->SetSelectedColor( setColor, pButton->GetButtonSelectedBgColor() );
			pButton->SetDefaultColor( setColor, bgColor );
			pButton->SetArmedColor( setColor, pButton->GetButtonArmedBgColor() );
			pButton->SetDepressedColor( setColor, pButton->GetButtonDepressedBgColor() );
		}

		// Show our "NEW!" label if there's any unseen items on that page
		CExLabel* pNew = dynamic_cast<CExLabel*>( m_Pages[i]->FindChildByName( "New" ) );
		if ( pNew )
		{
			pNew->SetVisible( nNewCount > 0 );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::MarkItemIDDirty( itemid_t itemID )
{
	if ( m_vecDirtyItems.Find( itemID ) == m_vecDirtyItems.InvalidIndex() )
	{
		m_vecDirtyItems.AddToTail( itemID );
	}
}


//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::PositionItemPanel( CItemModelPanel *pPanel, int iIndex )
{
	int iCenter = GetWide() * 0.5;
	int iButtonX = (iIndex % GetNumColumns());
	int iButtonY = (iIndex / GetNumColumns());
	int iXPos = (iCenter + m_iItemBackpackOffcenterX) + (iButtonX * m_pItemModelPanels[iIndex]->GetWide()) + (m_iItemBackpackXDelta * iButtonX);
	int iYPos = m_iItemYPos + (iButtonY * m_pItemModelPanels[iIndex]->GetTall() ) + (m_iItemBackpackYDelta * iButtonY);

	m_pItemModelPanels[iIndex]->SetPos( iXPos, iYPos );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::PerformLayout( void ) 
{
	BaseClass::PerformLayout();

	for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
	{
		// Viewing the backpack. Layout all the buttons and hide the class image.
		m_pItemModelPanels[i]->SetVisible( true );
		m_pItemModelPanels[i]->SetNoItemText( "#SelectNoItemSlot" );

		PositionItemPanel( m_pItemModelPanels[i], i );

		// Cache off where we put the panel
		m_pItemModelPanels[i]->GetPos( m_ItemModelPanelPos[i].x, m_ItemModelPanelPos[i].y );

		// Take into account parent's position
		Panel* pParent = m_pItemModelPanels[i]->GetParent();
		if( pParent )
		{
			int x = 0,y = 0;
			pParent->GetPos( x, y );
			m_ItemModelPanelPos[i].x += x;
			m_ItemModelPanelPos[i].y += y;
		}
	}

	// adjust page buttons
	{
		m_nNumActivePages = GetNumPages();

		int iCenter = GetWide() * 0.5;

		int iPageBarWidth = 2 * abs( m_iItemBackpackOffcenterX );
		int iPageButtonWidth = ( iPageBarWidth - ( m_iPageButtonPerRow - 1 ) * m_iPageButtonXDelta ) / m_iPageButtonPerRow;
		int iPageButtonWidthPlusDelta = iPageButtonWidth + m_iPageButtonXDelta;
		int iPageButtonHeightPlusDelta = m_iPageButtonHeight + m_iPageButtonYDelta;
		int iStart = iCenter + m_iItemBackpackOffcenterX;

		m_PageButtonPos.EnsureCount( m_Pages.Count() );
		for ( int i=0; i<m_Pages.Count(); ++i )
		{
			EditablePanel *pPage = m_Pages[i];
			if ( pPage )
			{
				// Apply control settings here
				if ( m_pPageButtonKVs )
					pPage->ApplySettings( m_pPageButtonKVs );
				CExButton* pButton = dynamic_cast<CExButton*>( pPage->FindChildByName( "Button" ) );
				pPage->InvalidateLayout( true, true );
				// Make the button have the right command and send it's signals to us
				if ( pButton )
				{
					pButton->SetSelected( false );
					pButton->SetCommand( CFmtStr( "goto_page_%d", i ) );
					pButton->AddActionSignalTarget( this );
				}
				pPage->SetDialogVariable( "page", i+1 );
				
				bool bVisible = i < m_nNumActivePages;
				if ( bVisible )
				{
					int iRow = i /m_iPageButtonPerRow;
					int iColumn = i % m_iPageButtonPerRow;
					pPage->SetBounds( iStart + iColumn * iPageButtonWidthPlusDelta, m_iPageButtonYPos + iRow * iPageButtonHeightPlusDelta, iPageButtonWidth, m_iPageButtonHeight );
					pPage->GetPos( m_PageButtonPos[i].x , m_PageButtonPos[i].y );
				}
				pPage->SetVisible( bVisible );
			}
		}

		// Update colors and the "NEW!" labels
		SetPageButtonTextColorBasedOnContents();
	}

	if ( m_pNextPageButton )
	{
		m_pNextPageButton->SetVisible( true );
	}
	if ( m_pPrevPageButton )
	{
		m_pPrevPageButton->SetVisible( true );
	}
	if ( m_pCurPageLabel )
	{
		m_pCurPageLabel->SetVisible( true );
	}

	if ( m_pSortByComboBox )
	{
		m_pSortByComboBox->SetVisible( !InToolSelectionMode() );
	}
	if ( m_pShowRarityComboBox )
	{
		m_pShowRarityComboBox->SetVisible( true );
	}

	if ( m_pNextPageButton )
	{
		m_pNextPageButton->SetEnabled( GetNumPages() > 1 );
	}
	if ( m_pPrevPageButton )
	{
		m_pPrevPageButton->SetEnabled( GetNumPages() > 1 );
	}

	if ( !m_bDragging )
	{	
		if ( m_pDragToNextPageButton && m_pDragToPrevPageButton )
		{
			m_pDragToNextPageButton->SetVisible( false );
			m_pDragToPrevPageButton->SetVisible( false );
		}
	}

	bool bShowActions = (!m_bItemsOnly && !InToolSelectionMode());
	if ( m_pCraftButton )
	{
		m_pCraftButton->SetVisible( bShowActions );
	}
	if ( m_pCancelToolButton )
	{
		m_pCancelToolButton->SetVisible( InToolSelectionMode() );
	}

	if ( m_pShowExplanationsButton )
	{
		m_pShowExplanationsButton->SetVisible( !m_bItemsOnly );
	}
	if ( m_pShowBaseItemsCheckbox )
	{
		m_pShowBaseItemsCheckbox->SetVisible( !m_bItemsOnly );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::FireGameEvent( IGameEvent *event )
{
	static CSchemaItemDefHandle pItemDef_BasePaintCan( "Paint Can" );
	const char *type = event->GetName();
	if ( Q_strcmp( "gc_connected", type ) == 0 )
	{
		if ( !m_bInitializedSeenItems )
		{
			CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
			if ( pInventory )
			{
				for ( int i = 0; i < pInventory->GetItemCount(); i++ )
				{
					CEconItemView *pItem = pInventory->GetItem(i);
					m_mapSeenItems.Insert( pItem->GetItemID() );
				}
			}

			m_bInitializedSeenItems = true;
		}

		m_vecPaintCans.Purge();
		m_vecStrangeParts.Purge();
		const CEconItemSchema::ToolsItemDefinitionMap_t &toolDefs = GetItemSchema()->GetToolsItemDefinitionMap();

		// Store all of the active paint can item defs
		FOR_EACH_MAP_FAST( toolDefs, i )
		{
			const CEconItemDefinition *pItemDef = toolDefs[i];
			const IEconTool *pEconTool = pItemDef->GetEconTool();
			if ( !pEconTool )
				continue;

			// Paint can list
			// Ignore the stock paintcan thats only for armory purposes
			if ( !V_strcmp( pEconTool->GetTypeName(), "paint_can" ) && pItemDef_BasePaintCan != pItemDef ) 
			{
				// Paint Can
				m_vecPaintCans.AddToTail( pItemDef->GetDefinitionIndex() );
			}
			// Strange Parts List
			else if ( !V_strcmp( pEconTool->GetTypeName(), "strange_part" ) )
			{
				m_vecStrangeParts.AddToTail( pItemDef->GetDefinitionIndex() );
			}
		}
	}

	BaseClass::FireGameEvent( event );
}

void CBackpackPanel::CheckForQuickOpenKey()
{
	if ( !m_hQuickOpenCrate )
		return;

	// We only want to continue if it's the transaction we're listening for
	if ( EconUI()->GetStorePanel()->GetMostRecentSuccessfulTransactionID() != m_nQuickOpenTxn )
	{
		return;
	}

	CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
	if ( pInventory )
	{
		for ( int i = 0; i < pInventory->GetItemCount(); i++ )
		{
			CEconItemView *pInvItem = pInventory->GetItem( i );

			uint32 iPosition = pInvItem->GetInventoryPosition();
			if ( IsUnacknowledged( iPosition ) == false )
				continue;

			if ( InventoryManager()->GetBackpackPositionFromBackend( iPosition ) != 0 )
				continue;

			// Now make sure we haven't got a clientside saved ack for this item.
			if ( InventoryManager()->HasBeenAckedByClient( pInvItem ) )
				continue;

			// If item is not a drop we want to show the notification otherwise they'll get the notification on death
			int iFoundMethod = GetUnacknowledgedReason( iPosition );
			if ( iFoundMethod != UNACK_ITEM_PURCHASED )
				continue;

			if ( !pInvItem->GetStaticData()->IsTool() )
				continue;

			if( !CEconSharedToolSupport::ToolCanApplyTo( pInvItem, m_hQuickOpenCrate ) )
				continue;

			if ( !pInvItem->GetStaticData()->GetEconTool() )
				continue;

			if ( !Q_strcmp( pInvItem->GetStaticData()->GetEconTool()->GetTypeName(), "decoder_ring" ) == 0 )
				continue;

			ApplyTool( this, pInvItem, m_hQuickOpenCrate );
			CloseStoreStatusDialog();

			m_hQuickOpenCrate = NULL;
			m_nQuickOpenTxn = 0;
			return;
		}
	}

	m_hQuickOpenCrate = NULL;
	m_nQuickOpenTxn = 0;
}

//-----------------------------------------------------------------------------
// Purpose: When the store get's a new transaction ID, it comes here as well
//-----------------------------------------------------------------------------
void CBackpackPanel::SetCurrentTransactionID( uint64 nTxnID )
{
	// If we've got a quick open crate st, and no quick open transaction ID,
	// then we want to capture the incoming transaction ID so that we can
	// compare future incoming successful transactions to see if they have
	// the key we're expecting
	if ( m_hQuickOpenCrate && m_nQuickOpenTxn == 0 )
	{
		m_nQuickOpenTxn = nTxnID;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnShowPanel( bool bVisible, bool bReturningFromArmory )
{
	if ( bVisible )
	{
		m_pMouseDragItemPanel->SetVisible( false );

		if( m_pDynamicRecipePanel )
		{
			m_pDynamicRecipePanel->SetVisible( false );
		}

		if ( m_pItemSlotPanel )
		{
			m_pItemSlotPanel->SetVisible( false );
		}

		m_bShowBaseItems = false;
		if ( m_pShowBaseItemsCheckbox )
		{
			m_pShowBaseItemsCheckbox->SetSelected( m_bShowBaseItems );
		}

		if ( !bReturningFromArmory )
		{
			SetCurrentPage( 0 );
			CancelToolSelection();
		}

		m_nNumActivePages = 0;

#ifdef STAGING_ONLY
		// Reset pinned-state of the card
		m_pMouseOverCardPanel->PinCard( false );
#endif
	}
	else
	{
		if ( m_bDragging )
		{
			StopDrag( false );
		}
	}

	if ( m_pInspectPanel )
	{
		m_pInspectPanel->SetVisible( false );
	}

	if ( m_pInspectCosmeticPanel )
	{
		m_pInspectCosmeticPanel->SetVisible( false );
	}

	if ( m_pCollectionCraftPanel )
	{
		m_pCollectionCraftPanel->SetVisible( false );
	}

	if ( m_pHalloweenOfferingPanel )
	{
		m_pHalloweenOfferingPanel->SetVisible( false );
	}

	if ( m_pMannCoTradePanel )
	{
		m_pMannCoTradePanel->SetVisible( false );
	}

	if ( m_pStrangeToolPanel )
	{
		m_pStrangeToolPanel->MarkForDeletion();
		m_pStrangeToolPanel = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::PostShowPanel( bool bVisible )
{
	if ( bVisible )
	{
		DeSelectAllBackpackItemPanels();

		RequestFocus();

		// Clear out text field
		ClearNameFilter( true );
	}

	// If this is the first time we've opened the loadout, start the loadout explanations
	ConVar *pConVar = GetExplanationConVar();
	if ( bVisible && pConVar && !pConVar->GetBool() && ShouldShowExplanations() )
	{
		m_flStartExplanationsAt = Plat_FloatTime() + 0.5;
		vgui::ivgui()->AddTickSignal( GetVPanel() );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CBackpackPanel::GetNumPages( void )
{
	int iMaxItems = InventoryManager()->GetLocalInventory()->GetMaxItemCount();
	return (int)(ceil((float)iMaxItems / (float)BACKPACK_SLOTS_PER_PAGE));
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::AssignItemToPanel( CItemModelPanel *pPanel, int iIndex )
{
	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );

	static int iItemBackpackPos = 0;
	if ( iIndex == 0 )
	{
		iItemBackpackPos = 0;
	}
	int iPanelBackpackPos = GetBackpackPosForPanelIndex(iIndex);

	static int iLastMapItem = -1;

	pPanel->SetShowQuantity( true );

	const wchar_t* wszFilter = GetNameFilter();
	bool bInToolSelection = InToolSelectionMode() && m_ToolSelectionItem.IsValid();

	CEconItemView *pItemData = NULL;
	CEconItemView tempItem;
	if ( m_bShowBaseItems )
	{
		const CEconItemDefinition* pItemDef = NULL;

		const CEconItemSchema::BaseItemDefinitionMap_t& mapItems = GetItemSchema()->GetBaseItemDefinitionMap();
		int iStart = iIndex == 0 ? mapItems.FirstInorder() : mapItems.NextInorder( iLastMapItem );
		for ( int it = iStart; it != mapItems.InvalidIndex(); it = mapItems.NextInorder( it ) )
		{
			iLastMapItem = it;

			if ( mapItems[it]->IsBaseItem() && !mapItems[it]->IsHidden() )
			{
				// Instead of linking to this base item definition, link to the definition of what it will become
				// when we customize it.
				CFmtStr fmtStrCustomizedDefName( "Upgradeable %s", mapItems[it]->GetDefinitionName() );
				pItemDef = GetItemSchema()->GetItemDefinitionByName( fmtStrCustomizedDefName.Access() );
				
				// If we don't have an upgradeable version, we assume that we can't upgrade it and link to the base
				// definition instead. We expect this to only happen if the item won't actually be useable for whatever
				// purpose (name tags, etc.). We sanity-check this on the GC.
				if ( !pItemDef )
				{
					pItemDef = mapItems[it];
				}

				tempItem.Init( pItemDef->GetDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );

				// skip this item if the tool cannot be applied to it
				if ( bInToolSelection && !CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, &tempItem ) )
				{
					pItemDef = NULL;
					continue;
				}

				if ( DoesItemPassSearchFilter( tempItem.GetDescription(), wszFilter ) )
				{
					break;
				}
			}

			pItemDef = NULL;
		}

		if ( pItemDef )
		{
			pItemData = &tempItem;

			++iItemBackpackPos;
		}
	}
	else if ( HasNameFilter() )
	{
		int iStart = iIndex == 0 ? m_mapFilteringItems.FirstInorder() : m_mapFilteringItems.NextInorder( iLastMapItem );
		for ( int it = iStart; it != m_mapFilteringItems.InvalidIndex(); it = m_mapFilteringItems.NextInorder( it ) )
		{
			iLastMapItem = it;

			CEconItemView *pItem = m_mapFilteringItems[it];

			// skip this item if the tool cannot be applied to it
			if ( bInToolSelection && !CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, pItem ) )
			{
				continue;
			}

			if ( !DoesItemPassSearchFilter( pItem->GetDescription(), wszFilter ) )
			{
				continue;
			}

			if ( ++iItemBackpackPos != iPanelBackpackPos )
			{
				continue;
			}

			pItemData = pItem;
			break;
		}
	}
	else if ( bInToolSelection )
	{
		CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
		if ( pInventory )
		{
			// Backpack positions start from 1
			Assert( iPanelBackpackPos > 0 && iPanelBackpackPos <= pInventory->GetMaxItemCount() );
			int iStart = iIndex == 0 ? 0 : iLastMapItem + 1;
			for ( int i = iStart; i < pInventory->GetItemCount(); i++ )
			{
				iLastMapItem = i;

				CEconItemView *pItem = pInventory->GetItem(i);

				if ( m_ToolSelectionItem.GetStaticData()->IsTool() )
				{
					if ( !CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, pItem ) )
					{
						continue;
					}
				}
				else
				{
					if ( !pItem->GetStaticData()->IsTool() )
					{
						continue;
					}

					if ( !CEconSharedToolSupport::ToolCanApplyTo( pItem, &m_ToolSelectionItem ) )
					{
						continue;
					}

					if ( ( m_ToolSelectionItem.GetStaticData()->GetCapabilities() & ITEM_CAP_DECODABLE ) && pItem->GetStaticData()->GetEconTool() && ( Q_strcmp( pItem->GetStaticData()->GetEconTool()->GetTypeName(), "decoder_ring" ) != 0 ) )
					{
						continue;
					}
				}

				if ( ++iItemBackpackPos != iPanelBackpackPos )
				{
					continue;
				}

				pItemData = pItem;
				break;
			}
		}
	}
	else
	{
		pItemData = InventoryManager()->GetItemByBackpackPosition( iPanelBackpackPos );
		iItemBackpackPos = iPanelBackpackPos;

		if ( pItemData == NULL && pPanel->GetItem() == NULL )
		{
			return;
		}

		int nDirtyIndex = pItemData ? m_vecDirtyItems.Find( pItemData->GetItemID() ) : m_vecDirtyItems.InvalidIndex();

		if ( pItemData	// Want to put in an item
		  && pPanel->GetItem()	// Panel has an item
		  && pItemData->GetItemID() == pPanel->GetItem()->GetItemID() // That panel has the same item that we want to put in
		  && nDirtyIndex == m_vecDirtyItems.InvalidIndex() ) // And that item is not dirtied.  
		{
			// We dont do anything
			return;
		}

		if ( nDirtyIndex != m_vecDirtyItems.InvalidIndex() )
		{
			m_vecDirtyItems.Remove( nDirtyIndex );
		}
	}

	if ( iItemBackpackPos != iPanelBackpackPos )
	{
		pItemData = NULL;
	}

	pPanel->SetItem( pItemData );

	bool bSeen = true;
	// Have we not seen this item before?
	if ( !m_bShowBaseItems && pItemData && m_mapSeenItems.Find( pItemData->GetItemID() ) == m_mapSeenItems.InvalidIndex() )
	{
		bSeen = false;
	}

	// Show our "NEW!" label if this item hasnt been seen
	CExLabel *pNewPanel = dynamic_cast< CExLabel* >( pPanel->FindChildByName( "New" ) );
	if ( pNewPanel )
	{
		pNewPanel->SetVisible( !bSeen );
	}

	pPanel->DirtyDescription();
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::ClearNameFilter( bool bUpdateModelPanels )
{
	if ( m_wNameFilter.Count() == 0 )
		return;

	m_wNameFilter.RemoveAll();
	if( m_pNameFilterTextEntry )
	{
		m_pNameFilterTextEntry->SetText( "" );
	}

	if ( bUpdateModelPanels )
	{
		m_flFilterItemTime = gpGlobals->curtime + 0.1f;
	}
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::UpdateFilteringItems()
{
	m_mapFilteringItems.RemoveAll();

	if ( !HasNameFilter() )
		return;

	CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
	if ( !pInventory )
		return;

	for ( int i = 0; i < pInventory->GetItemCount(); i++ )
	{
		CEconItemView *pItem = pInventory->GetItem(i);

		if ( pItem->GetItemDefinition()->IsHidden() )
			continue;

		int iBackpackPosition = InventoryManager()->GetBackpackPositionFromBackend( pItem->GetInventoryPosition() );
		m_mapFilteringItems.Insert( iBackpackPosition, pItem );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::UpdateModelPanels( void )
{
	tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );

	UpdateFilteringItems();
	
	// We're showing the backpack. Show all the items in our inventory
	FOR_EACH_VEC( m_pItemModelPanels, i )
	{
		m_pItemModelPanels[i]->SetShowEquipped( true );
		m_pItemModelPanels[i]->SetShowGreyedOutTooltip( true );
		AssignItemToPanel( m_pItemModelPanels[i], i );

		if ( !m_pItemModelPanels[i]->HasItem() && m_pItemModelPanels[i]->IsSelected() )
		{
			m_pItemModelPanels[i]->SetSelected( false );
		}

		SetBorderForItem( m_pItemModelPanels[i], false );
	}

	// Clean out.  We just did all the heavy lifting.
	m_vecDirtyItems.Purge();

	if ( InToolSelectionMode() && m_ToolSelectionItem.IsValid() )
	{
		wchar_t	wTemp[256];
		g_pVGuiLocalize->ConstructString_safe( wTemp, g_pVGuiLocalize->Find( "BackpackApplyTool" ), 1, m_ToolSelectionItem.GetItemName() );
		SetDialogVariable( "loadoutclass", wTemp );
	}
	else
	{
		SetDialogVariable( "loadoutclass", g_pVGuiLocalize->Find( "BackpackTitle" ) );
	}

	char szTmp[16];
	V_sprintf_safe( szTmp, "%d/%d", GetCurrentPage()+1, GetNumPages() );
	SetDialogVariable( "backpackpage", szTmp );

	// Now layout again to position our item buttons 
	InvalidateLayout();
}

//-----------------------------------------------------------------------------
// Purpose: Mark visited item model panels as seen
//-----------------------------------------------------------------------------
void CBackpackPanel::OnItemPanelEntered( vgui::Panel *panel )
{
	if ( m_pContextMenu && m_pContextMenu->IsVisible() )
		return;

	CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );
	if ( pItemPanel )
	{
		// Hide the "NEW!" label
		CExLabel *pNewPanel = dynamic_cast< CExLabel* >( pItemPanel->FindChildByName( "New" ) );
		if ( pNewPanel )
		{
			pNewPanel->SetVisible( false );
		}

		// Mark this item as "seen"
		CEconItemView *pItem = pItemPanel->GetItem();
		if ( pItem )
		{
			if ( m_mapSeenItems.Find( pItem->GetItemID() ) == m_mapSeenItems.InvalidIndex() )
			{
				m_mapSeenItems.Insert( pItem->GetItemID() );
				SetPageButtonTextColorBasedOnContents();
			}
		}
	}

	BaseClass::OnItemPanelEntered( panel );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnItemPanelMousePressed( vgui::Panel *panel )
{
	CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );

	if ( pItemPanel && IsVisible() && pItemPanel->IsGreyedOut() == false && AllowDragging( pItemPanel ) )
	{
		m_flMouseDownTime = gpGlobals->curtime;
		m_iMouseDownX = m_iMouseDownY = 0;
		m_pItemDraggedFromPanel = pItemPanel;
		m_iDraggedFromPage = GetCurrentPage();
		m_bDragging = false;
		m_bMouseDownOnItemPanel = true;
	}
}


//-----------------------------------------------------------------------------
// Purpose: Handle the escape key since it doesn't show up in OnKeyCodePressed
//-----------------------------------------------------------------------------
void CBackpackPanel::OnKeyCodeTyped(vgui::KeyCode code)
{
	if ( code == KEY_ESCAPE && InToolSelectionMode() )
	{
		CancelToolSelection();
	}
	else if ( code == KEY_ENTER )
	{
		// Do nothing.  This gets hit frequently when people type in the filter
		// text entry and then hit 'Enter', expecting it to execute the filter.
		// We automatically apply it, so let's just eat 'Enter', which was causing
		// us to activate some button on the main menu.
	}
	else
	{
		BaseClass::OnKeyCodeTyped( code );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Handles key press events in the backpack
//-----------------------------------------------------------------------------
void CBackpackPanel::OnKeyCodePressed( vgui::KeyCode code )
{
	// Ignore key events while the confirm delete dialog is up
	if( m_pConfirmDeleteDialog )
		return;

	// let our parent class handle all the arrow key/dpad stuff
	if( HandleItemSelectionKeyPressed( code ) )
	{
		return;
	}

	// Handle close here, CBasePanel parent doesn't support "DialogClosing" command
	ButtonCode_t nButtonCode = GetBaseButtonCode( code );

	if ( (nButtonCode == KEY_XBUTTON_B || nButtonCode == STEAMCONTROLLER_B) && InToolSelectionMode() )
	{
		CancelToolSelection();
	}
	else if( code == KEY_PAGEDOWN )
	{
		OnCommand( "nextpage" );
	}
	else if( code == KEY_PAGEUP )
	{
		OnCommand( "prevpage" );
	}
	else if ( ( nButtonCode == KEY_XBUTTON_A || code == KEY_ENTER || nButtonCode == STEAMCONTROLLER_A ) )
	{
		if( InToolSelectionMode() )
		{
			HandleToolItemSelection( GetFirstSelectedItem() );
		}
		else
		{
			OpenContextMenu();
		}
	}
	else if ( nButtonCode == KEY_XBUTTON_X || nButtonCode == STEAMCONTROLLER_X )
	{
		if( !InToolSelectionMode() )
		{
			OnCommand( "deleteitem" );
		}
	}
	else
	{
		BaseClass::OnKeyCodePressed( code );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Handles key press events in the backpack
//-----------------------------------------------------------------------------
void CBackpackPanel::OnKeyCodeReleased( vgui::KeyCode code )
{
	if( ! HandleItemSelectionKeyReleased( code ) )
		BaseClass::OnKeyCodeReleased( code );
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnMouseCaptureLost( void )
{
	if ( m_bDragging )
	{
		StopDrag( false );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnMouseReleased(vgui::MouseCode code)
{
	if ( code == MOUSE_LEFT )
	{
		if ( m_bDragging )
		{
			// When we're dragging, we have mouse capture, so the item panels aren't getting mouse input.
			// We need to find out what item panel we're over, and let it know.
			if ( m_pPrevDragOverItemPanel )
			{
				OnItemPanelMouseReleased( m_pPrevDragOverItemPanel );
			}
			else
			{
				StopDrag( false );
			}
		}
	}

	BaseClass::OnMouseReleased( code );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnConfirmDelete( KeyValues *data )
{
	// Delete all the selected item
	if ( data )
	{
		int iConfirmed = data->GetInt( "confirmed", 0 );
		if ( iConfirmed )
		{
			for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
			{
				if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
				{
					EconUI()->Gamestats_ItemTransaction( IE_ITEM_DELETED, m_pItemModelPanels[i]->GetItem() );
					InventoryManager()->DropItem( m_pItemModelPanels[i]->GetItem()->GetItemID() );
				}
			}
			DeSelectAllBackpackItemPanels();
		}
	}

	m_pConfirmDeleteDialog = NULL;

	// If we're embedded in the discard item panel, it needs to know we made room. Send a message to our parent that it can catch.
	PostMessage( GetParent(), new KeyValues("ConfirmDlgResult", "confirmed", 2 ) );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnItemPanelMouseReleased( vgui::Panel *panel )
{
	CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );

	if ( pItemPanel && IsVisible() )
	{
		if ( InToolSelectionMode() )
		{
			// They're selecting the item they'd like to apply a tool to
			HandleToolItemSelection( pItemPanel->GetItem() );
		}
		else if ( !m_bDragging )
		{
			// If they're not holding down ctrl, deselect all existing selections
			if ( !vgui::input()->IsKeyDown(KEY_LCONTROL) && !vgui::input()->IsKeyDown(KEY_RCONTROL) )
			{
				DeSelectAllBackpackItemPanels();
			}

			// Quick clicks just select the item
			ToggleSelectBackpackItemPanel( pItemPanel );

			if ( pItemPanel->IsSelected() )
			{
				OpenContextMenu();
			}
		}
		else
		{
			int iPanelIndex = GetBackpackPositionForPanel( pItemPanel );
			if ( !CanDragTo(pItemPanel, iPanelIndex) )
			{
				StopDrag(false);
			}
			else
			{
				StopDrag( true );
				if ( (pItemPanel != m_pItemDraggedFromPanel || m_iDraggedFromPage != GetCurrentPage() ) && m_pMouseDragItemPanel->HasItem() )
				{
					HandleDragTo( pItemPanel, iPanelIndex );
				}
				else if ( m_iDraggedFromPage == GetCurrentPage() )
				{
					m_pItemDraggedFromPanel->SetItem( m_pMouseDragItemPanel->GetItem() );
				}
			}
		}

		m_pItemDraggedFromPanel = NULL;
	}
}


bool GetDecodedByItemDefIndex( const CEconItemView *pItem, uint32 *pDecodedBy = NULL )
{
	static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "decoded by itemdefindex" );

	if ( pDecodedBy )
	{
		return pItem->FindAttribute( pAttrDef_DecodedBy, pDecodedBy );
	}
	else
	{
		return pItem->FindAttribute( pAttrDef_DecodedBy );
	}
}

CEconItemView* GetFirstCompatibleKeyForCrate( const CEconItemView *pItem )
{
	// Check if we have any decoder rings that can be applied onto this
	CPlayerInventory *pInv = InventoryManager()->GetLocalInventory();
	Assert( pInv );
	if ( pInv )
	{
		for ( int i = 0; i < pInv->GetItemCount(); ++i )
		{
			CEconItemView *pInvItem = pInv->GetItem( i );

			if ( pInvItem->GetQuality() == AE_SELFMADE )
				continue;

			if ( pInvItem->GetStaticData()->IsTool() && CEconSharedToolSupport::ToolCanApplyTo( pInvItem, pItem ) && pInvItem->GetStaticData()->GetEconTool() && ( Q_strcmp( pInvItem->GetStaticData()->GetEconTool()->GetTypeName(), "decoder_ring" ) == 0 ) )
			{
				return pInvItem;
			}
		}
	}

	return NULL;
}

bool CanInventoryItemsApplyTo( const CEconItemView *pItem )
{
	// Check if we have any tools that can be applied onto this
	CPlayerInventory *pInv = InventoryManager()->GetLocalInventory();
	Assert( pInv );
	if ( pInv )
	{
		for ( int i = 0 ; i < pInv->GetItemCount() ; ++i )
		{
			CEconItemView *pInvItem = pInv->GetItem( i );
			if ( pInvItem->GetStaticData()->IsTool() && CEconSharedToolSupport::ToolCanApplyTo( pInvItem, pItem ) )
			{
				return true;
			}
		}
	}

	return false;
}
//-----------------------------------------------------------------------------
bool CreateMarketPriceString( item_definition_index_t iDefIndex, wchar_t *pszString, int iBufferSize )
{
	// Get Market Price
	steam_market_gc_identifier_t ident;
	ident.m_unDefIndex = iDefIndex;
	ident.m_unQuality = AE_UNIQUE;			// Get this from default item def?

	const client_market_data_t *pClientMarketData = GetClientMarketData( ident );
	if ( !pClientMarketData )
		return false;

	const ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency();

	// Set that price into the button
	wchar_t pszCurrencyString[kLocalizedPriceSizeInChararacters];
	MakeMoneyString( pszCurrencyString, ARRAYSIZE( pszCurrencyString ), pClientMarketData->m_unLowestPrice, eCurrency );

	wchar_t pszConstructed[kLocalizedPriceSizeInChararacters];
	g_pVGuiLocalize->ConstructString_safe( pszConstructed, g_pVGuiLocalize->Find( "#TF_MarketPrice" ), 1, pszCurrencyString );

	// copy result;
	V_wcsncpy( pszString, pszConstructed, iBufferSize );
	return true;
}
//-----------------------------------------------------------------------------
bool CreateStorePriceString( item_definition_index_t iDefIndex, wchar_t *pszString, int iBufferSize )
{
	// Get Market Price
	steam_market_gc_identifier_t ident;
	ident.m_unDefIndex = iDefIndex;
	ident.m_unQuality = AE_UNIQUE;			// Get this from default item def?

	// Get the price of the item
	const econ_store_entry_t *pEntry = EconUI()->GetStorePanel()->GetPriceSheet()->GetEntry( iDefIndex );
	if ( !pEntry )
		return false;

	const ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency();

	// Set that price into the button
	wchar_t pszCurrencyString[kLocalizedPriceSizeInChararacters];
	MakeMoneyString( pszCurrencyString, ARRAYSIZE( pszCurrencyString ), pEntry->GetCurrentPrice( eCurrency ), eCurrency );

	wchar_t pszConstructed[kLocalizedPriceSizeInChararacters];
	g_pVGuiLocalize->ConstructString_safe( pszConstructed, g_pVGuiLocalize->Find( "#TF_StorePrice" ), 1, pszCurrencyString );

	// copy result;
	V_wcsncpy( pszString, pszConstructed, iBufferSize );
	return true;
}
//-----------------------------------------------------------------------------
void CBackpackPanel::AddCommerceSubmenus( Menu *pSubMenu, item_definition_index_t iItemDef, const char* pszActionFmt )
{
	wchar_t wPriceListing[256];
	// Store
	if ( CreateStorePriceString( iItemDef, wPriceListing, sizeof( wPriceListing ) ) )
	{
		int nIndex = pSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "%s%s%d", "store_", pszActionFmt, iItemDef ) ), this );
		vgui::MenuItem *pMenuItem = pSubMenu->GetMenuItem( nIndex );
		pMenuItem->SetText( wPriceListing );
		pMenuItem->InvalidateLayout( true, false );
	}
	
	// Market
	if ( CreateMarketPriceString( iItemDef, wPriceListing, sizeof( wPriceListing ) ) )
	{
		int nIndex = pSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "%s%s%d", "market_", pszActionFmt, iItemDef ) ), this );
		vgui::MenuItem *pMenuItem = pSubMenu->GetMenuItem( nIndex );
		pMenuItem->SetText( wPriceListing );
		pMenuItem->InvalidateLayout( true, false );
	}
	else
	{
		int nIndex = pSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "%s%s%d", "market_", pszActionFmt, iItemDef ) ), this );
		vgui::MenuItem *pMenuItem = pSubMenu->GetMenuItem( nIndex );
		pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_MarketUnavailable" ) );
		pMenuItem->InvalidateLayout( true, false );
	}

}
//-----------------------------------------------------------------------------
void CBackpackPanel::AddPaintToContextMenu( Menu *pPaintSubMenu, item_definition_index_t iPaintDef, bool bAddCommerce )
{
	GameItemDefinition_t * pPaintCanDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinition( iPaintDef ) );
	if ( !pPaintCanDef )
		return;

	wchar_t wBuff[256];
	char cBuff[256];
	V_swprintf_safe( wBuff, L"     %ls", g_pVGuiLocalize->Find( pPaintCanDef->GetItemBaseName() ) );

	char szItemName[256];
	g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pPaintCanDef->GetItemBaseName() ), szItemName, sizeof( szItemName ) );
	V_sprintf_safe( cBuff, "     %s", szItemName );

	uint32 unPaintRGB0 = 0;
	uint32 unPaintRGB1 = 0;

	static CSchemaAttributeDefHandle pAttrDef_PaintRGB( "set item tint RGB" );
	static CSchemaAttributeDefHandle pAttrDef_PaintRGB2( "set item tint RGB 2" );

	float fRGB = 0.0f;

	if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pPaintCanDef, pAttrDef_PaintRGB, &fRGB ) && fRGB != 0.0f )
	{
		unPaintRGB0 = fRGB;

		// We may or may not have a secondary paint color as well. If we don't, we just use the primary
		// paint color to fill both slots.
		if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pPaintCanDef, pAttrDef_PaintRGB2, &fRGB ) )
		{
			unPaintRGB1 = fRGB;
		}
		else
		{
			unPaintRGB1 = unPaintRGB0;
		}
	}

	if ( !bAddCommerce )
	{
		int nIndex = pPaintSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "paint%d", iPaintDef ) ), this );
		vgui::MenuItem *pMenuItem = pPaintSubMenu->GetMenuItem( nIndex );
		pMenuItem->SetText( wBuff );
		pMenuItem->InvalidateLayout( true, false );

		CItemMaterialCustomizationIconPanel *pCustomPanel = new CItemMaterialCustomizationIconPanel( pMenuItem, "paint" );
		pCustomPanel->SetZPos( -100 );
		pCustomPanel->SetTall( 30 );
		pCustomPanel->SetWide( 30 );
		pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( ( unPaintRGB0 & 0xFF0000 ) >> 16, 0, 255 ), clamp( ( unPaintRGB0 & 0xFF00 ) >> 8, 0, 255 ), clamp( ( unPaintRGB0 & 0xFF ), 0, 255 ), 255 ) );
		pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( ( unPaintRGB1 & 0xFF0000 ) >> 16, 0, 255 ), clamp( ( unPaintRGB1 & 0xFF00 ) >> 8, 0, 255 ), clamp( ( unPaintRGB1 & 0xFF ), 0, 255 ), 255 ) );
	}
	else
	{
		// 
		const char *pszContextMenuBorder = "NotificationDefault";
		const char *pszContextMenuFont = "HudFontMediumSecondary";

		Menu *pSubMenu = new Menu( this, "PaintSubMenu" );
		pSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
		pSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
		int iPos = pPaintSubMenu->AddCascadingMenuItem( cBuff, this, pSubMenu );

		CItemMaterialCustomizationIconPanel *pCustomPanel = new CItemMaterialCustomizationIconPanel( pPaintSubMenu, "paint" );
		pCustomPanel->SetZPos( 100 );
		pCustomPanel->SetPos( 0, iPos * pPaintSubMenu->GetMenuItemHeight() );
		pCustomPanel->SetTall( 30 );
		pCustomPanel->SetWide( 30 );
		pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( ( unPaintRGB0 & 0xFF0000 ) >> 16, 0, 255 ), clamp( ( unPaintRGB0 & 0xFF00 ) >> 8, 0, 255 ), clamp( ( unPaintRGB0 & 0xFF ), 0, 255 ), 255 ) );
		pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( ( unPaintRGB1 & 0xFF0000 ) >> 16, 0, 255 ), clamp( ( unPaintRGB1 & 0xFF00 ) >> 8, 0, 255 ), clamp( ( unPaintRGB1 & 0xFF ), 0, 255 ), 255 ) );

		AddCommerceSubmenus( pSubMenu, iPaintDef, "paint" );
	}
}
//
// Add commerce context options for an item.  Adds 'Store' and 'Market' options if appropriate (and Pricing) other wise just click to use
//
void CBackpackPanel::AddCommerceToContextMenu( Menu *pMenu, const char* pszActionFmt, item_definition_index_t iItemDefIndex, bool bAddMarket, bool bAddStore )
{
	GameItemDefinition_t * pItemDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinition( iItemDefIndex ) );
	if ( !pItemDef )
		return;

	//
	if ( !bAddMarket && !bAddStore )
	{
		int nIndex = pMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "%s%d", pszActionFmt, iItemDefIndex ) ), this );
		vgui::MenuItem *pMenuItem = pMenu->GetMenuItem( nIndex );
		pMenuItem->SetText( g_pVGuiLocalize->Find( pItemDef->GetItemBaseName() ) );
		pMenuItem->InvalidateLayout( true, false );
	}
	else
	{
		// 
		const char *pszContextMenuBorder = "NotificationDefault";
		const char *pszContextMenuFont = "HudFontMediumSecondary";

		Menu *pSubMenu = new Menu( this, "CommerceSubMenu" );
		pSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
		pSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
		pMenu->AddCascadingMenuItem( pItemDef->GetItemBaseName(), this, pSubMenu );

		AddCommerceSubmenus( pSubMenu, iItemDefIndex, pszActionFmt );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Opens a context menu with actions relevant for the passed in item
//-----------------------------------------------------------------------------
void CBackpackPanel::OpenContextMenu()
{
	CUtlVector<CEconItemView*> vecSelectedItems; 
	for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
	{
		if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->GetItem() )
		{
			vecSelectedItems.AddToTail( m_pItemModelPanels[i]->GetItem() );
		}
	}

	if ( m_pContextMenu )
		delete m_pContextMenu;

	m_pContextMenu = new Menu( this, "ContextMenu" );
	MenuBuilder contextMenuBuilder( m_pContextMenu, this );
	const char *pszContextMenuBorder = "NotificationDefault";
	const char *pszContextMenuFont = "HudFontMediumSecondary";
	m_pContextMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
	m_pContextMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );

	if ( vecSelectedItems.Count() == 1 )
	{
		const CEconItemView *pItem = vecSelectedItems.Head();
		const CTFItemDefinition *pItemDef = pItem->GetStaticData();
		static CSchemaItemDefHandle DuckBadgeItemDef( "Duck Badge" );
		static CSchemaItemDefHandle StrangeCountTransferItemDef( "Strange Count Transfer Tool" );

		// Tools of any kind can't be used if they are in escrow.
		static CSchemaAttributeDefHandle pAttrib_ToolEscrowUntil( "tool escrow until date" );
		uint32 unEscrowTime;
		const bool bToolIsInEscrow = pItem->FindAttribute( pAttrib_ToolEscrowUntil, &unEscrowTime )
									&& unEscrowTime > CRTime::RTime32TimeCur();
			
		const IEconTool *pEconTool = pItem->GetItemDefinition()->GetEconTool();

		const bool bIsTool = pItem->GetStaticData()->IsTool() && (pEconTool != NULL);
		const bool bIsGCConsumable = ( ( pItem->GetStaticData()->GetCapabilities() & ITEM_CAP_USABLE_GC ) != 0 );
		bool bSkipAddTrade = false;		// Hack: We should really ask the tool if the command supplants trade.

		// Tool usage goes first.  The cursor starts on this element, so double-clicks will work like how they used to.
		// Strange Count Transfer
		if ( StrangeCountTransferItemDef == pItem->GetItemDefinition() )
		{
			contextMenuBuilder.AddMenuItem( "#ApplyOnItem", new KeyValues( "Context_OpenStrangeCountTransfer" ), "primaryaction" );
		}
		else if ( pItem->GetStaticData()->IsTool() && pEconTool == NULL )
		{
			// do nothing. not a real tool (basic balloons with color that we don't want to 'remove' the paint)
		}
		else if ( (bIsTool || bIsGCConsumable) && !bToolIsInEscrow && pEconTool->CanBeUsedNow( pItem ) )
		{
			Assert( pEconTool );

			const int nTokens = pEconTool->GetUseCommandCount( pItem );
			for ( int i = 0; i < nTokens; ++i )
			{
				const char *pszToolUsageString = pEconTool->GetUseCommandLocalizationToken( pItem, i );

				// If we didn't have a custom usage string, fall back to a sane default based on whether or
				// not we're a consumable or not.
				if ( !pszToolUsageString )
				{
					pszToolUsageString = bIsGCConsumable ? "#ConsumeItem" : "#ApplyOnItem";
				}

				const char *pszContext = pEconTool->GetUseCommand( pItem, i );
				contextMenuBuilder.AddMenuItem( pszToolUsageString, new KeyValues( pszContext ), "primaryaction" );
			}

			// Hack: We should really ask the tool if the command supplants trade. For now, if we have two
			// things, then one of them is trade, so skip it.
			bSkipAddTrade = nTokens > 1;
		}
		else if ( pItem->GetItemDefinition()->GetCapabilities() & ITEM_CAP_DECODABLE )
		{
			
			static CSchemaAttributeDefHandle pAttrDef_CanShuffleCrateContents( "can shuffle crate contents" );

			if ( pItem->FindAttribute( pAttrDef_CanShuffleCrateContents ) )
			{
				contextMenuBuilder.AddMenuItem( "#ShuffleContents", new KeyValues( "Context_Shuffle" ), "primaryaction" );
			}

			if ( GetFirstCompatibleKeyForCrate( pItem ) != NULL )
			{
				contextMenuBuilder.AddMenuItem( "#UseKey", new KeyValues( "Context_OpenCrateWithKey" ), "primaryaction" );
			}
			
			if ( GetDecodedByItemDefIndex( pItem ) )
			{
				contextMenuBuilder.AddMenuItem( "#GetKey", new KeyValues( "Context_GetItemFromStore" ), "primaryaction" );
				contextMenuBuilder.AddMenuItem( "#BuyAndUseKey", new KeyValues( "Context_BuyKeyAndOpenCrate" ), "primaryaction" );
			}
		}
		else if ( pItem->GetItemDefinition()->GetCapabilities() & ITEM_CAP_HAS_SLOTS )
		{
			// check if we have at least 1 slot criteria
			static CSchemaAttributeDefHandle pAttrDef_Slot( "item slot criteria 1" );
			if ( pItem->FindAttribute( pAttrDef_Slot ) )
			{	
				contextMenuBuilder.AddMenuItem( "#EditSlots", new KeyValues( "Context_EditSlot" ), "primaryaction" );
			}
		}
		else if ( DuckBadgeItemDef == pItem->GetItemDefinition() )
		{
			contextMenuBuilder.AddMenuItem( "#Duck_ViewLeaderboards", new KeyValues( "Context_OpenDuckLeaderboards" ), "primaryaction" );

			if ( CanInventoryItemsApplyTo( pItem ) )
			{
				contextMenuBuilder.AddMenuItem( "#UseDuckToken", new KeyValues( "Context_ApplyByItem" ), "primaryaction" );
			}
			
			if ( GetDecodedByItemDefIndex( pItem ) )
			{
				contextMenuBuilder.AddMenuItem( "#GetDuckToken", new KeyValues( "Context_GetItemFromStore" ), "primaryaction" );
			}
		}

		// 3D Inspect
		float flInspect = 0;
		static CSchemaAttributeDefHandle pAttrib_WeaponAllowInspect( "weapon_allow_inspect" );
		static CSchemaAttributeDefHandle pAttrib_CosmeticAllowInspect( "cosmetic_allow_inspect" );
		if ( pItem && pItem->IsValid() &&
			( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttrib_WeaponAllowInspect, &flInspect ) || FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttrib_CosmeticAllowInspect, &flInspect ) 
#ifdef STAGING_ONLY
			|| tf_weapon_force_allow_inspect.GetBool()
#endif
			) )
		{
			if ( flInspect != 0
#ifdef STAGING_ONLY
				|| tf_weapon_force_allow_inspect.GetBool() 
#endif
				)
			{
				contextMenuBuilder.AddMenuItem( "#Context_InspectModel", new KeyValues( "Context_InspectModel" ), "primaryaction" );
			}
		}

		// Add equip sub menu
		{
			Menu *pEquipSubMenu = NULL;
			for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; iClass++ )
			{
				if ( !pItemDef->CanBeUsedByClass( iClass ) )
					continue;
			
				if ( pEquipSubMenu == NULL )
				{
					pEquipSubMenu = new Menu( this, "EquipMenu" );
					pEquipSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
					pEquipSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );

					contextMenuBuilder.AddCascadingMenuItem( "#Context_Equip", pEquipSubMenu, "primaryaction" );
				}

				const char *pszClassName = NULL;
				switch ( iClass )
				{
					case TF_CLASS_SCOUT: 			pszClassName = "#TF_Class_Name_Scout"; break;
					case TF_CLASS_SNIPER: 			pszClassName = "#TF_Class_Name_Sniper"; break;
					case TF_CLASS_SOLDIER: 			pszClassName = "#TF_Class_Name_Soldier"; break;
					case TF_CLASS_DEMOMAN: 			pszClassName = "#TF_Class_Name_Demoman"; break;
					case TF_CLASS_MEDIC: 			pszClassName = "#TF_Class_Name_Medic"; break;
					case TF_CLASS_HEAVYWEAPONS: 	pszClassName = "#TF_Class_Name_HWGuy"; break;
					case TF_CLASS_PYRO: 			pszClassName = "#TF_Class_Name_Pyro"; break;
					case TF_CLASS_SPY: 				pszClassName = "#TF_Class_Name_Spy"; break;
					case TF_CLASS_ENGINEER: 		pszClassName = "#TF_Class_Name_Engineer"; break;
				}
			
				pEquipSubMenu->AddMenuItem( pszClassName, new KeyValues( "Command", "command", CFmtStr( "equipclass%d", iClass ) ), this );
			}
		}
		
		// For customizable items only
		if ( !pItem->IsTemporaryItem() )
		{
			bool bCanCraftUp = GetCollectionCraftingInvalidReason(pItem, NULL) == NULL;
			bool bCanStatClockTrade = GetCraftCommonStatClockInvalidReason(pItem, NULL) == NULL;
			Menu *pMannCoTradeSubMenu = NULL;

			if ( bCanCraftUp || bCanStatClockTrade )
			{
				pMannCoTradeSubMenu = new Menu(this, "MannCoTradeSubMenu");
				pMannCoTradeSubMenu->SetBorder(scheme()->GetIScheme(GetScheme())->GetBorder(pszContextMenuBorder));
				pMannCoTradeSubMenu->SetFont(scheme()->GetIScheme(GetScheme())->GetFont(pszContextMenuFont));
				contextMenuBuilder.AddCascadingMenuItem("#Context_MannCoTrade", pMannCoTradeSubMenu, "customization");

				if ( bCanCraftUp )
				{
					int nIndex = pMannCoTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftUpCollection"), this);
					vgui::MenuItem *pMenuItem = pMannCoTradeSubMenu->GetMenuItem(nIndex);
					pMenuItem->SetText("#Context_TradeUp");
					pMenuItem->InvalidateLayout(true, false);
				}

				if ( bCanStatClockTrade )
				{
					int nIndex = pMannCoTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftCommonStatClock"), this);
					vgui::MenuItem *pMenuItem = pMannCoTradeSubMenu->GetMenuItem(nIndex);
					pMenuItem->SetText("#Context_CommonStatClock");
					pMenuItem->InvalidateLayout(true, false);
				}
			}



			// Campaign coin access trades
			static CSchemaAttributeDefHandle pAttrDef_IsOperationPass( "is_operation_pass" );
			if ( pItem->FindAttribute( pAttrDef_IsOperationPass ) )
			{
				Menu *pMannCoCoinTradeSubMenu = new Menu( this, "MannCoTradeSubMenu" );
				pMannCoCoinTradeSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
				pMannCoCoinTradeSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
				contextMenuBuilder.AddCascadingMenuItem( "#Context_MannCoTrade", pMannCoCoinTradeSubMenu, "customization" );

				int nIndex = pMannCoCoinTradeSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "Context_CraftUpCollection" ), this );
				vgui::MenuItem *pMenuItem = pMannCoCoinTradeSubMenu->GetMenuItem( nIndex );
				pMenuItem->SetText( "#Context_TradeUp" );
				pMenuItem->InvalidateLayout( true, false );

				nIndex = pMannCoCoinTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftCommonStatClock"), this);
				pMenuItem = pMannCoCoinTradeSubMenu->GetMenuItem(nIndex);
				pMenuItem->SetText("#Context_CommonStatClock");
				pMenuItem->InvalidateLayout(true, false);
			}

			// Halloween trade up offering.
			// Needs two attrs
			static CSchemaAttributeDefHandle pAttrDef_HalloweenOffering( "allow_halloween_offering" );
			static CSchemaAttributeDefHandle pAttrDef_DeactiveDate( "deactive date" );

			// Check the date
			uint32 unDeactiveDate = 0;
			uint32 unCurrentDate = CRTime::RTime32TimeCur();
			if ( pAttrDef_HalloweenOffering && pItem->FindAttribute( pAttrDef_HalloweenOffering ) && pItem->FindAttribute( pAttrDef_DeactiveDate, &unDeactiveDate ) && unDeactiveDate > unCurrentDate )
			{
				vgui::MenuItem *pMenuItem = contextMenuBuilder.AddMenuItem( "#Context_HalloweenOffering", new KeyValues( "Context_HalloweenOffering" ), "customization" );

				ImagePanel *pNewImage = new ImagePanel( pMenuItem, "new" );
				pNewImage->SetZPos( 100 );
				pNewImage->SetWide( 40 );
				pNewImage->SetTall( 40 );
				pNewImage->SetPos( 220, -5 );
				pNewImage->SetMouseInputEnabled( false );
				pNewImage->SetShouldScaleImage( true );
				pNewImage->SetImage( "new" );
			}

			// Change name
			GameItemDefinition_t * pNameTagDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinitionByName( "Name Tag" ) );
			if ( CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast<const GameItemDefinition_t *>( pNameTagDef ), pItemDef ) )
			{
				contextMenuBuilder.AddMenuItem( "#Context_Rename", new KeyValues( "DoRename" ), "customization" );
			}

			// Change description
			GameItemDefinition_t * pDescTagDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinitionByName( "Description Tag" ) );
			if ( CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast<const GameItemDefinition_t *>( pDescTagDef ), pItemDef ) )
			{
				contextMenuBuilder.AddMenuItem( "#Context_Description", new KeyValues( "DoDescription" ), "customization" );
			}

			// Add paint options sub menu
			if ( m_vecPaintCans.Count() > 0 )
			{
				GameItemDefinition_t * pPaintCanDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinition( m_vecPaintCans[0] ) );
				if ( pPaintCanDef && CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast<const GameItemDefinition_t *>( pPaintCanDef ), pItemDef ) )
				{
					Menu *pPaintSubMenu = NULL;
					pPaintSubMenu = new Menu( this, "PaintSubMenu" );
					pPaintSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
					pPaintSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
					contextMenuBuilder.AddCascadingMenuItem( "#Context_Paint", pPaintSubMenu, "customization" );

					CUtlVector<item_definition_index_t> vecOwnedPaints;
					CUtlVector<item_definition_index_t> vecStorePaints;

					// Find out if the user owns this item or not and place in the proper bucket
					CPlayerInventory *pLocalInv = TFInventoryManager()->GetLocalInventory();

					FOR_EACH_VEC( m_vecPaintCans, i )
					{	
						if ( pLocalInv && pLocalInv->FindFirstItembyItemDef( m_vecPaintCans[i] ) )
						{
							vecOwnedPaints.AddToTail( m_vecPaintCans[i] );
						}
						else
						{
							vecStorePaints.AddToTail( m_vecPaintCans[i] );
						}
					}

					if ( vecOwnedPaints.Count() > 0 )
					{
						// Add Header and loop
						int nIndex = pPaintSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "" ), this );
						vgui::MenuItem *pMenuItem = pPaintSubMenu->GetMenuItem( nIndex );
						pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_Owned" ) );
						pMenuItem->InvalidateLayout( true, false );

						FOR_EACH_VEC( vecOwnedPaints, i )
						{
							AddPaintToContextMenu( pPaintSubMenu, vecOwnedPaints[i], false );
						}
					}

					pPaintSubMenu->AddSeparator();
					if ( vecStorePaints.Count() > 0 )
					{
						// Add Header and loop
						int nIndex = pPaintSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "" ), this );
						vgui::MenuItem *pMenuItem = pPaintSubMenu->GetMenuItem( nIndex );
						pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_Commerce" ) );
						pMenuItem->InvalidateLayout( true, false );

						FOR_EACH_VEC( vecStorePaints, i )
						{
							AddPaintToContextMenu( pPaintSubMenu, vecStorePaints[i], true );
						}
					}
				}
			}

			// Strange Parts
			if ( BIsItemStrange( pItem ) )
			{
				Menu *pStrangePartsSubMenu = NULL;
				CUtlVector<item_definition_index_t> vecOwnedParts;
				CUtlVector<item_definition_index_t> vecStoreParts;

				// Find out if the user owns this item or not and place in the proper bucket
				CPlayerInventory *pLocalInv = TFInventoryManager()->GetLocalInventory();
				FOR_EACH_VEC( m_vecStrangeParts, i )
				{
					// Determine if this can be applied
					//GameItemDefinition_t *pStrangePartDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinition( m_vecStrangeParts[i] ) );
					CEconItemView partItemView;
					partItemView.Init( m_vecStrangeParts[i], AE_USE_SCRIPT_VALUE, 1 );
					if ( CEconSharedToolSupport::ToolCanApplyTo( &partItemView, pItem ) )
					{
						// Create menu
						if ( !pStrangePartsSubMenu )
						{
							pStrangePartsSubMenu = new Menu( this, "StrangePartsSubMenu" );
							pStrangePartsSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
							pStrangePartsSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
							contextMenuBuilder.AddCascadingMenuItem( "#Context_StrangeParts", pStrangePartsSubMenu, "customization" );
						}

						if ( pLocalInv && pLocalInv->FindFirstItembyItemDef( m_vecStrangeParts[i] ) )
						{
							vecOwnedParts.AddToTail( m_vecStrangeParts[i] );
						}
						else
						{
							vecStoreParts.AddToTail( m_vecStrangeParts[i] );
						}
					}
				}

				if ( pStrangePartsSubMenu )
				{
					if ( vecOwnedParts.Count() > 0 )
					{
						// Add Header and loop
						int nIndex = pStrangePartsSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "" ), this );
						vgui::MenuItem *pMenuItem = pStrangePartsSubMenu->GetMenuItem( nIndex );
						pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_Owned" ) );
						pMenuItem->InvalidateLayout( true, false );

						FOR_EACH_VEC( vecOwnedParts, i )
						{
							AddCommerceToContextMenu( pStrangePartsSubMenu, "strangepart_", vecOwnedParts[i], false, false );
						}
					}

					pStrangePartsSubMenu->AddSeparator();
					if ( vecStoreParts.Count() > 0 )
					{
						// Add Header and loop 
						int nIndex = pStrangePartsSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "" ), this );
						vgui::MenuItem *pMenuItem = pStrangePartsSubMenu->GetMenuItem( nIndex );
						pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_Market" ) );
						pMenuItem->InvalidateLayout( true, false );

						FOR_EACH_VEC( vecStoreParts, i )
						{
							AddCommerceToContextMenu( pStrangePartsSubMenu, "strangepart_", vecStoreParts[i], true, false );
						}
					}
				}
			}

			if ( pItem->IsMarketable() )
			{
				contextMenuBuilder.AddMenuItem( "#Context_MarketPlaceSell", new KeyValues( "DoSellMarketplace" ), "economy" );
			}

			// Trade to another player
			if ( pItem->IsTradable() && !bSkipAddTrade )
			{
				contextMenuBuilder.AddMenuItem( "#Context_Trade", new KeyValues( "DoTradeToPlayer" ), "economy" );
			}

			if ( pItem->GetItemDefinition()->GetCapabilities() & ITEM_CAP_CAN_BE_RESTORED )
			{
				if ( RemovableAttributes_DoAnyAttributesApply( pItem ) )
				{
					contextMenuBuilder.AddMenuItem( "#RefurbishItem", new KeyValues( "Context_RefurbishItem" ), "destructive" );
				}
			}
		}
	}
	else
	{
		// Check if ALL selected items can be crafted together
		bool bCanCraftUp = true;
		for( int i=0; i < COLLECTION_CRAFTING_ITEM_COUNT && i < vecSelectedItems.Count(); ++i )
		{
			CEconItemView* pPrevItem = ( i - 1 ) < 0 ? NULL : vecSelectedItems[ i - 1 ];
			bCanCraftUp &= GetCollectionCraftingInvalidReason( vecSelectedItems[ i ], pPrevItem ) == NULL;
		}

		bool bCanStatClockTrade = true;
		for (int i = 0; i < COLLECTION_CRAFTING_ITEM_COUNT && i < vecSelectedItems.Count(); ++i)
		{
			CEconItemView* pPrevItem = (i - 1) < 0 ? NULL : vecSelectedItems[i - 1];
			bCanStatClockTrade &= GetCraftCommonStatClockInvalidReason(vecSelectedItems[i], pPrevItem) == NULL;
		}

		Menu *pMannCoTradeSubMenu = NULL;

		if ( bCanCraftUp || bCanStatClockTrade )
		{
			pMannCoTradeSubMenu = new Menu(this, "MannCoTradeSubMenu");
			pMannCoTradeSubMenu->SetBorder(scheme()->GetIScheme(GetScheme())->GetBorder(pszContextMenuBorder));
			pMannCoTradeSubMenu->SetFont(scheme()->GetIScheme(GetScheme())->GetFont(pszContextMenuFont));
			contextMenuBuilder.AddCascadingMenuItem("#Context_MannCoTrade", pMannCoTradeSubMenu, "customization");

			if (bCanCraftUp)
			{
				int nIndex = pMannCoTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftUpCollection"), this);
				vgui::MenuItem *pMenuItem = pMannCoTradeSubMenu->GetMenuItem(nIndex);
				pMenuItem->SetText("#Context_TradeUp");
				pMenuItem->InvalidateLayout(true, false);
			}

			if (bCanStatClockTrade)
			{
				int nIndex = pMannCoTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftCommonStatClock"), this);
				vgui::MenuItem *pMenuItem = pMannCoTradeSubMenu->GetMenuItem(nIndex);
				pMenuItem->SetText("#Context_CommonStatClock");
				pMenuItem->InvalidateLayout(true, false);
			}
		}
	}

	if ( !m_bShowBaseItems )
	{
		bool bDeleteAvailable = true;
		// Check that all of the selected items are deletable
		for( int i=0; i < vecSelectedItems.Count() && bDeleteAvailable; ++i )
		{
			static CSchemaAttributeDefHandle pAttrDef_NoDelete( "cannot delete" );
			bDeleteAvailable &= !vecSelectedItems[i]->FindAttribute( pAttrDef_NoDelete );
		}

		// Only show the delete button if every slected item is deletable
		if ( bDeleteAvailable )
		{
			contextMenuBuilder.AddMenuItem( "#TF_SteamWorkshop_Delete", new KeyValues( "DoDelete" ), "destructive" );
		}
	}

	// Position to the cursor's position
	int nX, nY;
	g_pVGuiInput->GetCursorPosition( nX, nY );
	m_pContextMenu->SetPos( nX - 1, nY - 1 );
	
	m_pContextMenu->SetVisible(true);
	m_pContextMenu->AddActionSignalTarget(this);
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnItemPanelMouseRightRelease( vgui::Panel *panel )
{
#ifdef STAGING_ONLY
	if ( tf_use_card_tooltips.GetBool() )
	{
		m_pMouseOverCardPanel->PinCard( true );
	}
	else
#endif
	{
		CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );
		if ( pItemPanel && pItemPanel->IsVisible() )
		{
			// If they're not holding down ctrl, deselect all existing selections
			if ( !vgui::input()->IsKeyDown(KEY_LCONTROL) && !vgui::input()->IsKeyDown(KEY_RCONTROL) )
			{
				DeSelectAllBackpackItemPanels();
				ToggleSelectBackpackItemPanel( pItemPanel );
			}
			else if ( AllowSelection() && !pItemPanel->IsGreyedOut() )
			{
				if ( !pItemPanel->IsSelected() && pItemPanel->HasItem() )
				{
					pItemPanel->SetSelected( true );
				}
				SetBorderForItem( pItemPanel, false );
			}

			OpenContextMenu();
		}
	}
}

void CBackpackPanel::OnMouseMismatchedRelease( MouseCode code, Panel* pPressedPanel )
{
	if ( pPressedPanel )
	{
		OnMouseReleased( code );
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::StartDrag( int x, int y )
{
	// don't allow item drag if there's a filter
	if ( HasNameFilter() )
		return;

	m_bDragging = true;
	HideMouseOverPanel();

	vgui::ivgui()->AddTickSignal( GetVPanel() );

	m_pMouseDragItemPanel->SetItem( m_pItemDraggedFromPanel->GetItem() );
	m_pMouseDragItemPanel->InvalidateLayout( true );

	m_pItemDraggedFromPanel->Dragged( true );

	// Calculate the mouse offset from the top left of the panel we're going to drag
	m_iDragOffsetX = m_pMouseDragItemPanel->GetWide() * 0.5f;
	m_iDragOffsetY = m_pMouseDragItemPanel->GetTall() * 0.5f;
	m_flPreventDragPageSwitchUntil = 0;

	m_pMouseDragItemPanel->SetVisible( true );

	m_pItemDraggedFromPanel->SetItem( NULL );
	SetBorderForItem( m_pItemDraggedFromPanel, false );
	m_pPrevDragOverItemPanel = NULL;

	vgui::input()->SetMouseCapture( GetVPanel() );

	if ( m_pDragToNextPageButton && m_pDragToPrevPageButton )
	{
		m_pDragToNextPageButton->SetVisible( GetNumPages() > 1 );
		m_pDragToPrevPageButton->SetVisible( GetNumPages() > 1 );
	}

	// play pickup sound
	CEconItemView *item = m_pMouseDragItemPanel->GetItem();
	if ( item )
	{
		const char *soundFilename = item->GetDefinitionString( "pickup_sound", "" );
		if ( soundFilename[0] )
		{
			vgui::surface()->PlaySound( soundFilename );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::StopDrag( bool bSucceeded )
{
	if ( !m_pItemDraggedFromPanel )
		return;

	if ( !bSucceeded )
	{
		if ( m_iDraggedFromPage == GetCurrentPage() )
		{
			m_pItemDraggedFromPanel->SetItem( m_pMouseDragItemPanel->GetItem() );
		}
		m_pItemDraggedFromPanel = NULL;
	}

	m_pMouseDragItemPanel->SetVisible( false );
	m_bDragging = false;

	vgui::input()->SetMouseCapture( NULL );

	if ( m_pDragToNextPageButton && m_pDragToPrevPageButton )
	{
		m_pDragToNextPageButton->SetVisible( false );
		m_pDragToPrevPageButton->SetVisible( false );
	}

	// play drop sound
	CEconItemView *item = m_pMouseDragItemPanel->GetItem();
	if ( item )
	{
		const char *soundFilename = item->GetDefinitionString( "drop_sound", "ui/item_default_drop.wav" );
		vgui::surface()->PlaySound( soundFilename );
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBackpackPanel::GetBackpackPositionForPanel( CItemModelPanel *pItemPanel )
{
	for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
	{
		if ( m_pItemModelPanels[i] == pItemPanel  )
			return i;
	}
	return -1;
}



//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::HandleDragTo( CItemModelPanel *pItemPanel, int iPanelIndex )
{
	// Find the position based on the panel we're dragging to
	if ( iPanelIndex != -1 )
	{
		// If the current panel is selected, unselect it
		if ( m_pItemModelPanels[iPanelIndex]->IsSelected() )
		{
			ToggleSelectBackpackItemPanel( m_pItemModelPanels[iPanelIndex] );
		}
		if ( m_pItemDraggedFromPanel->IsSelected() )
		{
			ToggleSelectBackpackItemPanel( m_pItemDraggedFromPanel );
		}

		// We "move" the items in the backpack immediately, because when the messages come back 
		// from steam they'll fix the positions if the move fails for some reason.
		CEconItemView *pItem = NULL;
		if ( m_pItemModelPanels[iPanelIndex]->HasItem() )
		{
			// We need to copy it because it's about to get stomped by the other item
			pItem = new CEconItemView( *m_pItemModelPanels[iPanelIndex]->GetItem() );
		}
		m_pItemModelPanels[iPanelIndex]->SetItem( m_pMouseDragItemPanel->GetItem() );

		if ( m_iDraggedFromPage == GetCurrentPage() )
		{
			m_pItemDraggedFromPanel->SetItem( pItem );
		}

		if ( pItem )
		{
			delete pItem;
		}

		// Tell the inventory to move the item
		// Translate it to the right page
		int iBackpackPosition = GetBackpackPosForPanelIndex( iPanelIndex );
		InventoryManager()->MoveItemToBackpackPosition( m_pMouseDragItemPanel->GetItem(), iBackpackPosition );
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::OnTick( void )
{
	BaseClass::OnTick();

	bool bNeedsTick = false;
	if ( m_flStartExplanationsAt && m_flStartExplanationsAt < Plat_FloatTime() )
	{
		m_flStartExplanationsAt = 0;

		if ( ShouldShowExplanations() )
		{
			ConVar *pConVar = GetExplanationConVar();
			if ( pConVar )
			{
				pConVar->SetValue( 1 );
			}

			CExplanationPopup *pPopup = dynamic_cast<CExplanationPopup*>( FindChildByName("StartExplanation") );
			if ( pPopup )
			{
				pPopup->Popup();
			}
		}
	}
	else
	{
		bNeedsTick = true;
	}

	// To handle page movement while holding the mouse still over the page buttons, 
	// we need to keep calling OnCursorMoved() whenever we're dragging.
	if ( m_bDragging && m_pMouseDragItemPanel && m_pItemDraggedFromPanel && IsVisible() )
	{
		int mx,my;
		vgui::input()->GetCursorPos( mx, my );
		ScreenToLocal( mx, my );
		OnCursorMoved( mx,my );

		bNeedsTick = true;
	}

	if ( !bNeedsTick && !NeedsDerivedTickSignal() )
	{
		vgui::ivgui()->RemoveTickSignal( GetVPanel() );
	}

}


//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::OnThink( void )
{
	BaseClass::OnThink();

	if ( m_flFilterItemTime > 0 && gpGlobals->curtime >= m_flFilterItemTime )
	{
		SetCurrentPage( 0 );
		DeSelectAllBackpackItemPanels();
		UpdateModelPanels();

		m_flFilterItemTime = 0.0f;
	}
}


//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::OnCursorMoved( int x, int y )
{
	if ( !m_pItemDraggedFromPanel )
		return;

	if ( m_bDragging && m_pMouseDragItemPanel )
	{
		m_pMouseDragItemPanel->SetPos( x - m_iDragOffsetX, y - m_iDragOffsetY );

		// When we're dragging, we have mouse capture, so the item panels aren't getting mouse input.
		// We need to find out what item panel we're over, and let it know.

		if ( m_flPreventDragPageSwitchUntil < Plat_FloatTime() )
		{
			// First, are we over the page turning areas?
			bool bDragNext = false;
			if ( m_pDragToNextPageButton && m_pDragToNextPageButton->IsVisible() )
			{
				int iDragX, iDragY;
				m_pDragToNextPageButton->GetPos( iDragX, iDragY );
				bDragNext = ( x >= iDragX && x <= (iDragX + m_pDragToNextPageButton->GetWide() ) );
			}
			if ( !bDragNext && m_pNextPageButton && m_pNextPageButton->IsEnabled() )
			{
				int iDragX, iDragY;
				m_pNextPageButton->GetPos( iDragX, iDragY );
				bDragNext = ( x >= iDragX && x <= (iDragX + m_pNextPageButton->GetWide()) && y >= iDragY && y <= (iDragY + m_pNextPageButton->GetTall()) );
			}
			if ( bDragNext )
			{
				OnCommand( "nextpage" );
				m_flPreventDragPageSwitchUntil = Plat_FloatTime() + tf_backpack_page_button_delay.GetFloat();
				return;
			}

			bool bDragPrev = false;
			if ( m_pDragToPrevPageButton && m_pDragToPrevPageButton->IsVisible() )
			{
				int iDragX, iDragY;
				m_pDragToPrevPageButton->GetPos( iDragX, iDragY );
				bDragPrev = ( x >= iDragX && x <= (iDragX + m_pDragToPrevPageButton->GetWide() ) );
			}
			if ( !bDragPrev && m_pPrevPageButton && m_pPrevPageButton->IsEnabled() )
			{
				int iDragX, iDragY;
				m_pPrevPageButton->GetPos( iDragX, iDragY );
				bDragPrev = ( x >= iDragX && x <= (iDragX + m_pPrevPageButton->GetWide()) && y >= iDragY && y <= (iDragY + m_pPrevPageButton->GetTall()) );
			}
			if ( bDragPrev )
			{
				OnCommand( "prevpage" );
				m_flPreventDragPageSwitchUntil = Plat_FloatTime() + tf_backpack_page_button_delay.GetFloat();
				return;
			}
		}

		// check if we're hovering page button
		static int iPrevHoveringPage = -1;
		static float flLastPageButtonEnterTime = 0.f;
		int iHoveringPage = GetPageButtonIndexAtPos( x, y );
		if ( iHoveringPage != -1 )
		{
			if ( iHoveringPage == GetCurrentPage() )
			{
				iPrevHoveringPage = -1;
				flLastPageButtonEnterTime = 0.f;
			}
			else if ( iPrevHoveringPage != iHoveringPage )
			{
				iPrevHoveringPage = iHoveringPage;
				flLastPageButtonEnterTime = Plat_FloatTime() + tf_backpack_page_button_delay.GetFloat();
			}
			else if ( flLastPageButtonEnterTime > 0 && flLastPageButtonEnterTime < Plat_FloatTime() )
			{
				flLastPageButtonEnterTime = 0.f;
				SetCurrentPage( iHoveringPage );
				UpdateModelPanels();
			}
			return;
		}
		else
		{
			// reset hovering page buttons data
			iPrevHoveringPage = -1;
			flLastPageButtonEnterTime = 0.f;
		}

		CItemModelPanel *pOverPanel = GetItemPanelAtPos( x, y );
		if ( m_pPrevDragOverItemPanel != pOverPanel )
		{
			if ( m_pPrevDragOverItemPanel )
			{
				OnItemPanelExited( m_pPrevDragOverItemPanel );
			}

			m_pPrevDragOverItemPanel = pOverPanel;

			if ( m_pPrevDragOverItemPanel )
			{
				OnItemPanelEntered( m_pPrevDragOverItemPanel );
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBackpackPanel::OnItemPanelCursorMoved( int x, int y )
{
	if ( !m_pItemDraggedFromPanel )
		return;

	if ( !m_bDragging && m_pItemDraggedFromPanel->HasItem() && !InToolSelectionMode() )
	{
		// Don't drag instantly, so it's easy to select
		if ( (gpGlobals->curtime - m_flMouseDownTime) > 0.3 )
		{
			StartDrag( x,y );
		}
		else
		{
			if ( !m_iMouseDownX )
			{
				m_iMouseDownX = x;
				m_iMouseDownY = y;
			}
			else if ( abs(m_iMouseDownX - x) > XRES(10) || abs(m_iMouseDownY - y) > YRES(10) )
			{
				StartDrag( x,y );
			}
		}
	}

	OnCursorMoved( x, y );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::ToggleSelectBackpackItemPanel( CItemModelPanel *pPanel )
{
	if ( !AllowSelection() || pPanel->IsGreyedOut() )
		return;

	if ( pPanel->IsSelected() || !pPanel->HasItem() )
	{
		pPanel->SetSelected( false );
	}
	else
	{
		pPanel->SetSelected( true );
	}
	SetBorderForItem( pPanel, false );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::DeSelectAllBackpackItemPanels( void )
{
	for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
	{
		if ( m_pItemModelPanels[i]->IsSelected() )
		{
			m_pItemModelPanels[i]->SetSelected( false );
			SetBorderForItem( m_pItemModelPanels[i], false );
		}
	}
}


//-----------------------------------------------------------------------------
// Purpose: Called whenever the selection changes in the item loadout panel
//-----------------------------------------------------------------------------
void CBackpackPanel::OnItemContentsChanged( CEconItemView *pEconItemView )
{
	Assert( pEconItemView );

	for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
	{
		CEconItemView *pInternalItem = m_pItemModelPanels[i] && m_pItemModelPanels[i]->HasItem()
									 ? m_pItemModelPanels[i]->GetItem()
									 : NULL;

		if ( *pInternalItem == *pEconItemView )
		{
			m_pItemModelPanels[i]->DirtyDescription();
			OnItemSelectionChanged();
			return;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Called when text changes in combo box
//-----------------------------------------------------------------------------
void CBackpackPanel::OnTextChanged( KeyValues *data )
{
	Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );

	vgui::TextEntry *pTextEntry = dynamic_cast<vgui::TextEntry *>( pPanel );
	if ( pTextEntry )
	{
		if ( pTextEntry == m_pNameFilterTextEntry )
		{
			m_wNameFilter.RemoveAll();
			if ( m_pNameFilterTextEntry->GetTextLength() )
			{
				m_wNameFilter.EnsureCount( m_pNameFilterTextEntry->GetTextLength() + 1 );
				m_pNameFilterTextEntry->GetText( m_wNameFilter.Base(), m_wNameFilter.Count() * sizeof(wchar_t) );
				V_wcslower( m_wNameFilter.Base() );
			}
			m_flFilterItemTime = gpGlobals->curtime + 0.5f;
			return;
		}
	}

	vgui::ComboBox *pComboBox = dynamic_cast<vgui::ComboBox *>( pPanel );
	if ( pComboBox )
	{
		if ( pComboBox == m_pSortByComboBox )
		{
			// the class selection combo box changed, update class details
			KeyValues *pUserData = m_pSortByComboBox->GetActiveItemUserData();
			if ( !pUserData )
				return;

			enum { kSortType_Dummy = -1 };
			int iSortTypeSelectionIndex = pUserData->GetInt( "sortby", kSortType_Dummy );
			if ( iSortTypeSelectionIndex != kSortType_Dummy )
			{
				uint32 iSortType = g_BackpackSortTypes[iSortTypeSelectionIndex].iSortType;
				if ( iSortType != kGCItemSort_NoSort )
				{
					InventoryManager()->SortBackpackBy( iSortType );

					// Now go back to the "Sort by" header, and move the focus to the close button.
					m_pSortByComboBox->ActivateItemByRow( 0 );
				}
			}
		}
		else if ( pComboBox == m_pShowRarityComboBox )
		{
			cl_showbackpackrarities.SetValue( m_pShowRarityComboBox->GetActiveItem() );

			// Refresh all item borders
			for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
			{
				SetBorderForItem( m_pItemModelPanels[i], false );
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnButtonChecked( KeyValues *pData )
{
	Panel *pPanel = reinterpret_cast<vgui::Panel *>( pData->GetPtr("panel") );
	
	if ( m_bShowBaseItems != m_pShowBaseItemsCheckbox->IsSelected() && m_pShowBaseItemsCheckbox == pPanel && IsVisible() )
	{
		SetShowBaseItems( m_pShowBaseItemsCheckbox->IsSelected() );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnCancelSelection( void )
{
	if ( m_pConfirmDeleteDialog )
	{
		m_pConfirmDeleteDialog->MarkForDeletion();
		m_pConfirmDeleteDialog = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CBackpackPanel::GetGreyOutItemPanelReason( CItemModelPanel *pItemPanel )
{
	if ( InToolSelectionMode() )
	{
		bool bIsSelectedTool = (m_ToolSelectionItem.IsValid() && pItemPanel->HasItem()) ? (m_ToolSelectionItem == *pItemPanel->GetItem()) : false;
		if ( !bIsSelectedTool )
		{
			if ( m_ToolSelectionItem.GetStaticData()->IsTool() )
			{
				if ( !CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, pItemPanel->GetItem() ) )
				{
					return "#Econ_GreyOutReason_ToolCannotApply";
				}
			}
			else if ( pItemPanel->GetItem() && pItemPanel->GetItem()->GetStaticData()->IsTool() )
			{
				if ( !CEconSharedToolSupport::ToolCanApplyTo( pItemPanel->GetItem(), &m_ToolSelectionItem ) )
				{
					return "#Econ_GreyOutReason_ToolCannotApply";
				}
			}
		}
	}

	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::SetBorderForItem( CItemModelPanel *pItemPanel, bool bMouseOver )
{
	tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );

	if ( !pItemPanel )
		return;

	const char *pszBorder = NULL;

	bool bIsSelectedTool = (m_ToolSelectionItem.IsValid() && pItemPanel->HasItem()) ? (m_ToolSelectionItem == *pItemPanel->GetItem()) : false;

	// Handle grey out
	const char *pszGreyOutReason = GetGreyOutItemPanelReason( pItemPanel );
	const bool bGreyOut = pszGreyOutReason != NULL;

	pItemPanel->SetGreyedOut( pszGreyOutReason );

	int iRarity = GetItemQualityForBorder( pItemPanel );

	if ( InToolSelectionMode() && bIsSelectedTool )
	{
		// We're in tool application mode, and this panel is the tool being used
		pszBorder = "BackpackItemBorder_SelfMade";

		if ( m_pToolIcon )
		{
			int iX, iY;
			pItemPanel->GetPos( iX, iY );
			m_pToolIcon->SetPos( iX, iY );
			m_pToolIcon->SetVisible( true );
		}
	}
	else if ( bGreyOut )
	{
		if( pItemPanel->IsSelected() )
		{
			pszBorder = g_szItemBorders[iRarity][4];
		}
		else
		{
			pszBorder = g_szItemBorders[iRarity][3];
		}
	}
	else
	{
		
		if ( pItemPanel->IsSelected() )
		{
			pszBorder = g_szItemBorders[iRarity][2];
		}
		else if ( bMouseOver )
		{
			pszBorder = g_szItemBorders[iRarity][1];
		}
		else
		{
			pszBorder = g_szItemBorders[iRarity][0];
		}
	}

	vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );	
	pItemPanel->SetBorder( pScheme->GetBorder( pszBorder ) );
}

//-----------------------------------------------------------------------------
class CTFRemoveItemCustomizationConfirmDialog : public CTFGenericConfirmDialog
{
	DECLARE_CLASS_SIMPLE( CTFRemoveItemCustomizationConfirmDialog, CTFGenericConfirmDialog );
public:
	CTFRemoveItemCustomizationConfirmDialog( const RefurbishableProperty& prop, CEconItemView *pItem )
		: CTFGenericConfirmDialog( prop.m_szDialogTitle,	// dialog title
								   prop.m_szDialogDesc,		// dialog text
								   "#RefurbishItem_Yes",	// confirm button text
								   "#RefurbishItem_No",		// cancel button text
								   NULL,					// callback
								   NULL )					// parent
		, m_prop( prop )
		, m_Item( *pItem )									// copy in case our UI changes behind us
	{
		GetCustomDialogLocalizationTokenFunc_t m_pDialogCustomTokenFunc = m_prop.m_pGetCustomDialogLocalizationTokenFunc;
		if ( m_pDialogCustomTokenFunc )
		{
			CUtlConstWideString wsDialogCustomToken;
			(*m_pDialogCustomTokenFunc)( &m_Item, m_prop.m_iUserData, wsDialogCustomToken );
			if ( !wsDialogCustomToken.IsEmpty() )
			{
				AddStringToken( "confirm_dialog_token", wsDialogCustomToken.Get() );
			}
		}
	}

	virtual ~CTFRemoveItemCustomizationConfirmDialog() { }

	virtual void OnCommand( const char *command );

private:
	RefurbishableProperty m_prop;
	CEconItemView m_Item;
};

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void SendGCSimpleAttributeRemovalMessage( CEconItemView *pEconItemView, const char *szDesc, EGCItemMsg eItemMsg )
{
	EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, pEconItemView, szDesc );
	GCSDK::CProtoBufMsg<CMsgGCRemoveCustomizationAttributeSimple> msg( eItemMsg );
	msg.Body().set_item_id( pEconItemView->GetItemID() );
	GCClientSystem()->BSendMessage( msg );
}

void CTFRemoveItemCustomizationConfirmDialog::OnCommand( const char *command )
{
	BaseClass::OnCommand( command );

	// Did the user say "yes, remove this particular attribute"? If so, notify the GC. We can't
	// remove multiple attributes at a time because each removal will cause a new item to be created,
	// invalidating the item reference we've got in this dialog.
	if ( !Q_strnicmp( command, "confirm", 7 ) )
	{
		// remove the attribute
		switch( m_prop.m_eRemovalType )
		{
			case kCustomizationRemove_Paint:
				SendGCSimpleAttributeRemovalMessage( &m_Item, "paint", k_EMsgGCRemoveItemPaint );
				break;

			case kCustomizationRemove_Name:
			{
				EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, &m_Item, "name" );
				GCSDK::CGCMsg< MsgGCRemoveItemName_t > msg( k_EMsgGCRemoveItemName );
				msg.Body().m_unItemID = m_Item.GetItemID();
				msg.Body().m_bDescription = false;
				GCClientSystem()->BSendMessage( msg );
			}
			break;

			case kCustomizationRemove_Desc:
			{
				EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, &m_Item, "description" );
				GCSDK::CGCMsg< MsgGCRemoveItemName_t > msg( k_EMsgGCRemoveItemName );
				msg.Body().m_unItemID = m_Item.GetItemID();
				msg.Body().m_bDescription = true;
				GCClientSystem()->BSendMessage( msg );
			}
			break;

			case kCustomizationRemove_CustomTexture:
				SendGCSimpleAttributeRemovalMessage( &m_Item, "custom_texture", k_EMsgGCRemoveCustomTexture );
				break;

			case kCustomizationRemove_MakersMark:
				SendGCSimpleAttributeRemovalMessage( &m_Item, "makers_mark", k_EMsgGCRemoveMakersMark );
				break;
			
			case kCustomizationRemove_StrangePart:
			{
				Assert( m_prop.m_iUserData != kNoUserData );
				int iKillEaterAttrIndex = m_prop.m_iUserData;

				// What attribute did we select?
				const CEconItemAttributeDefinition *pAttrDef = GetKillEaterAttr_Type( iKillEaterAttrIndex );
				Assert( pAttrDef );

				// Make sure this item has this attribute.
				float fScoreType = kKillEaterEvent_PlayerKill;
				Verify( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( &m_Item, pAttrDef, &fScoreType ) || iKillEaterAttrIndex == 0 );
				
				// Dispatch message.
				EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, &m_Item, "strange_part" );
				GCSDK::CProtoBufMsg<CMsgGCRemoveStrangePart> msg( k_EMsgGCRemoveStrangePart );
				
				msg.Body().set_item_id( m_Item.GetItemID() );
				msg.Body().set_strange_part_score_type( (int)fScoreType );
				GCClientSystem()->BSendMessage( msg );
			}
			break;

			case kCustomizationRemove_StrangeScores:
			{
				Assert( m_prop.m_iUserData == kNoUserData );

				EconUI()->Gamestats_ItemTransaction( IE_ITEM_RESET_STRANGE_COUNTERS, &m_Item );
				GCSDK::CProtoBufMsg<CMsgGCResetStrangeScores> msg( k_EMsgGCResetStrangeScores );
				msg.Body().set_item_id( m_Item.GetItemID() );
				GCClientSystem()->BSendMessage( msg );
			}
			break;

			case kCustomizationRemove_UpgradeCard:
				{
					Assert( m_prop.m_iUserData != kNoUserData );
				
					// Make sure we selected a valid attribute that this item has.
					const CEconItemAttributeDefinition *pAttrDef = GetCardUpgradeForIndex( &m_Item, m_prop.m_iUserData );
					Assert( pAttrDef );
					Verify( m_Item.FindAttribute( pAttrDef ) );
				
					// Dispatch message.
					EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, &m_Item, "upgrade_card" );
					GCSDK::CProtoBufMsg<CMsgGCRemoveUpgradeCard> msg( k_EMsgGCRemoveUpgradeCard );
				
					msg.Body().set_item_id( m_Item.GetItemID() );
					msg.Body().set_attribute_index( pAttrDef->GetDefinitionIndex() );
					GCClientSystem()->BSendMessage( msg );
				}
				break;

			case kCustomizationRemove_KillStreak:
				SendGCSimpleAttributeRemovalMessage( &m_Item, "killstreak", k_EMsgGCRemoveKillStreak );
				break;
			case kCustomizationRemove_GiftedBy:
				SendGCSimpleAttributeRemovalMessage( &m_Item, "giftedby", k_EMsgGCRemoveGiftedBy );
				break;
			case kCustomizationRemove_Festivizer:
				SendGCSimpleAttributeRemovalMessage( &m_Item, "festivizer", k_EMsgGCRemoveFestivizer );
				break;
			default:
				AssertMsg( false, "Unknown item customization removal type!" );
				break;
		}
	}

	SetVisible( false );
	MarkForDeletion();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CRefurbishItemDialog : public CComboBoxBackpackOverlayDialogBase
{
public:
	DECLARE_CLASS_SIMPLE( CRefurbishItemDialog, CComboBoxBackpackOverlayDialogBase );

public:
	CRefurbishItemDialog( vgui::Panel *pParent, CEconItemView *m_pItem ) : CComboBoxBackpackOverlayDialogBase( pParent, m_pItem ) { }

private:
	virtual void PopulateComboBoxOptions()
	{
		Assert( m_pItem );

		KeyValues *pKeyValues = new KeyValues( "data" );
		for ( int i = 0; i < GetRemovableAttributesCount(); i++ )
		{
			if ( RemovableAttributes_DoesAttributeApply( i, m_pItem ) )
			{
				pKeyValues->SetInt( "data", i );

				RefurbishableProperty prop = RemovableAttributes_GetAttributeDetails( i );

				CUtlConstWideString wsDialogCustomToken;
				if ( prop.m_pGetCustomDialogLocalizationTokenFunc )
				{
					(*prop.m_pGetCustomDialogLocalizationTokenFunc)( m_pItem, prop.m_iUserData, wsDialogCustomToken );
				}
				CConstructLocalizedString localizedUI( GLocalizationProvider()->Find( prop.m_pszSelectionUILocalizationToken ), wsDialogCustomToken.IsEmpty() ? L"" : wsDialogCustomToken.Get() );
				GetComboBox()->AddItem( localizedUI, pKeyValues );
			}
		}
		pKeyValues->deleteThis();

		Assert( GetComboBox()->GetItemCount() > 0 );

		GetComboBox()->ActivateItemByRow( 0 );
	}

	virtual void OnComboBoxApplication()
	{
		if ( !m_pItem )
			return;

		KeyValues *pKVActiveUserData = GetComboBox()->GetActiveItemUserData();
		int iIndex = pKVActiveUserData ? pKVActiveUserData->GetInt( "data", -1 ) : -1;
		if ( iIndex < 0 )
			return;

		const RefurbishableProperty RefurbProp = RemovableAttributes_GetAttributeDetails( iIndex );

		CTFRemoveItemCustomizationConfirmDialog *pDialog = new CTFRemoveItemCustomizationConfirmDialog( RefurbProp, m_pItem );
		if ( pDialog )
		{
			pDialog->Show();
		}
	}

	virtual const char *GetTitleLabelLocalizationToken() const { return "#TF_Item_RefurbishItemHeader"; }
};


//-----------------------------------------------------------------------------
// Purpose: Handles item selection while in tool selection mode
//-----------------------------------------------------------------------------
void CBackpackPanel::HandleToolItemSelection( CEconItemView *pItem )
{
	if ( !InToolSelectionMode() )
	{
		// must be in tool selection mode
		Assert( InToolSelectionMode() );
		return;
	}

	if ( pItem )
	{
		// Check if we should bring up the shuffle dialog instead of directly using the tool
		static CSchemaAttributeDefHandle pAttrDef_CanShuffleCrateContents( "can shuffle crate contents" );
		if ( pItem->FindAttribute( pAttrDef_CanShuffleCrateContents ) )
		{
			CInputStringForItemBackpackOverlayDialog *pDialog = vgui::SETUP_PANEL( new CInputStringForItemBackpackOverlayDialog( this, pItem, &m_ToolSelectionItem ) );
			if ( pDialog )
			{
				pDialog->Show();
				CancelToolSelection();
			}
		}
		else if ( m_ToolSelectionItem.FindAttribute( pAttrDef_CanShuffleCrateContents ) )
		{
			CInputStringForItemBackpackOverlayDialog *pDialog = vgui::SETUP_PANEL( new CInputStringForItemBackpackOverlayDialog( this, &m_ToolSelectionItem, pItem ) );
			if ( pDialog )
			{
				pDialog->Show();
				CancelToolSelection();
			}
		}
		// is a tool being applied onto this item
		else if ( m_ToolSelectionItem.GetStaticData()->IsTool() && ApplyTool( this, &m_ToolSelectionItem, pItem ) )
		{
			CancelToolSelection();
			UpdateModelPanels();
		}
		// is this item a tool that can be applied on a selected item
		else if ( pItem->GetStaticData()->IsTool() && ApplyTool( this, pItem, &m_ToolSelectionItem ) )
		{
			CancelToolSelection();
			UpdateModelPanels();
		}
	}
}


//-----------------------------------------------------------------------------
// Purpose: Tries to use the item. This might switch the panel to a tool item
//			selection mode, or launch the recipe crafting panel.
//-----------------------------------------------------------------------------
void CBackpackPanel::SetupToolSelectionItem()
{
	for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
	{
		if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
		{
			m_ToolSelectionItem = *m_pItemModelPanels[i]->GetItem();
			break;
		}
	}
}


//-----------------------------------------------------------------------------
// Purpose: Open up the trade dialog
//-----------------------------------------------------------------------------
void CBackpackPanel::DoTradeToPlayer()
{
	OpenTradingStartDialog( this );
}

//-----------------------------------------------------------------------------
// Purpose: Use the trade dialog to send a gift to a player.
//-----------------------------------------------------------------------------
void CBackpackPanel::DoGiftToPlayer()
{
	OpenTradingStartDialog( this, &m_ToolSelectionItem );
}

//-----------------------------------------------------------------------------
// Purpose: Open up the overlay to sell the selected item
//-----------------------------------------------------------------------------
void CBackpackPanel::DoSellMarketplace()
{
	CUtlVector< CItemModelPanel* > m_vecSelected;
	GetSelectedPanels( SELECT_FIRST, m_vecSelected );
	Assert( m_vecSelected.Count() );
	if( !m_vecSelected.Count() )
		return;

	if ( m_vecSelected.Count() && steamapicontext && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() )
	{
		CEconItemView *pItem = m_vecSelected.Head()->GetItem();
		const char *pszPrefix = "";
		if ( GetUniverse() == k_EUniverseBeta )
		{
			pszPrefix = "beta.";
		}
		uint32 nAssetContext = 2; // k_EEconContextBackpack
		char szURL[512];
		V_snprintf( szURL, sizeof(szURL), "http://%ssteamcommunity.com/my/inventory/?sellOnLoad=1#%d_%d_%llu", pszPrefix, engine->GetAppID(), nAssetContext, pItem->GetItemID() );
		steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( szURL );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Use a description tag, or offer to buy one
//-----------------------------------------------------------------------------
void CBackpackPanel::DoDescription()
{
	static CSchemaItemDefHandle pItemDef_DescTag( "Description Tag" );
	if ( !AttemptToUseItem( pItemDef_DescTag->GetDefinitionIndex() ) )
	{
		AttemptToShowItemInStore( pItemDef_DescTag->GetDefinitionIndex() );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Use a name tag, or offer to buy one
//-----------------------------------------------------------------------------
void CBackpackPanel::DoRename()
{
	static CSchemaItemDefHandle pItemDef_NameTag( "Name Tag" );
	if ( !AttemptToUseItem( pItemDef_NameTag->GetDefinitionIndex() ) )
	{
		AttemptToShowItemInStore( pItemDef_NameTag->GetDefinitionIndex() );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Delete the selected items
//-----------------------------------------------------------------------------
void CBackpackPanel::DoDelete()
{
	// Hide the mouseover panel
	HideMouseOverPanel();

	int iItemsToDelete = 0;
	for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
	{
		if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
		{
			iItemsToDelete++;
		}
	}

	// Bring up confirm dialog
	CConfirmDeleteItemDialog *pConfirm = vgui::SETUP_PANEL( new CConfirmDeleteItemDialog( this, ( iItemsToDelete > 1 ) ) );
	if ( pConfirm )
	{
		pConfirm->Show();

		m_pConfirmDeleteDialog = pConfirm;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Use the selected tool
//-----------------------------------------------------------------------------
void CBackpackPanel::DoApplyOnItem()
{
	SetupToolSelectionItem();

	if ( m_ToolSelectionItem.IsValid() )
	{
		const IEconTool *pEconTool = m_ToolSelectionItem.GetItemDefinition()->GetEconTool();

		// Gather all quest objective attributes
		CRecipeComponentMatchingIterator recipeIterator( NULL, NULL );
		if ( m_ToolSelectionItem.GetSOCData() )
		{
			m_ToolSelectionItem.GetSOCData()->IterateAttributes( &recipeIterator );
		}

		if( pEconTool && recipeIterator.GetMatchingComponentInputs().Count() > 0 )
		{
			// Launch new crafting window if we need to
			if( m_pDynamicRecipePanel == NULL )
			{
				m_pDynamicRecipePanel = vgui::SETUP_PANEL( new CDynamicRecipePanel( this, "dynamic_recipe_panel", &m_ToolSelectionItem ) );
			}

			// Set recipe item into panel
			if ( m_pDynamicRecipePanel )
			{
				m_pDynamicRecipePanel->SetVisible( true );
				m_pDynamicRecipePanel->SetNewRecipe( &m_ToolSelectionItem );
			}
			return;
		}

		// Check if we actually have any items we can use this tool on
		bool bHasValidTargetItem = false;
		CPlayerInventory *pInv = InventoryManager()->GetLocalInventory();
		Assert( pInv );
		if ( pInv )
		{
			for ( int i = 0 ; i < pInv->GetItemCount() ; ++i )
			{
				CEconItemView *pItem = pInv->GetItem( i );
				if ( CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, pItem ) )
				{
					bHasValidTargetItem = true;
					break;
				}
			}

			// If no applicable items, try stock items
			if ( !bHasValidTargetItem )
			{
				// this is really inefficient, maybe have a list of baseitems somewhere
				CEconItemView tempItem;
				const CEconItemDefinition* pItemDef = NULL;

				const CEconItemSchema::SortedItemDefinitionMap_t& mapItems = GetItemSchema()->GetSortedItemDefinitionMap();
				for ( int it = mapItems.FirstInorder(); it != mapItems.InvalidIndex(); it = mapItems.NextInorder( it ) )
				{
					if ( mapItems[it]->IsBaseItem() && !mapItems[it]->IsHidden() )
					{
						CFmtStr fmtStrCustomizedDefName( "Upgradeable %s", mapItems[it]->GetDefinitionName() );
						pItemDef = GetItemSchema()->GetItemDefinitionByName( fmtStrCustomizedDefName.Access() );
						if ( pItemDef )
						{
							tempItem.Init( pItemDef->GetDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
							if ( CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, &tempItem ) )
							{
								bHasValidTargetItem = true;
								break;
							}
						}
					}
				}

				if ( bHasValidTargetItem )
				{
					// automatically switch to stock items
					OnCommand( "showbaseitems" );
				}
			}
		}

		if ( !bHasValidTargetItem )
		{
			ShowMessageBox( NULL, "#ToolNoTargetItems", "#GameUI_OK" );
			return;
		}

		m_eSelectionMode = ToolSelection;
		m_nLastToolPage = GetCurrentPage();

		if ( m_pMouseOverTooltip )
		{
			m_pMouseOverTooltip->HideTooltip();
		}

		ClearNameFilter( true );
		SetCurrentPage( 0 );
		UpdateModelPanels();
	}
}

//-----------------------------------------------------------------------------
// Purpose: use a consumable item directly from the backpack
//-----------------------------------------------------------------------------
void CBackpackPanel::DoUseConsumableItem()
{
	SetupToolSelectionItem();

#ifdef TF_CLIENT_DLL
	UseConsumableItem( &m_ToolSelectionItem, this );
#endif
}

//-----------------------------------------------------------------------------
// Purpose: Use the tool to unwrap an item
//-----------------------------------------------------------------------------
void CBackpackPanel::DoUnwrapItem()
{
	DoUseConsumableItem();
}

//-----------------------------------------------------------------------------
// Purpose: Use the tool to deliver an item
//-----------------------------------------------------------------------------
void CBackpackPanel::DoDeliverItem()
{
	SetupToolSelectionItem();

#ifdef TF_CLIENT_DLL
	const CEconTool_WrappedGift *pWrappedGiftTool = m_ToolSelectionItem.GetItemDefinition()
												  ? m_ToolSelectionItem.GetItemDefinition()->GetTypedEconTool<CEconTool_WrappedGift>()
												  : NULL;

	if ( pWrappedGiftTool && pWrappedGiftTool->BIsDirectGift() )
	{
		DoUseConsumableItem();
		return;
	}
	else if ( pWrappedGiftTool && pWrappedGiftTool->BIsGlobalGift() )
	{
		// If this is a global gift, we don't let the user pick a target so we're done as of now.
		extern void UseUntargetedGiftConfirm( bool bConfirmed, void *pContext );
		CTFGenericConfirmDialog *pDialog = ShowConfirmDialog( "#TF_DeliverGiftDialog_Title", "#TF_DeliverGiftDialog_Random_Text", 
														      "#TF_DeliverGiftDialog_Confirm", "#TF_DeliverGiftDialog_Cancel", 
														      &UseUntargetedGiftConfirm );

		pDialog->SetContext( &m_ToolSelectionItem );
		return;
	}

	DoGiftToPlayer();
#endif
}

//-----------------------------------------------------------------------------
// Purpose: Show
//-----------------------------------------------------------------------------
void CBackpackPanel::DoApplyByItem()
{
	SetupToolSelectionItem();

	m_eSelectionMode = ToolSelection;
	m_nLastToolPage = GetCurrentPage();

	if ( m_pMouseOverTooltip )
	{
		m_pMouseOverTooltip->HideTooltip();
	}

	ClearNameFilter( true );
	SetCurrentPage( 0 );
	UpdateModelPanels();
}

//-----------------------------------------------------------------------------
// Purpose: open shuffle items dialog
//-----------------------------------------------------------------------------
void CBackpackPanel::DoShuffle()
{
	SetupToolSelectionItem();

	CInputStringForItemBackpackOverlayDialog *pDialog = vgui::SETUP_PANEL( new CInputStringForItemBackpackOverlayDialog( this, &m_ToolSelectionItem ) );
	if ( pDialog )
	{
		pDialog->Show();
	}
}

void CBackpackPanel::DoEditSlot()
{
	SetupToolSelectionItem();

	// Launch new slot window if we need to
	if( m_pItemSlotPanel == NULL )
	{
		m_pItemSlotPanel = vgui::SETUP_PANEL( new CItemSlotPanel( this ) );
	}
				
	// Set item into panel
	if ( m_pItemSlotPanel )
	{
		m_pItemSlotPanel->SetVisible( true );
		m_pItemSlotPanel->SetItem( m_ToolSelectionItem.GetSOCData() );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Refurbish item
//-----------------------------------------------------------------------------
void CBackpackPanel::DoRefurbishItem()
{
	for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
	{
		if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
		{
			m_ComboBoxOverlaySelectionItem = *m_pItemModelPanels[i]->GetItem();
			break;
		}
	}

	CRefurbishItemDialog *pRefurbishDialog = vgui::SETUP_PANEL( new CRefurbishItemDialog( this, &m_ComboBoxOverlaySelectionItem ) );
	if ( pRefurbishDialog )
	{
		pRefurbishDialog->Show();
	}
}

//-----------------------------------------------------------------------------
// Purpose: Deode by item
//-----------------------------------------------------------------------------
void CBackpackPanel::DoGetItemFromStore()
{
	SetupToolSelectionItem();

	uint32 iDecoableItemDef = 0;
	if ( GetDecodedByItemDefIndex( &m_ToolSelectionItem, &iDecoableItemDef ) )
	{
		// casting to the proper type since our econ system is dumb
		const float& value_as_float = (float&)iDecoableItemDef;
		CEconItemDefinition * pDefIndex = GetItemSchema()->GetItemDefinition( (int)value_as_float );

		EconUI()->GetStorePanel()->AddToCartAndCheckoutImmediately( pDefIndex->GetDefinitionIndex() );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Open End of the Line duck leaderboards
//-----------------------------------------------------------------------------
void CBackpackPanel::DoOpenDuckLeaderboards()
{
	CCharacterInfoPanel* pCharInfo = dynamic_cast< CCharacterInfoPanel* >( EconUI() );
	CDucksLeaderboardManager *pDuckLeaderboards = vgui::SETUP_PANEL( new CDucksLeaderboardManager( pCharInfo, "DucksLeaderboardPanel" ) );
	pDuckLeaderboards->SetVisible( true );
}

//-----------------------------------------------------------------------------
// Strange Count Transfer Dialog
//-----------------------------------------------------------------------------
void CBackpackPanel::DoStrangeCountTransfer()
{
	CUtlVector< CItemModelPanel* > vecSelected;
	GetSelectedPanels( SELECT_FIRST, vecSelected );

	Assert( vecSelected.Count() );
	if ( vecSelected.IsEmpty() )
		return;

	m_pStrangeToolPanel = vgui::SETUP_PANEL( new CStrangeCountTransferPanel( this, vecSelected[0]->GetItem() ) );
}

//-----------------------------------------------------------------------------
// Collection crafting
//-----------------------------------------------------------------------------
void CBackpackPanel::DoCraftUpCollection()
{
	CUtlVector< CItemModelPanel* > vecSelected;
	GetSelectedPanels( SELECT_ALL, vecSelected );

	//Assert( vecSelected.Count() );
	//if ( vecSelected.IsEmpty() )
	//	return;

	// Get all the items that were selected
	CUtlVector< const CEconItemView* > vecSelectedItems;
	FOR_EACH_VEC( vecSelected, i )
	{
		if ( vecSelected[ i ]->GetItem() && GetCollectionCraftingInvalidReason( vecSelected[ i ]->GetItem(), NULL ) == NULL )
		{
			vecSelectedItems.AddToTail( vecSelected[ i ]->GetItem() );
		}
	}

	// For tracking how many times they've opened this menu
	tf_trade_up_use_count.SetValue( tf_trade_up_use_count.GetInt() - 1 );

	// Open it up!
	GetCollectionCraftPanel()->Show( vecSelectedItems );
}

//-----------------------------------------------------------------------------
// Collection crafting
//-----------------------------------------------------------------------------
void CBackpackPanel::DoHalloweenOffering()
{
	// Open it up!
	if ( !m_pHalloweenOfferingPanel )
	{
		m_pHalloweenOfferingPanel = vgui::SETUP_PANEL( new CHalloweenOfferingPanel( this, m_pMouseOverTooltip ) );
		m_pHalloweenOfferingPanel->InvalidateLayout( true, true );
	}
		// empty
	CUtlVector< const CEconItemView* > vecSelectedItems;
	m_pHalloweenOfferingPanel->Show( vecSelectedItems );
}

//-----------------------------------------------------------------------------
// Craft Common StatClock
//-----------------------------------------------------------------------------
void CBackpackPanel::DoCraftCommonStatClock()
{
	// Open it up!
	if ( !m_pMannCoTradePanel )
	{
		m_pMannCoTradePanel = vgui::SETUP_PANEL( new CCraftCommonStatClockPanel( this, m_pMouseOverTooltip ) );		// make this more generic
		m_pMannCoTradePanel->InvalidateLayout( true, true );
	}

	CUtlVector< CItemModelPanel* > vecSelected;
	GetSelectedPanels(SELECT_ALL, vecSelected);

	CUtlVector< const CEconItemView* > vecSelectedItems;
	FOR_EACH_VEC(vecSelected, i)
	{
		if (vecSelected[i]->GetItem() && GetCraftCommonStatClockInvalidReason(vecSelected[i]->GetItem(), NULL) == NULL)
		{
			vecSelectedItems.AddToTail(vecSelected[i]->GetItem());
		}
	}

	m_pMannCoTradePanel->Show( vecSelectedItems );
}

//-----------------------------------------------------------------------------
// Purpose: Bring up the 3D inspect panel for the selected item
//-----------------------------------------------------------------------------
void CBackpackPanel::DoInspectModel()
{
	CUtlVector< CItemModelPanel* > vecSelected;
	GetSelectedPanels( SELECT_FIRST, vecSelected );

	if ( vecSelected.IsEmpty() )
		return;

	CEconItemView *pItem = vecSelected[0]->GetItem();
	if ( pItem )
	{
		float flInspect = 0;
		static CSchemaAttributeDefHandle pAttrib_WeaponAllowInspect( "weapon_allow_inspect" );
		if ( ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttrib_WeaponAllowInspect, &flInspect ) && flInspect != 0.f )
#ifdef STAGING_ONLY
			|| tf_weapon_force_allow_inspect.GetBool()
#endif
			)
		{
			m_pInspectPanel->SetVisible( true );
			m_pInspectPanel->SetItemCopy( vecSelected[0]->GetItem() );
		}
		else
		{
			for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; ++iClass )
			{
				if ( pItem->GetStaticData()->CanBeUsedByClass( iClass ) )
				{
					m_pInspectCosmeticPanel->PreviewItem( iClass, pItem );
					break;
				}
			}
			m_pInspectCosmeticPanel->SetVisible( true );
		}
	}
}
//-----------------------------------------------------------------------------
void CBackpackPanel::OpenInspectModelPanelAndCopyItem( CEconItemView *pItemView )
{
	if ( !pItemView )
		return;

	EconUI()->OpenEconUI( ECONUI_BACKPACK );

	// Figure out which preview to show
	float flInspect = 0;
	static CSchemaAttributeDefHandle pAttrib_WeaponAllowInspect( "weapon_allow_inspect" );
	if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItemView, pAttrib_WeaponAllowInspect, &flInspect ) && flInspect != 0.f )
	{
		m_pInspectPanel->SetVisible( true );
		m_pInspectPanel->SetItemCopy( pItemView );
	}
	else
	{
		for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; ++iClass )
		{
			if ( pItemView->GetStaticData()->CanBeUsedByClass( iClass ) )
			{
				m_pInspectCosmeticPanel->PreviewItemCopy( iClass, pItemView );
				m_pInspectCosmeticPanel->SetVisible( true );
				break;
			}
		}
	}
}

CCollectionCraftingPanel* CBackpackPanel::GetCollectionCraftPanel()
{
	if ( !m_pCollectionCraftPanel )
	{
		m_pCollectionCraftPanel = vgui::SETUP_PANEL( new CCollectionCraftingPanel( this, m_pMouseOverTooltip ) );
		m_pCollectionCraftPanel->InvalidateLayout( true, true );
	}

	return m_pCollectionCraftPanel;
}

//-----------------------------------------------------------------------------
// Purpose: Buy a key, and then immediately use it on the selected crate once
//			tbe store transaction completes
//-----------------------------------------------------------------------------
void CBackpackPanel::DoBuyKeyAndOpenCrate()
{
	CUtlVector< CItemModelPanel* > vecSelected;
	GetSelectedPanels( SELECT_FIRST, vecSelected );

	if ( vecSelected.IsEmpty() )
		return;

	m_hQuickOpenCrate.SetItem( vecSelected.Head()->GetItem() );

	uint32 iDecoableItemDef = 0;
	if ( GetDecodedByItemDefIndex( m_hQuickOpenCrate, &iDecoableItemDef ) )
	{
		// casting to the proper type since our econ system is dumb
		const float& value_as_float = (float&)iDecoableItemDef;
		CEconItemDefinition * pDefIndex = GetItemSchema()->GetItemDefinition( (int)value_as_float );

		EconUI()->GetStorePanel()->AddToCartAndCheckoutImmediately( pDefIndex->GetDefinitionIndex() );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Find the first compatible key in our inventory, and use it on the
//			selected crate
//-----------------------------------------------------------------------------
void CBackpackPanel::DoOpenCrateWithKey()
{
	CUtlVector< CItemModelPanel* > vecSelected;
	GetSelectedPanels( SELECT_FIRST, vecSelected );

	if ( vecSelected.IsEmpty() )
		return;

	CEconItemView *pCrate = vecSelected.Head()->GetItem();

	CEconItemView *pKey = GetFirstCompatibleKeyForCrate( pCrate );
	if ( !pKey )
		return;

	ApplyTool( this, pKey, pCrate );
}


//-----------------------------------------------------------------------------
// Purpose: Open up the loadout for a class
//-----------------------------------------------------------------------------
void CBackpackPanel::DoEquipForClass( int nClass )
{
	// Negative because reasons
	EconUI()->OpenEconUI( -nClass );	
}

//-----------------------------------------------------------------------------
// Purpose: Given a paint can index, offer to use one or buy one
//-----------------------------------------------------------------------------
void CBackpackPanel::DoPaint( int nPaintItemIndex, bool bUseStore, bool bUseMarket )
{
	if ( !bUseStore && !bUseMarket )
	{
		AttemptToUseItem( nPaintItemIndex );
	}

	if ( bUseStore )
	{
		AttemptToShowItemInStore( nPaintItemIndex );
	}
	else if ( bUseMarket )
	{
		AttemptToShowItemInMarket( nPaintItemIndex );
	}
}
//-----------------------------------------------------------------------------
// Purpose: Given a strange part index, offer to use one or buy one (Market)
//-----------------------------------------------------------------------------
void CBackpackPanel::DoStrangePart( int nStrangePartIndex, bool bUseMarket )
{
	if ( !bUseMarket )
	{
		AttemptToUseItem( nStrangePartIndex );
	}

	if ( bUseMarket )
	{
		AttemptToShowItemInMarket( nStrangePartIndex );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Try to find the first item with the passed-in item name in our inventory
//			and try to use it on the selected panel's item.  If we dont have an item
//			matching the name passed in, go to the store and prompt the user to buy one.
//-----------------------------------------------------------------------------
bool CBackpackPanel::AttemptToUseItem( item_definition_index_t iItemDefIndex )
{
	CUtlVector< CItemModelPanel* > m_vecSelected;
	GetSelectedPanels( SELECT_FIRST, m_vecSelected );
	Assert( m_vecSelected.Count() );
	if ( !m_vecSelected.Count() )
		return false;

	CEconItemView *pSelectedItem = m_vecSelected.Head()->GetItem();
	Assert( pSelectedItem );
	if ( !pSelectedItem )
		return false;

	CEconItemView *pNameTag = CTFPlayerInventory::GetFirstItemOfItemDef( iItemDefIndex );
	if ( pNameTag )
	{
		if ( ApplyTool( this, pNameTag, pSelectedItem ) )
		{
			CancelToolSelection();
			UpdateModelPanels();
		}
		return true;
	}
	return false;
}
//-----------------------------------------------------------------------------
void CBackpackPanel::AttemptToShowItemInStore( item_definition_index_t iItemDefIndex )
{
	CUtlVector< CItemModelPanel* > m_vecSelected;
	GetSelectedPanels( SELECT_FIRST, m_vecSelected );
	Assert( m_vecSelected.Count() );
	if( !m_vecSelected.Count() )
		return;

	CEconItemView *pSelectedItem = m_vecSelected.Head()->GetItem();
	Assert( pSelectedItem );
	if ( !pSelectedItem )
		return;

	EconUI()->OpenStorePanel( iItemDefIndex, false );
}
//-----------------------------------------------------------------------------
void CBackpackPanel::AttemptToShowItemInMarket( item_definition_index_t iItemDefIndex )
{
	CUtlVector< CItemModelPanel* > m_vecSelected;
	GetSelectedPanels( SELECT_FIRST, m_vecSelected );
	Assert( m_vecSelected.Count() );
	if ( !m_vecSelected.Count() )
		return;

	CEconItemView *pSelectedItem = m_vecSelected.Head()->GetItem();
	Assert( pSelectedItem );
	if ( !pSelectedItem )
		return;

	CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( iItemDefIndex );
	Assert( pItemDef );
	if ( !pItemDef )
		return;

	if ( !CBaseAdPanel::CheckForRequiredSteamComponents( "#StoreUpdate_SteamRequired", "#MMenu_OverlayRequired" ) )
		return;

	if ( pItemDef && steamapicontext && steamapicontext->SteamFriends() )
	{
		const char *pszPrefix = "";
		if ( GetUniverse() == k_EUniverseBeta )
		{
			pszPrefix = "beta.";
		}

		static char pszItemName[256];
		g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pItemDef->GetItemBaseName() ), pszItemName, sizeof( pszItemName ) );

		char szURL[512];
		V_snprintf( szURL, sizeof( szURL ), "http://%ssteamcommunity.com/market/listings/%d/%s", pszPrefix, engine->GetAppID(), pszItemName );
		steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( szURL );
	}
}
//-----------------------------------------------------------------------------
// Purpose: Get the first, or all selected item model panels
//-----------------------------------------------------------------------------
void CBackpackPanel::GetSelectedPanels( ESelection eSelection, CUtlVector< CItemModelPanel* >& m_vecSelected ) const
{
	for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
	{
		if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
		{
			m_vecSelected.AddToTail( m_pItemModelPanels[i] );

			if ( eSelection == SELECT_FIRST )
			{
				return;
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OnCommand( const char *command )
{
	if ( V_strncasecmp( command, "goto_page_", V_strlen( "goto_page_" ) ) == 0 )
	{
		int iPage = V_atoi( &command[ V_strlen( "goto_page_" ) ] );
		SetCurrentPage( iPage );
		UpdateModelPanels();
		return;
	}
	else if ( !Q_strnicmp( command, "nextpage", 8 ) )
	{
		if ( !m_bDragging )
		{
			DeSelectAllBackpackItemPanels();
		}

		SetCurrentPage( GetCurrentPage() + 1 );
		UpdateModelPanels();
		return;
	}
	else if ( !Q_strnicmp( command, "prevpage", 8 ) )
	{
		if ( !m_bDragging )
		{
			DeSelectAllBackpackItemPanels();
		}

		SetCurrentPage( GetCurrentPage() - 1 );
		UpdateModelPanels();
		return;
	}
	else if ( !Q_strnicmp( command, "useitem", 7 ) )
	{
		AssertMsg( 0, "Everything should be going through the context menu. Fix the calling code." );
		return;
	}
	else if ( !Q_strnicmp( command, "showbackpackitems", 17 ) )
	{
		SetShowBaseItems( false );
		if ( m_pShowBaseItemsCheckbox )
		{
			m_pShowBaseItemsCheckbox->SetSelected( false );
		}
		return;
	}
	else if ( !Q_strnicmp( command, "showbaseitems", 13 ) )
	{
		SetShowBaseItems( true );
		if ( m_pShowBaseItemsCheckbox )
		{
			m_pShowBaseItemsCheckbox->SetSelected( true );
		}
		return;
	}
	else if ( !Q_strnicmp( command, "canceltool", 10 ) )
	{
		CancelToolSelection();
		UpdateModelPanels();
		return;
	}
	else if ( !Q_stricmp( command, "show_explanations" ) )
	{
		if ( !m_flStartExplanationsAt )
		{
			m_flStartExplanationsAt = Plat_FloatTime();
			vgui::ivgui()->AddTickSignal( GetVPanel() );
		}
		RequestFocus();
	}
	else if ( !Q_stricmp( command, "showdetails" ) )
	{
		for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
		{
			if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
			{
				OpenArmory( m_pItemModelPanels[i]->GetItem() );
				break;
			}
		}
		UpdateModelPanels();
		return;
	}
	else if ( !V_strnicmp( command, "equipclass", 10 ) )
	{
		int nClass = atoi( command + 10 );
		DoEquipForClass( nClass );
	}
	else if ( !V_strnicmp( command, "paint", 5 ) )
	{
		int nIndex = atoi( command + 5 );
		DoPaint( nIndex, false, false );
	}
	else if ( !V_strnicmp( command, "market_paint", 12 ) )
	{
		int nIndex = atoi( command + 12 );
		DoPaint( nIndex, false, true );
	}
	else if ( !V_strnicmp( command, "store_paint", 11 ) )
	{
		int nIndex = atoi( command + 11 );
		DoPaint( nIndex, true, false );
	}
	else if ( !V_strnicmp( command, "strangepart_", 12 ) )
	{
		int nIndex = atoi( command + 12 );
		DoStrangePart( nIndex, false );
	}
	else if ( !V_strnicmp( command, "market_strangepart_", 19 ) )
	{
		int nIndex = atoi( command + 19 );
		DoStrangePart( nIndex, true );
	}
	else if ( !V_strnicmp( command, "Context_CraftUpCollection", 25 ) )
	{
		DoCraftUpCollection();
	}
	else if ( !V_strnicmp( command, "Context_CraftCommonStatClock", 25 ) )
	{
		DoCraftCommonStatClock();
	}
#ifdef STAGING_ONLY
	else if ( !V_strnicmp( command, "unpin", 5 ) )
	{
		m_pMouseOverCardPanel->PinCard( false );
	}
#endif

	BaseClass::OnCommand( command );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::OpenArmory( CEconItemView* item )
{
	PostMessage( GetParent()->GetParent()->GetParent(), new KeyValues("OpenArmoryDirect", "itemdef", item->GetItemDefIndex() ) );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::CancelToolSelection( void )
{
	if ( m_eSelectionMode == StandardSelection )
		return;

	m_eSelectionMode = StandardSelection;

	ClearNameFilter( false );

	OnCommand( "showbackpackitems" );

	SetCurrentPage( m_nLastToolPage );
	m_nLastToolPage = 0;

	m_ToolSelectionItem.Invalidate();
	if ( m_pToolIcon )
	{
		m_pToolIcon->SetVisible( false );
	}
	DeSelectAllBackpackItemPanels();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::SetShowBaseItems( bool bShow )
{
	bool bGoToFirstPage = m_bShowBaseItems != bShow;
	m_bShowBaseItems = bShow;
	if( bGoToFirstPage )
	{
		SetCurrentPage( 0 );
	}

	DeSelectAllBackpackItemPanels();
	if ( m_pToolIcon )
	{
		m_pToolIcon->SetVisible( false );
	}
	UpdateModelPanels();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
ConVar *CBackpackPanel::GetExplanationConVar( void )
{
	return &tf_explanations_backpackpanel;
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBackpackPanel::SetCurrentPage( int nNewPage )
{
	if( m_pToolIcon )
	{
		m_pToolIcon->SetVisible( false );
	}

	if ( nNewPage < 0 )
	{
		nNewPage = GetNumPages() - 1;
	}
	else if ( nNewPage >= GetNumPages() )
	{
		nNewPage = 0;
	}

	// deselect old page button
	if ( m_Pages.Count() > GetCurrentPage() && m_Pages[GetCurrentPage()] )
	{
		CExButton* pButton = dynamic_cast<CExButton*>( m_Pages[GetCurrentPage()]->FindChildByName( "Button" ) );
		if ( pButton )
		{
			pButton->SetSelected( false );
		}
	}

	BaseClass::SetCurrentPage( nNewPage );

	// mark new page button as selected
	if ( m_Pages.Count() > GetCurrentPage() &&  m_Pages[GetCurrentPage()] )
	{
		CExButton* pButton = dynamic_cast<CExButton*>( m_Pages[GetCurrentPage()]->FindChildByName( "Button" ) );
		if ( pButton )
		{
			pButton->SetSelected( true );
		}
	}
}


int	CBackpackPanel::GetItemQualityForBorder( CItemModelPanel* pItemPanel ) const
{
	if ( pItemPanel->HasItem() && ( cl_showbackpackrarities.GetInt() > 0 || m_bForceShowBackpackRarities )
				   && ( cl_showbackpackrarities.GetInt() < 2 || pItemPanel->GetItem()->IsMarketable() ) )
	{
		uint8 nRarity = pItemPanel->GetItem()->GetItemDefinition()->GetRarity();
		if ( ( nRarity != k_unItemRarity_Any ) && ( pItemPanel->GetItem()->GetItemQuality() != AE_SELFMADE ) )
		{
			// translate this quality to rarity
			return nRarity + AE_RARITY_DEFAULT;
		}

		return pItemPanel->GetItem()->GetItemQuality();
	}

	return 0;
}