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


#include "cbase.h"
#include "crate_detail_panels.h"
#include "vgui_controls/TextImage.h"
#include "econ_gcmessages.h"
#include "gc_clientsystem.h"
#include "econ_ui.h"
#include <vgui/ISurface.h>
#include "econ_item_inventory.h"
#include "econ/tool_items/tool_items.h"

#define SHUFFLE_TIME 5.f

float CInputStringForItemBackpackOverlayDialog::m_sflNextShuffleTime = 0.f;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CInputStringForItemBackpackOverlayDialog::CInputStringForItemBackpackOverlayDialog( vgui::Panel *pParent, CEconItemView *pItem, CEconItemView *pChosenKey )
	: vgui::EditablePanel( pParent, "InputStringForItemBackpackOverlayDialog" )
	, m_Item( *pItem )
	, m_pPreviewModelPanel( NULL )
	, m_pTextEntry( NULL )
	, m_pItemModelPanelKVs( NULL )
	, m_bUpdateRecieved( false )
{
	if ( pChosenKey )
	{
		m_UseableKey = *pChosenKey;
	}
	m_pPreviewModelPanel = new CItemModelPanel( this, "preview_model" );
	m_pTextEntry = new vgui::TextEntry( this, "TextEntryControl" );
	m_pShuffleButton = new CExButton( this, "ShuffleButton", "Shuffle" );
	m_pRareLootLabel = new CExLabel( this, "RareLootLabel", "#Econ_Revolving_Loot_List_Rare_Item" );
	m_pProgressBar = new vgui::ProgressBar( this, "ShuffleProgress" );
	m_pGetKeyButton = new CExButton( this, "GetKeyButton", "getkey" );
	m_pUseKeyButton = new CExButton( this, "UseKeyButton", "usekey" );

	m_pMouseOverItemPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, "mouseoveritempanel" ) );
	m_pMouseOverTooltip = new CItemModelPanelToolTip( this );
	m_pMouseOverTooltip->SetupPanels( this, m_pMouseOverItemPanel );

	ListenForGameEvent( "inventory_updated" );
}

CInputStringForItemBackpackOverlayDialog::~CInputStringForItemBackpackOverlayDialog()
{
	if ( m_pItemModelPanelKVs )
	{
		m_pItemModelPanelKVs->deleteThis();
		m_pItemModelPanelKVs = NULL;
	}

	m_vecContentsPanels.PurgeAndDeleteElements();
}

void CInputStringForItemBackpackOverlayDialog::FireGameEvent( IGameEvent *event )
{
	// If we're not visible, ignore all events
	if ( !IsVisible() )
		return;

	// Something caused our inventory to update.  Assuming it was from our shuffle
	// then we need to update ourselves.
	const char *type = event->GetName();
	if ( Q_strcmp( "inventory_updated", type ) == 0 )
	{
		m_bUpdateRecieved = true;
	}
}

void CInputStringForItemBackpackOverlayDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
{
	BaseClass::ApplySchemeSettings( pScheme );

	LoadControlSettings( "Resource/UI/econ/InputStringForItemBackpackOverlayDialog.res" );

	CCrateLootListWrapper itemWrapper( &m_Item );
	const IEconLootList *pLootList = itemWrapper.GetEconLootList();
	// Set the crate footer text.  The crate itself specifies what to use.
	if ( pLootList->GetLootListFooterLocalizationKey() )
	{
		m_pRareLootLabel->SetText( pLootList->GetLootListFooterLocalizationKey() );
	}
	else
	{
		const char *pszRareLootListFooterLocalizationKey = m_Item.GetItemDefinition()->GetDefinitionString( "loot_list_rare_item_footer", "#Econ_Revolving_Loot_List_Rare_Item" );
		m_pRareLootLabel->SetText( pszRareLootListFooterLocalizationKey );
	}

	// Use the gradient border for the tooltip
	m_pMouseOverItemPanel->SetBorder( pScheme->GetBorder("LoadoutItemPopupBorder") );

	m_pPreviewModelPanel->SetItem( &m_Item );
	m_pPreviewModelPanel->SetActAsButton( false, false ); // Dont mess around with the mouse

	m_pTextEntry->RequestFocus();	
}

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

	// Pull out the model panel KVs for this panel
	KeyValues *pItemKV = inResourceData->FindKey( "modelpanels_kv" );
	if ( pItemKV )
	{
		if ( m_pItemModelPanelKVs )
		{
			m_pItemModelPanelKVs->deleteThis();
		}
		m_pItemModelPanelKVs = new KeyValues( "modelpanels_kv" );
		pItemKV->CopySubkeys( m_pItemModelPanelKVs );
	}

	CreateItemPanels();
}

void CInputStringForItemBackpackOverlayDialog::CreateItemPanels()
{
	CCrateLootListWrapper itemWrapper( &m_Item );
	const IEconLootList *pLootList = itemWrapper.GetEconLootList();

	class CItemDefLootListIterator : public IEconLootList::IEconLootListIterator
	{
	public:
		CItemDefLootListIterator( CUtlVector< item_definition_index_t > *pVecItemDefs  )
			: m_pVecItemDefs( pVecItemDefs )
		{}

		virtual void OnIterate( item_definition_index_t unItemDefIndex ) OVERRIDE
		{
			const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( unItemDefIndex );
			if ( pItemDef && pItemDef->BValidForShuffle() )
			{
				m_pVecItemDefs->AddToTail( unItemDefIndex );
			}
		}

	private:
		CUtlVector< item_definition_index_t > * const m_pVecItemDefs;
	};

	// Get the drops from the item
	CUtlVector< item_definition_index_t > vecItemDefs;
	CItemDefLootListIterator it( &vecItemDefs );
	pLootList->EnumerateUserFacingPotentialDrops( &it );

	if ( !m_pItemModelPanelKVs )
		return;

	if ( m_vecContentsPanels.Count() != vecItemDefs.Count() )
	{
		m_vecContentsPanels.PurgeAndDeleteElements();

		FOR_EACH_VEC( vecItemDefs, i )
		{
			// Create new panel
			CItemModelPanel* pItemPanel = m_vecContentsPanels[ m_vecContentsPanels.AddToTail( new CItemModelPanel( this, CFmtStr( "item_preview_%d", i ) ) ) ];
			pItemPanel->ApplySettings( m_pItemModelPanelKVs );
			pItemPanel->InvalidateLayout( true );
			pItemPanel->SetActAsButton( false, true );	// Lets us get mouse enter/exit evens for tooltips
			pItemPanel->SetTooltip( m_pMouseOverTooltip, "" );	// Tooltip panel to use
		}
	}

	// Create the panels and set the items into them
	FOR_EACH_VEC( vecItemDefs, i )
	{
		const item_definition_index_t &itemDef = vecItemDefs[i];
			
		CItemModelPanel* pItemPanel = m_vecContentsPanels[i];

		CEconItemView item;
		item.SetItemDefIndex( itemDef );
		item.SetItemQuality( AE_UNIQUE );	// Unique by default
		item.SetItemLevel( 0 ); // Hide this?
		item.SetInitialized( true );
		item.SetItemOriginOverride( kEconItemOrigin_Invalid );

		pItemPanel->SetItem( &item );
	}
}

void CInputStringForItemBackpackOverlayDialog::PerformLayout( void )
{
	BaseClass::PerformLayout();

	// Find out how wide these panels will be side by side
	const int nBuffer = 5;
	int nTotalWide = 0;
	const int nCount = m_vecContentsPanels.Count();
	if ( nCount )
	{
		const int nWide = m_vecContentsPanels.Head()->GetWide();
		nTotalWide = (nCount * nWide) + ( (nCount - 1) * nBuffer );
	}

	// Find out how much space the panels take up within the parent
	int nParentWide = GetWide();
	int nDiff = nParentWide - nTotalWide;
	// How far we need to offset from the left edge
	int nStartOffset = nDiff / 2;

	// Place all the panels side by side
	FOR_EACH_VEC( m_vecContentsPanels, i )
	{
		CItemModelPanel* pItemPanel = m_vecContentsPanels[ i ];

		const int nWide = pItemPanel->GetWide();
		
		pItemPanel->SetPos( nStartOffset + i * (nWide + nBuffer), YRES(150) );
		pItemPanel->SetVisible( true );
	}

	// Which button to show
	m_pUseKeyButton->SetVisible( m_UseableKey.IsValid() );
	m_pGetKeyButton->SetVisible( !m_UseableKey.IsValid() );
}

void CInputStringForItemBackpackOverlayDialog::OnCommand( const char *command )
{
	if ( !Q_strnicmp( command, "cancel", 6 ) )
	{
		TFModalStack()->PopModal( this );

		SetVisible( false );
		MarkForDeletion();
	}
	else if ( !Q_strnicmp( command, "shuffle", 7 ) )
	{
		// let the GC know
		if ( m_pTextEntry && Plat_FloatTime() >= m_sflNextShuffleTime )
		{
			// Set the next time they can send a request to shuffle
			m_sflNextShuffleTime = Plat_FloatTime() + SHUFFLE_TIME;

			enum { kMaxCodeStringSize = 32 };
			char szText[ kMaxCodeStringSize ] = { 0 };
			m_pTextEntry->GetText( &szText[0], sizeof( szText )  );

			GCSDK::CProtoBufMsg<CMsgGCShuffleCrateContents> msg( k_EMsgGCShuffleCrateContents );

			msg.Body().set_crate_item_id( m_Item.GetID() );
			msg.Body().set_user_code_string( szText );

			GCClientSystem()->BSendMessage( msg );

			m_pProgressBar->SetProgress( 0.f );
			m_pProgressBar->SetVisible( true );
			m_pTextEntry->SetVisible( false );

			vgui::surface()->PlaySound( "ui/itemcrate_shuffle.wav" );
		}
	}
	else if ( !Q_strnicmp( command, "getkey", 6 ) )
	{
		static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "decoded by itemdefindex" );
			
		uint32 iDecodableItemDef = 0;
		if ( m_Item.FindAttribute( pAttrDef_DecodedBy, &iDecodableItemDef ) )
		{
			// casting to the proper type since our econ system is dumb
			const float& value_as_float = (float&)iDecodableItemDef;
			EconUI()->CloseEconUI();
			EconUI()->OpenStorePanel( (int)value_as_float, false );

			// close ourselves
			TFModalStack()->PopModal( this );
			SetVisible( false );
			MarkForDeletion();
		}
	}
	else if ( !Q_strnicmp( command, "usekey", 6 ) )
	{
		if ( m_UseableKey.IsValid() )
		{
			// Use the key
			ApplyTool( GetParent(), &m_UseableKey, &m_Item );
			// close ourselves
			TFModalStack()->PopModal( this );
			SetVisible( false );
			MarkForDeletion();
		}
	}
}

void CInputStringForItemBackpackOverlayDialog::FindUsableKey()
{
	static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "decoded by itemdefindex" );
			
	uint32 iDecodableItemDef = 0;
	if ( m_Item.FindAttribute( pAttrDef_DecodedBy, &iDecodableItemDef ) )
	{
		const float& value_as_float = (float&)iDecodableItemDef;
		iDecodableItemDef = (float)value_as_float;
		CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
		if ( !pInventory )
			return;

		for ( int i = 0; i < pInventory->GetItemCount(); i++ )
		{
			CEconItemView *pItem = pInventory->GetItem(i);
			if ( pItem->GetItemDefIndex() == iDecodableItemDef )
			{
				m_UseableKey = *pItem;
			}
		}
	}
}

void CInputStringForItemBackpackOverlayDialog::OnThink()
{
	float flDelta = m_sflNextShuffleTime - Plat_FloatTime();

	// If we're ready, show "Shuffle"
	if ( flDelta < 0 )
	{
		// Show the text entry, show the progress bar
		m_pProgressBar->SetVisible( false );
		m_pTextEntry->SetVisible( true );

		// Re-enable the shuffle/use buttons
		m_pShuffleButton->SetEnabled( m_pTextEntry->GetTextLength() != 0 );
		m_pUseKeyButton->SetEnabled( true );
		// Say "Shuffle"
		m_pShuffleButton->SetText( "#ShuffleContents" );

		// We got a inventory update message, update
		if ( m_bUpdateRecieved )
		{
			CreateItemPanels();
			m_bUpdateRecieved = false;
		}
	}
	else
	{
		// Show the progress bar, hide the text field
		m_pProgressBar->SetVisible( true );
		m_pTextEntry->SetVisible( false );

		// Dont allow clicking the shuffle or use key button
		m_pShuffleButton->SetEnabled( false );
		m_pUseKeyButton->SetEnabled( false );
		// Say "Shuffling..."
		m_pShuffleButton->SetText( "#ShufflingContents" );

		// Set progress
		float flProgress = ( SHUFFLE_TIME - flDelta ) / SHUFFLE_TIME;
		m_pProgressBar->SetProgress( flProgress );
	}
}

void CInputStringForItemBackpackOverlayDialog::Show()
{
	SetVisible( true );
	MakePopup();
	MoveToFront();
	SetKeyBoardInputEnabled( true );
	SetMouseInputEnabled( true );
	TFModalStack()->PushModal( this );

	// If a key wasnt passed in, find the first one in the 
	// player's inventory
	if ( !m_UseableKey.IsValid() )
	{
		FindUsableKey();
	}

	// Which button to show
	m_pUseKeyButton->SetVisible( m_UseableKey.IsValid() );
	m_pGetKeyButton->SetVisible( !m_UseableKey.IsValid() );

	// Put the current gen code of the crate into the text field
	static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "crate generation code" );
	const char *pszAttrGenCode;
	if ( FindAttribute_UnsafeBitwiseCast<CAttribute_String>( &m_Item, pAttrDef_DecodedBy, &pszAttrGenCode ) )
	{
		m_pTextEntry->SetText( pszAttrGenCode );
	}
}