class ItemModeItemChanged extends Event
{
	var equipmentArea : gamedataEquipmentArea;
	var slotIndex : Int32;
	var hotkey : EHotkey;
}

class InventoryItemModeLogicController extends inkLogicController
{
	private editable var m_itemCategoryList : inkCompoundRef;
	private editable var m_itemCategoryHeader : inkTextRef;
	private editable var m_mainWrapper : inkCompoundRef;
	private editable var m_emptyInventoryText : inkTextRef;
	private editable var m_filterButtonsGrid : inkCompoundRef;
	private editable var m_outfitsFilterInfoText : inkTextRef;
	private editable var m_prevFilterHint : inkWidgetRef;
	private editable var m_nextFilterHint : inkWidgetRef;
	private editable var m_itemGridContainer : inkWidgetRef;
	private editable var m_itemGridScrollControllerWidget : inkWidgetRef;
	private editable var m_wardrobeSlotsContainer : inkWidgetRef;
	private editable var m_wardrobeSlotsLabel : inkTextRef;
	private var m_buttonHintsController : weak< ButtonHints >;
	private var m_TooltipsManager : weak< gameuiTooltipsManager >;
	private var m_InventoryManager : InventoryDataManagerV2;
	private var m_player : weak< PlayerPuppet >;
	private var m_equipmentSystem : weak< EquipmentSystem >;
	private var m_transactionSystem : weak< TransactionSystem >;
	private var m_uiScriptableSystem : weak< UIScriptableSystem >;
	private var m_wardrobeSystem : weak< WardrobeSystem >;
	private var itemChooser : weak< InventoryGenericItemChooser >;
	private var m_lastEquipmentAreas : array< gamedataEquipmentArea >;
	private var m_currentHotkey : EHotkey;
	default m_currentHotkey = EHotkey.INVALID;
	private var m_inventoryController : weak< gameuiInventoryGameController >;
	private var m_itemsPositionProvider : ItemPositionProvider;
	var equipmentBlackboard : weak< IBlackboard >;
	var itemModsBlackboard : weak< IBlackboard >;
	var disassembleBlackboard : weak< IBlackboard >;
	var equipmentBlackboardCallback : CallbackHandle;
	var itemModsBlackboardCallback : CallbackHandle;
	var itemModsUpgradeBlackboardCallback : CallbackHandle;
	var disassembleBlackboardCallback : CallbackHandle;
	var equipmentInProgressCallback : CallbackHandle;
	var m_playerState : gamePSMVehicle;
	var m_itemGridClassifier : ItemModeGridClassifier;
	var m_itemGridDataView : ItemModeGridView;
	var m_itemGridDataSource : ScriptableDataSource;
	[ category = "FILTER" ]
	private var m_activeFilter : weak< BackpackFilterButtonController >;
	[ category = "FILTER" ]
	private var m_filters : array< weak< BackpackFilterButtonController > >;
	[ category = "FILTER" ]
	private var m_filterManager : ItemCategoryFliterManager;
	[ category = "FILTER" ]
	private var m_currentFilterIndex : Int32;
	[ category = "FILTER" ]
	private var m_savedFilter : ItemFilterCategory;
	private var m_lastSelectedDisplay : weak< InventoryItemDisplayController >;
	private var m_itemModeInventoryListenerCallback : ItemModeInventoryListenerCallback;
	private var m_itemModeInventoryListener : InventoryScriptListener;
	private var m_itemModeInventoryListenerRegistered : Bool;
	private var m_itemGridContainerController : weak< ItemModeGridContainer >;
	private var m_cyberwareGridContainerController : weak< ItemModeGridContainer >;
	private var m_comparisonResolver : ItemPreferredComparisonResolver;
	private var m_isE3Demo : Bool;
	var m_isShown : Bool;
	var m_itemDropQueue : array< ItemModParams >;
	private var m_confirmationPopupToken : inkGameNotificationToken;
	private var m_itemPreviewPopupToken : inkGameNotificationToken;
	private var m_lastItemHoverOverEvent : ItemDisplayHoverOverEvent;
	private var m_isComparisionDisabled : Bool;
	private var m_animContainer : inGameMenuAnimContainer;
	private var m_lastNotificationType : UIMenuNotificationType;
	private var m_outfitWardrobeSpawned : Bool;
	private var m_wardrobeOutfitSlotControllers : array< weak< WardrobeOutfitSlotController > >;
	private var m_delayedItemEquippedRequested : Bool;
	default m_delayedItemEquippedRequested = false;
	private var m_delaySystem : weak< DelaySystem >;
	private var m_delayedTimeoutCallbackId : DelayID;
	private var m_delayedOutfitCooldownResetCallbackId : DelayID;
	private var m_timeoutPeroid : Float;
	default m_timeoutPeroid = 0.5f;
	private var m_outfitInCooldown : Bool;
	default m_outfitInCooldown = false;
	private var m_outfitCooldownPeroid : Float;
	default m_outfitCooldownPeroid = 0.4f;
	private var m_tokenPopup : inkGameNotificationToken;
	private var m_refreshRequested : Bool;
	private var m_currentFilter : ItemFilterCategory;
	private var m_viewMode : ItemViewModes;
	private var m_currentItems : array< weak< WrappedInventoryItemData > >;
	private var m_previousSelectedItem : weak< InventoryItemDisplayController >;
	private var m_cursorData : MenuCursorUserData;
	private var m_pressedItemDisplay : weak< InventoryItemDisplayController >;

	protected event OnInitialize()
	{
		m_itemModeInventoryListenerCallback = new ItemModeInventoryListenerCallback;
		m_itemModeInventoryListenerCallback.Setup( ( ( weak< weak< InventoryItemModeLogicController > > )( this ) ) );
		inkCompoundRef.RemoveAllChildren( m_itemCategoryList );
		SetupVirutalGrid();
		inkWidgetRef.SetVisible( m_itemGridContainer, false );
		m_animContainer = new inGameMenuAnimContainer;
		RegisterToGlobalInputCallback( 'OnPostOnRelease', this, 'OnPostOnRelease' );
	}

	protected event OnUninitialize()
	{
		m_delaySystem.CancelCallback( m_delayedTimeoutCallbackId );
		m_delaySystem.CancelCallback( m_delayedOutfitCooldownResetCallbackId );
		UnregisterBlackboard();
		CleanupVirtualGrid();
		GameInstance.GetTransactionSystem( m_player.GetGame() ).UnregisterInventoryListener( m_player, m_itemModeInventoryListener );
		m_itemModeInventoryListener = NULL;
		m_itemModeInventoryListenerRegistered = false;
		UnregisterFromGlobalInputCallback( 'OnPostOnRelease', this, 'OnPostOnRelease' );
	}


	private var m_virtualGridInitialized : Bool;

	private function SetupVirutalGrid()
	{
		var virtualGrid : inkGridController;
		if( !( m_virtualGridInitialized ) )
		{
			m_itemGridContainerController = ( ( ItemModeGridContainer )( inkWidgetRef.GetController( m_itemGridContainer ) ) );
			m_itemGridClassifier = new ItemModeGridClassifier;
			m_itemGridDataView = new ItemModeGridView;
			m_itemGridDataSource = new ScriptableDataSource;
			m_itemsPositionProvider = new ItemPositionProvider;
			virtualGrid = ( ( inkGridController )( m_itemGridContainerController.GetItemsWidget().GetController() ) );
			virtualGrid.SetClassifier( m_itemGridClassifier );
			virtualGrid.SetSource( m_itemGridDataView );
			m_itemGridDataView.SetSource( m_itemGridDataSource );
			virtualGrid.SetProvider( m_itemsPositionProvider );
			virtualGrid.RegisterToCallback( 'OnAllElementsSpawned', this, 'OnAllElementsSpawned' );
			m_itemGridDataView.EnableSorting();
			m_virtualGridInitialized = true;
		}
	}

	private function CleanupVirtualGrid()
	{
		var virtualGrid : inkGridController;
		if( m_virtualGridInitialized )
		{
			m_itemGridDataView.SetSource( NULL );
			virtualGrid = ( ( inkGridController )( m_itemGridContainerController.GetItemsWidget().GetController() ) );
			virtualGrid.SetSource( NULL );
			virtualGrid.SetClassifier( NULL );
			virtualGrid.SetProvider( NULL );
			m_itemGridClassifier = NULL;
			m_itemGridDataView = NULL;
			m_itemGridDataSource = NULL;
			m_virtualGridInitialized = false;
		}
	}

	protected function RegisterBlackboard()
	{
		equipmentBlackboard = GameInstance.GetBlackboardSystem( m_player.GetGame() ).Get( GetAllBlackboardDefs().UI_Equipment );
		itemModsBlackboard = GameInstance.GetBlackboardSystem( m_player.GetGame() ).Get( GetAllBlackboardDefs().UI_ItemModSystem );
		disassembleBlackboard = GameInstance.GetBlackboardSystem( m_player.GetGame() ).Get( GetAllBlackboardDefs().UI_Crafting );
		if( equipmentBlackboard )
		{
			equipmentBlackboardCallback = equipmentBlackboard.RegisterListenerVariant( GetAllBlackboardDefs().UI_Equipment.itemEquipped, this, 'OnItemEquiped' );
			equipmentInProgressCallback = equipmentBlackboard.RegisterListenerBool( GetAllBlackboardDefs().UI_Equipment.EquipmentInProgress, this, 'OnEquipmentInProgress' );
		}
		if( itemModsBlackboard )
		{
			itemModsBlackboardCallback = itemModsBlackboard.RegisterListenerVariant( GetAllBlackboardDefs().UI_ItemModSystem.ItemModSystemUpdated, this, 'OnItemModUpdatedEquiped' );
			itemModsUpgradeBlackboardCallback = itemModsBlackboard.RegisterListenerBool( GetAllBlackboardDefs().UI_ItemModSystem.ItemModSystemUpgradingInProgress, this, 'OnItemModUpgradeInProgress' );
		}
		if( disassembleBlackboard )
		{
			disassembleBlackboardCallback = disassembleBlackboard.RegisterListenerVariant( GetAllBlackboardDefs().UI_Crafting.lastIngredients, this, 'OnDisassembleComplete', true );
		}
	}

	protected function UnregisterBlackboard()
	{
		if( equipmentBlackboard )
		{
			equipmentBlackboard.UnregisterListenerVariant( GetAllBlackboardDefs().UI_Equipment.itemEquipped, equipmentBlackboardCallback );
			equipmentBlackboard.UnregisterListenerBool( GetAllBlackboardDefs().UI_Equipment.EquipmentInProgress, equipmentInProgressCallback );
		}
		if( itemModsBlackboard )
		{
			itemModsBlackboard.UnregisterListenerVariant( GetAllBlackboardDefs().UI_ItemModSystem.ItemModSystemUpdated, itemModsBlackboardCallback );
			itemModsBlackboard.UnregisterListenerBool( GetAllBlackboardDefs().UI_ItemModSystem.ItemModSystemUpgradingInProgress, itemModsUpgradeBlackboardCallback );
		}
		if( disassembleBlackboard )
		{
			disassembleBlackboard.UnregisterListenerVariant( GetAllBlackboardDefs().UI_Crafting.lastIngredients, disassembleBlackboardCallback );
		}
	}

	public function SetSortMode( identifier : ItemSortMode )
	{
		m_itemGridDataView.SetSortMode( identifier );
	}

	protected event OnItemEquiped( value : Variant )
	{
		if( !( m_delayedItemEquippedRequested ) )
		{
			QueueEvent( new DelayedItemEquipped );
			m_delayedItemEquippedRequested = true;
		}
	}

	protected event OnEquipmentInProgress( inProgress : Bool )
	{
		var i, limit : Int32;
		var sets : array< ClothingSet >;
		var isSetDefined, isSetEquipped : Bool;
		var targetSet : gameWardrobeClothingSetIndex;
		var activeSet : weak< ClothingSet >;
		activeSet = m_wardrobeSystem.GetActiveClothingSet();
		sets = m_wardrobeSystem.GetClothingSets();
		for( i = 0, limit = m_wardrobeOutfitSlotControllers.Size(); i < limit; i += 1 )
		{
			targetSet = WardrobeSystem.NumberToWardrobeClothingSetIndex( m_wardrobeOutfitSlotControllers[ i ].GetIndex() );
			if( inProgress )
			{
				isSetDefined = false;
			}
			else
			{
				isSetDefined = IsWardrobeSetDefined( sets, targetSet );
			}
			if( activeSet == NULL )
			{
				isSetEquipped = false;
			}
			else
			{
				isSetEquipped = activeSet.setID == targetSet;
			}
			m_wardrobeOutfitSlotControllers[ i ].Update( isSetDefined, isSetEquipped );
		}
	}

	protected event OnDelayedItemEquipped( evt : DelayedItemEquipped )
	{
		var isOutfitItemEquipped : Bool;
		m_delayedItemEquippedRequested = false;
		if( !( m_equipmentSystem.GetPlayerData( m_player ).IsEquipPending() ) )
		{
			if( m_lastEquipmentAreas.Contains( gamedataEquipmentArea.Outfit ) )
			{
				isOutfitItemEquipped = ItemID.IsValid( m_InventoryManager.GetEquippedItemIdInArea( itemChooser.GetEquipmentArea(), itemChooser.GetSlotIndex() ) );
			}
			if( isOutfitItemEquipped )
			{
				UpdateOutfitWardrobe( true, -1 );
			}
			m_InventoryManager.RemoveInventoryItemFromCache( itemChooser.GetModifiedItemID() );
			itemChooser.RefreshItems();
			m_viewMode = ItemViewModes.Item;
			m_currentFilter = ItemFilterCategory.Invalid;
			RefreshAvailableItems();
			m_comparisonResolver.FlushCache();
		}
	}

	protected event OnPostOnRelease( evt : inkPointerEvent )
	{
		var setComparisionDisabledRequest : UIScriptableSystemSetComparisionTooltipDisabled;
		if( evt.IsAction( 'toggle_comparison_tooltip' ) )
		{
			m_isComparisionDisabled = !( m_isComparisionDisabled );
			m_buttonHintsController.AddButtonHint( 'toggle_comparison_tooltip', GetLocalizedText( ( ( m_isComparisionDisabled ) ? ( "UI-UserActions-EnableComparison" ) : ( "UI-UserActions-DisableComparison" ) ) ) );
			setComparisionDisabledRequest = new UIScriptableSystemSetComparisionTooltipDisabled;
			setComparisionDisabledRequest.value = m_isComparisionDisabled;
			m_uiScriptableSystem.QueueRequest( setComparisionDisabledRequest );
			InvalidateItemTooltipEvent();
		}
	}

	protected event OnItemModUpdatedEquiped( value : Variant )
	{
		var isMainItemSelected : Bool;
		isMainItemSelected = itemChooser.GetSelectedItem() == itemChooser.GetModifiedItem();
		itemChooser.RefreshSelectedItem();
		this.itemChooser.RefreshItems();
		m_viewMode = ( ( isMainItemSelected ) ? ( ItemViewModes.Item ) : ( ItemViewModes.Mod ) );
		m_currentFilter = ItemFilterCategory.Invalid;
		RefreshAvailableItems();
		NotifyItemUpdate();
	}

	protected event OnItemModUpgradeInProgress( value : Variant )
	{
		itemChooser.RefreshSelectedItem();
	}

	private function SelectMainItem()
	{
		if( itemChooser )
		{
			itemChooser.SelectMainItem();
		}
	}

	protected event OnItemChooserItemChanged( e : ItemChooserItemChanged )
	{
		var itemViewMode : ItemViewModes;
		var itemsToSkip : array< ItemID >;
		var isEquipped : Bool;
		var isPreviousDifferentFromCurrent : Bool;
		itemViewMode = ItemViewModes.Mod;
		if( !( TDBID.IsValid( e.slotID ) ) || ( e.slotID == TDBID.None() ) )
		{
			itemViewMode = ItemViewModes.Item;
		}
		if( e.itemEquipmentArea == gamedataEquipmentArea.Consumable || e.itemEquipmentArea == gamedataEquipmentArea.QuickSlot )
		{
			if( e.itemEquipmentArea == gamedataEquipmentArea.Consumable )
			{
				m_currentHotkey = EHotkey.DPAD_UP;
			}
			else if( e.itemEquipmentArea == gamedataEquipmentArea.QuickSlot )
			{
				m_currentHotkey = EHotkey.RB;
			}
			itemsToSkip.PushBack( itemChooser.GetSelectedItem().GetItemID() );
			SetEquipmentArea( e.itemEquipmentArea );
			UpdateAvailableHotykeyItems( m_currentHotkey, itemsToSkip );
		}
		else
		{
			m_currentHotkey = EHotkey.INVALID;
			SetEquipmentArea( e.itemEquipmentArea );
			m_viewMode = itemViewMode;
			if( m_viewMode == ItemViewModes.Mod )
			{
				m_currentFilter = ItemFilterCategory.Invalid;
			}
			else
			{
				if( !( IsEquipmentAreaWeapon( m_lastEquipmentAreas ) ) )
				{
					m_currentFilter = ItemFilterCategory.Invalid;
				}
			}
			RefreshAvailableItems();
		}
		isPreviousDifferentFromCurrent = m_previousSelectedItem.GetItemID() != itemChooser.GetSelectedItem().GetItemID();
		isEquipped = InventoryItemData.IsEquipped( m_previousSelectedItem.GetItemData() );
		if( isPreviousDifferentFromCurrent && !( isEquipped ) )
		{
			ResetScrollPosition();
		}
		m_previousSelectedItem = itemChooser.GetSelectedItem();
	}

	protected event OnDisassembleComplete( value : Variant )
	{
		if( itemChooser )
		{
			itemChooser.RefreshItems();
		}
	}

	private function ResetScrollPosition()
	{
		( ( inkScrollController )( inkWidgetRef.GetController( m_itemGridScrollControllerWidget ) ) ).SetScrollPosition( 0.0 );
	}

	private function UpdateOutfitWardrobe( active : Bool )
	{
		UpdateOutfitWardrobe( active, -2 );
	}

	private function UpdateOutfitWardrobe( active : Bool, activeSetOverride : Int32 )
	{
		var i, limit : Int32;
		var spawnData : OutfitWardrobeSlotSpawnData;
		var sets : array< ClothingSet >;
		var isSetDefined, isSetEquipped : Bool;
		var targetSet : gameWardrobeClothingSetIndex;
		var activeSet : weak< ClothingSet >;
		inkWidgetRef.SetVisible( m_wardrobeSlotsContainer, active );
		inkTextRef.SetVisible( m_wardrobeSlotsLabel, active );
		inkCompoundRef.SetVisible( m_filterButtonsGrid, !( active ) );
		inkTextRef.SetVisible( m_outfitsFilterInfoText, active );
		if( active )
		{
			sets = m_wardrobeSystem.GetClothingSets();
			if( activeSetOverride >= 0 )
			{
				activeSet = GetClothingSetByIndex( sets, activeSetOverride );
			}
			else if( activeSetOverride == -2 )
			{
				activeSet = m_wardrobeSystem.GetActiveClothingSet();
			}
			if( !( m_outfitWardrobeSpawned ) )
			{
				for( i = 0; i < 6; i += 1 )
				{
					targetSet = WardrobeSystem.NumberToWardrobeClothingSetIndex( i );
					spawnData = new OutfitWardrobeSlotSpawnData;
					spawnData.index = i;
					spawnData.active = IsWardrobeSetDefined( sets, targetSet );
					spawnData.isNew = m_uiScriptableSystem.IsWardrobeSetNew( targetSet );
					if( activeSet == NULL )
					{
						spawnData.equipped = false;
					}
					else
					{
						spawnData.equipped = activeSet.setID == targetSet;
					}
					AsyncSpawnFromLocal( inkWidgetRef.Get( m_wardrobeSlotsContainer ), 'wardrobeOutfitSlot', this, 'OnOutfitWardrobeSlotSpawned', spawnData );
				}
				m_outfitWardrobeSpawned = true;
			}
			else
			{
				for( i = 0, limit = m_wardrobeOutfitSlotControllers.Size(); i < limit; i += 1 )
				{
					targetSet = WardrobeSystem.NumberToWardrobeClothingSetIndex( m_wardrobeOutfitSlotControllers[ i ].GetIndex() );
					isSetDefined = IsWardrobeSetDefined( sets, targetSet );
					if( activeSet == NULL )
					{
						isSetEquipped = false;
					}
					else
					{
						isSetEquipped = activeSet.setID == targetSet;
					}
					m_wardrobeOutfitSlotControllers[ i ].Update( isSetDefined, isSetEquipped );
				}
			}
		}
	}

	private function GetClothingSetByIndex( const sets : ref< array< ClothingSet > >, targetIndex : Int32 ) : ClothingSet
	{
		var i, limit : Int32;
		var targetSet : gameWardrobeClothingSetIndex;
		targetSet = WardrobeSystem.NumberToWardrobeClothingSetIndex( targetIndex );
		for( i = 0, limit = sets.Size(); i < limit; i += 1 )
		{
			if( sets[ i ].setID == targetSet )
			{
				return sets[ i ];
			}
		}
		return NULL;
	}

	private function IsWardrobeSetDefined( const sets : ref< array< ClothingSet > >, targetSet : gameWardrobeClothingSetIndex ) : Bool
	{
		var i, limit : Int32;
		for( i = 0, limit = sets.Size(); i < limit; i += 1 )
		{
			if( sets[ i ].setID == targetSet )
			{
				return true;
			}
		}
		return false;
	}

	protected event OnWardrobeOutfitSlotClicked( e : WardrobeOutfitSlotClickedEvent )
	{
		if( m_InventoryManager.IsWardrobeEnabled() )
		{
			if( e.equipped )
			{
				WardrobeOutfitUnequipSet();
				UpdateOutfitWardrobe( true, -1 );
				itemChooser.RefreshItems( true, -1 );
			}
			else
			{
				WardrobeOutfitEquipSet( WardrobeSystem.NumberToWardrobeClothingSetIndex( e.index ) );
				UpdateOutfitWardrobe( true, e.index );
				itemChooser.RefreshItems( true, e.index );
			}
		}
		else
		{
			ShowNotification( m_player.GetGame(), UIMenuNotificationType.InventoryActionBlocked );
		}
	}

	protected event OnWardrobeOutfitSlotHoverOver( e : WardrobeOutfitSlotHoverOverEvent )
	{
		var dummyData : DummyTooltipData;
		var setInspectedEvent : UIScriptableSystemWardrobeSetInspected;
		dummyData = new DummyTooltipData;
		m_TooltipsManager.ShowTooltipAtWidget( 'outfitWardrobeInfoTooltip', e.evt.GetTarget(), dummyData, gameuiETooltipPlacement.RightTop );
		if( e.controller.IsNew() )
		{
			setInspectedEvent = new UIScriptableSystemWardrobeSetInspected;
			setInspectedEvent.wardrobeSet = WardrobeSystem.NumberToWardrobeClothingSetIndex( e.controller.GetIndex() );
			m_uiScriptableSystem.QueueRequest( setInspectedEvent );
			e.controller.SetIsNew( false );
		}
	}

	protected event OnWardrobeOutfitSlotHoverOut( e : WardrobeOutfitSlotHoverOutEvent )
	{
		m_TooltipsManager.HideTooltips();
	}

	private function WardrobeOutfitEquipSet( setID : gameWardrobeClothingSetIndex )
	{
		var req : EquipWardrobeSetRequest;
		req = new EquipWardrobeSetRequest;
		req.setID = setID;
		req.owner = m_player;
		if( m_delaySystem )
		{
			m_delaySystem.CancelCallback( m_delayedTimeoutCallbackId );
			m_delayedTimeoutCallbackId = m_delaySystem.DelayScriptableSystemRequest( 'EquipmentSystem', req, m_timeoutPeroid, false );
		}
	}

	private function WardrobeOutfitUnequipSet()
	{
		var req : UnequipWardrobeSetRequest;
		req = new UnequipWardrobeSetRequest;
		req.owner = m_player;
		if( m_delaySystem )
		{
			m_delaySystem.CancelCallback( m_delayedTimeoutCallbackId );
			m_delayedTimeoutCallbackId = m_delaySystem.DelayScriptableSystemRequest( 'EquipmentSystem', req, m_timeoutPeroid, false );
		}
	}

	protected event OnOutfitWardrobeSlotSpawned( widget : inkWidget, userData : IScriptable )
	{
		var controller : weak< WardrobeOutfitSlotController >;
		var spawnData : weak< OutfitWardrobeSlotSpawnData >;
		controller = ( ( WardrobeOutfitSlotController )( widget.GetController() ) );
		spawnData = ( ( OutfitWardrobeSlotSpawnData )( userData ) );
		m_wardrobeOutfitSlotControllers.PushBack( controller );
		controller.Setup( spawnData.index, spawnData.active, spawnData.equipped, spawnData.isNew );
	}

	private function SetEquipmentArea( equipmentArea : gamedataEquipmentArea )
	{
		var equipmentAreas : array< gamedataEquipmentArea >;
		equipmentAreas = m_inventoryController.GetEquipementAreaDisplays( equipmentArea ).equipmentAreas;
		SetupFiltersToCheck( ( ( equipmentAreas.Size() > 0 ) ? ( equipmentAreas[ 0 ] ) : ( gamedataEquipmentArea.Invalid ) ) );
		m_lastEquipmentAreas = equipmentAreas;
		UpdateOutfitWardrobe( m_lastEquipmentAreas.Contains( gamedataEquipmentArea.Outfit ) );
	}

	public function SetupData( buttonHints : weak< ButtonHints >, tooltipsManager : weak< gameuiTooltipsManager >, inventoryManager : InventoryDataManagerV2, player : weak< PlayerPuppet > )
	{
		m_TooltipsManager = tooltipsManager;
		m_buttonHintsController = buttonHints;
		m_InventoryManager = inventoryManager;
		m_player = player;
		m_isE3Demo = GameInstance.GetQuestsSystem( m_player.GetGame() ).GetFact( 'e3_2020' ) > 0;
		m_comparisonResolver = ItemPreferredComparisonResolver.Make( m_InventoryManager );
		m_equipmentSystem = ( ( EquipmentSystem )( GameInstance.GetScriptableSystemsContainer( m_player.GetGame() ).Get( 'EquipmentSystem' ) ) );
		m_transactionSystem = GameInstance.GetTransactionSystem( m_player.GetGame() );
		m_wardrobeSystem = GameInstance.GetWardrobeSystem( m_player.GetGame() );
		m_uiScriptableSystem = UIScriptableSystem.GetInstance( m_player.GetGame() );
		m_itemGridDataView.BindUIScriptableSystem( m_uiScriptableSystem );
		m_isComparisionDisabled = m_uiScriptableSystem.IsComparisionTooltipDisabled();
		m_playerState = ( ( gamePSMVehicle )( m_player.GetPlayerStateMachineBlackboard().GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vehicle ) ) );
		m_buttonHintsController.AddButtonHint( 'toggle_comparison_tooltip', GetLocalizedText( ( ( m_isComparisionDisabled ) ? ( "UI-UserActions-EnableComparison" ) : ( "UI-UserActions-DisableComparison" ) ) ) );
		m_delaySystem = GameInstance.GetDelaySystem( m_player.GetGame() );
		RegisterBlackboard();
		if( m_itemModeInventoryListener && m_itemModeInventoryListenerRegistered )
		{
			GameInstance.GetTransactionSystem( m_player.GetGame() ).UnregisterInventoryListener( m_player, m_itemModeInventoryListener );
			m_itemModeInventoryListenerRegistered = false;
			m_itemModeInventoryListener = NULL;
		}
		m_itemModeInventoryListener = GameInstance.GetTransactionSystem( m_player.GetGame() ).RegisterInventoryListener( m_player, m_itemModeInventoryListenerCallback );
		m_itemModeInventoryListenerRegistered = true;
		m_filterManager = ItemCategoryFliterManager.Make( true );
	}

	public function SetupMode( displayData : InventoryItemDisplayData, dataSource : InventoryDataManagerV2, optional inventoryController : weak< gameuiInventoryGameController > )
	{
		SetupVirutalGrid();
		itemChooser = CreateItemChooser( displayData, dataSource );
		m_inventoryController = inventoryController;
		inkTextRef.SetText( m_itemCategoryHeader, m_inventoryController.GetCategoryHeader( displayData ) );
		if( m_activeFilter )
		{
			m_activeFilter.SetActive( false );
			m_activeFilter = NULL;
		}
		m_itemGridDataView.SetFilterType( ItemFilterCategory.AllItems );
		ResetScrollPosition();
	}

	public function RequestClose() : Bool
	{
		var result : Bool;
		result = true;
		if( itemChooser )
		{
			result = itemChooser.RequestClose();
		}
		if( result )
		{
			inkCompoundRef.RemoveAllChildren( m_itemCategoryList );
		}
		CleanupVirtualGrid();
		return result;
	}

	public function SetTranslation( translation : Vector2 )
	{
		inkCompoundRef.SetTranslation( m_mainWrapper, translation );
	}

	public function CreateItemChooser( displayData : InventoryItemDisplayData, dataSource : InventoryDataManagerV2 ) : InventoryGenericItemChooser
	{
		var itemChooserToCreate : CName;
		var itemChooserRet : InventoryGenericItemChooser;
		var showTransmogedIcon : Bool;
		var isClothingArea : Bool;
		itemChooserToCreate = 'genericItemChooser';
		switch( displayData.m_equipmentArea )
		{
			case gamedataEquipmentArea.Weapon:
				itemChooserToCreate = 'weaponItemChooser';
			break;
			case gamedataEquipmentArea.SystemReplacementCW:
			case gamedataEquipmentArea.ArmsCW:
			case gamedataEquipmentArea.HandsCW:
			case gamedataEquipmentArea.EyesCW:
			case gamedataEquipmentArea.LegsCW:
			case gamedataEquipmentArea.MusculoskeletalSystemCW:
			case gamedataEquipmentArea.IntegumentarySystemCW:
			case gamedataEquipmentArea.NervousSystemCW:
			case gamedataEquipmentArea.FrontalCortexCW:
			case gamedataEquipmentArea.CardiovascularSystemCW:
			case gamedataEquipmentArea.ImmuneSystemCW:
				itemChooserToCreate = 'cyberwareModsChooser';
			break;
		}
		inkCompoundRef.RemoveAllChildren( m_itemCategoryList );
		isClothingArea = IsEquipmentAreaClothing( displayData.m_equipmentArea );
		if( isClothingArea && m_wardrobeSystem.GetActiveClothingSetIndex() != gameWardrobeClothingSetIndex.INVALID )
		{
			showTransmogedIcon = true;
		}
		itemChooserRet = ( ( InventoryGenericItemChooser )( SpawnFromLocal( inkCompoundRef.Get( m_itemCategoryList ), itemChooserToCreate ).GetController() ) );
		itemChooserRet.Bind( m_player, dataSource, displayData.m_equipmentArea, displayData.m_slotIndex, m_TooltipsManager, showTransmogedIcon );
		itemChooserRet.BindUIScriptableSystem( m_uiScriptableSystem );
		return itemChooserRet;
	}

	public function GetEquipmentAreas() : array< gamedataEquipmentArea >
	{
		return m_lastEquipmentAreas;
	}

	public function IsOutfitMode() : Bool
	{
		return m_lastEquipmentAreas.Contains( gamedataEquipmentArea.Outfit );
	}

	private function SetupFiltersToCheck( equipmentArea : gamedataEquipmentArea )
	{
		m_filterManager.Clear( true );
		if( equipmentArea == gamedataEquipmentArea.Weapon )
		{
			m_filterManager.AddFilterToCheck( ItemFilterCategory.RangedWeapons );
			m_filterManager.AddFilterToCheck( ItemFilterCategory.MeleeWeapons );
			m_filterManager.AddFilterToCheck( ItemFilterCategory.SoftwareMods );
			m_filterManager.AddFilterToCheck( ItemFilterCategory.Attachments );
		}
		else if( IsEquipmentAreaClothing( equipmentArea ) )
		{
			m_filterManager.AddFilterToCheck( ItemFilterCategory.Clothes );
			m_filterManager.AddFilterToCheck( ItemFilterCategory.SoftwareMods );
			m_filterManager.AddFilterToCheck( ItemFilterCategory.Attachments );
		}
	}

	private function CreateFilterButtons( targetWidget : inkCompoundRef, optional equipmentArea : gamedataEquipmentArea )
	{
		var i : Int32;
		var filters : array< ItemFilterCategory >;
		var filterButton : BackpackFilterButtonController;
		if( !( m_lastEquipmentAreas.Contains( equipmentArea ) ) )
		{
			filters = m_filterManager.GetSortedFiltersList();
			inkCompoundRef.RemoveAllChildren( m_filterButtonsGrid );
			for( i = 0; i < filters.Size(); i += 1 )
			{
				filterButton = ( ( BackpackFilterButtonController )( SpawnFromLocal( ( ( weak< weak< inkCompoundWidget > > )( inkCompoundRef.Get( targetWidget ) ) ), 'filterButtonItem' ).GetController() ) );
				filterButton.RegisterToCallback( 'OnRelease', this, 'OnItemFilterClick' );
				filterButton.RegisterToCallback( 'OnHoverOver', this, 'OnItemFilterHoverOver' );
				filterButton.RegisterToCallback( 'OnHoverOut', this, 'OnItemFilterHoverOut' );
				filterButton.Setup( filters[ i ] );
				if( filters[ i ] == m_savedFilter )
				{
					filterButton.SetActive( true );
					m_activeFilter = filterButton;
				}
				m_filters.PushBack( filterButton );
				inkWidgetRef.SetVisible( m_prevFilterHint, i > 0 );
				inkWidgetRef.SetVisible( m_nextFilterHint, i > 0 );
			}
		}
	}

	private function SelectFilterButton( targetFilter : ItemFilterCategory )
	{
		var i : Int32;
		var controller : BackpackFilterButtonController;
		for( i = 0; i < inkCompoundRef.GetNumChildren( m_filterButtonsGrid ); i += 1 )
		{
			controller = ( ( BackpackFilterButtonController )( inkCompoundRef.GetWidgetByIndex( m_filterButtonsGrid, i ).GetController() ) );
			if( controller.GetFilterType() == targetFilter )
			{
				SetActiveFilterController( controller );
			}
		}
	}

	private function GetFilterButtonIndex( targetFilter : ItemFilterCategory ) : Int32
	{
		var i : Int32;
		var controller : BackpackFilterButtonController;
		for( i = 0; i < inkCompoundRef.GetNumChildren( m_filterButtonsGrid ); i += 1 )
		{
			controller = ( ( BackpackFilterButtonController )( inkCompoundRef.GetWidgetByIndex( m_filterButtonsGrid, i ).GetController() ) );
			if( controller.GetFilterType() == targetFilter )
			{
				return i;
			}
		}
		return -1;
	}

	private function SelectFilterButtonByIndex( index : Int32 )
	{
		var controller : BackpackFilterButtonController;
		if( ( index >= 0 ) && ( index < inkCompoundRef.GetNumChildren( m_filterButtonsGrid ) ) )
		{
			controller = ( ( BackpackFilterButtonController )( inkCompoundRef.GetWidgetByIndex( m_filterButtonsGrid, index ).GetController() ) );
			SetActiveFilterController( controller );
			m_currentFilterIndex = index;
		}
	}

	protected event OnFilterHotkeyPressed( evt : inkPointerEvent )
	{
		if( ( m_itemPreviewPopupToken == NULL ) && inkWidgetRef.IsVisible( m_prevFilterHint ) )
		{
			if( evt.IsAction( 'option_switch_next_settings' ) )
			{
				NavigateFilters( ECustomFilterDPadNavigationOption.SelectNext );
				PlaySound( 'Button', 'OnPress' );
			}
			else if( evt.IsAction( 'option_switch_prev_settings' ) )
			{
				PlaySound( 'Button', 'OnPress' );
				NavigateFilters( ECustomFilterDPadNavigationOption.SelectPrev );
			}
		}
	}

	private function NavigateFilters( option : ECustomFilterDPadNavigationOption )
	{
		var filtersAmount : Int32;
		filtersAmount = inkCompoundRef.GetNumChildren( m_filterButtonsGrid );
		switch( option )
		{
			case ECustomFilterDPadNavigationOption.SelectNext:
				m_currentFilterIndex = ( ( m_currentFilterIndex < ( filtersAmount - 1 ) ) ? ( m_currentFilterIndex + 1 ) : ( 0 ) );
			break;
			case ECustomFilterDPadNavigationOption.SelectPrev:
				m_currentFilterIndex = ( ( m_currentFilterIndex > 0 ) ? ( m_currentFilterIndex - 1 ) : ( filtersAmount - 1 ) );
			break;
		}
		SelectFilterButtonByIndex( m_currentFilterIndex );
	}

	protected event OnItemFilterClick( evt : inkPointerEvent )
	{
		var widget : inkWidget;
		var controller : BackpackFilterButtonController;
		if( evt.IsAction( 'click' ) )
		{
			widget = evt.GetCurrentTarget();
			controller = ( ( BackpackFilterButtonController )( widget.GetController() ) );
			SetActiveFilterController( controller );
			PlayLibraryAnimation( 'inventory_grid_filter_change' );
			PlaySound( 'Button', 'OnPress' );
		}
	}

	private function SetActiveFilterController( controller : BackpackFilterButtonController )
	{
		if( m_activeFilter )
		{
			m_activeFilter.SetActive( false );
		}
		m_activeFilter = controller;
		m_activeFilter.SetActive( true );
		m_savedFilter = controller.GetFilterType();
		m_currentFilter = m_savedFilter;
		m_itemGridDataView.SetFilterTypeAndSortMode( controller.GetFilterType(), m_itemGridDataView.GetSortMode() );
	}

	protected event OnItemFilterHoverOver( evt : inkPointerEvent )
	{
		var widget : inkWidget;
		var tooltipData : MessageTooltipData;
		var controller : BackpackFilterButtonController;
		widget = evt.GetCurrentTarget();
		controller = ( ( BackpackFilterButtonController )( widget.GetController() ) );
		tooltipData = new MessageTooltipData;
		tooltipData.Title = NameToString( controller.GetLabelKey() );
		m_TooltipsManager.ShowTooltipAtWidget( 0, evt.GetTarget(), tooltipData, gameuiETooltipPlacement.RightTop, true );
	}

	protected event OnItemFilterHoverOut( evt : inkPointerEvent )
	{
		m_TooltipsManager.HideTooltips();
	}

	private function IsEquipmentAreaWeapon( const equipmentAreas : ref< array< gamedataEquipmentArea > > ) : Bool
	{
		var i : Int32;
		for( i = 0; i < equipmentAreas.Size(); i += 1 )
		{
			if( IsEquipmentAreaWeapon( equipmentAreas[ i ] ) )
			{
				return true;
			}
		}
		return false;
	}

	private function IsEquipmentAreaWeapon( equipmentArea : gamedataEquipmentArea ) : Bool
	{
		return equipmentArea == gamedataEquipmentArea.Weapon;
	}

	private function IsEquipmentAreaClothing( const equipmentAreas : ref< array< gamedataEquipmentArea > > ) : Bool
	{
		var i : Int32;
		for( i = 0; i < equipmentAreas.Size(); i += 1 )
		{
			if( IsEquipmentAreaClothing( equipmentAreas[ i ] ) )
			{
				return true;
			}
		}
		return false;
	}

	private function IsEquipmentAreaClothing( equipmentArea : gamedataEquipmentArea ) : Bool
	{
		return ( ( ( ( equipmentArea == gamedataEquipmentArea.Head || equipmentArea == gamedataEquipmentArea.Face ) || equipmentArea == gamedataEquipmentArea.OuterChest ) || equipmentArea == gamedataEquipmentArea.InnerChest ) || equipmentArea == gamedataEquipmentArea.Legs ) || equipmentArea == gamedataEquipmentArea.Feet;
	}

	public function UpdateDisplayedItems( itemID : ItemID, optional tryToPreserveFilter : Bool )
	{
		var i : Int32;
		var itemEquipArea : gamedataEquipmentArea;
		var scopes : array< gamedataItemType >;
		var itemRecord : Item_Record;
		var doRefresh : Bool;
		var selectedSlot : TweakDBID;
		var itemViewMode : ItemViewModes;
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) );
		selectedSlot = itemChooser.GetSelectedSlotID();
		if( itemRecord )
		{
			itemViewMode = ItemViewModes.Mod;
			if( !( TDBID.IsValid( selectedSlot ) ) || ( selectedSlot == TDBID.None() ) )
			{
				itemViewMode = ItemViewModes.Item;
			}
			if( m_currentHotkey == EHotkey.INVALID )
			{
				if( ( itemRecord.TagsContains( 'itemPart' ) || itemRecord.TagsContains( 'Fragment' ) ) || itemRecord.TagsContains( 'SoftwareShard' ) )
				{
					doRefresh = true;
				}
				itemEquipArea = itemRecord.EquipArea().Type();
				for( i = 0; i < m_lastEquipmentAreas.Size(); i += 1 )
				{
					if( m_lastEquipmentAreas[ i ] == itemEquipArea )
					{
						doRefresh = true;
					}
				}
			}
			else
			{
				scopes = Hotkey.GetScope( m_currentHotkey );
				if( scopes.Contains( itemRecord.ItemType().Type() ) )
				{
					doRefresh = true;
				}
			}
		}
		if( doRefresh )
		{
			m_InventoryManager.MarkToRebuild();
			m_viewMode = itemViewMode;
			RefreshAvailableItems();
		}
	}

	protected event OnDelayedRefreshItems( evt : DelayedRefreshItems )
	{
		m_refreshRequested = false;
		UpdateAvailableItems();
	}

	private function RefreshAvailableItems()
	{
		var itemsToSkip : array< ItemID >;
		if( m_currentHotkey == EHotkey.INVALID )
		{
			if( !( m_refreshRequested ) )
			{
				m_refreshRequested = true;
				QueueEvent( new DelayedRefreshItems );
			}
		}
		else
		{
			itemsToSkip.PushBack( m_equipmentSystem.GetPlayerData( m_player ).GetItemIDFromHotkey( m_currentHotkey ) );
			UpdateAvailableHotykeyItems( m_currentHotkey, itemsToSkip );
		}
	}

	private function UpdateAvailableHotykeyItems( hotkey : EHotkey, optional itemsToSkip : array< ItemID > )
	{
		var i : Int32;
		var k : Int32;
		var slotTypes : array< gamedataItemType >;
		var freshItems : array< InventoryItemData >;
		var totalItems : array< InventoryItemData >;
		var currentItemID : ItemID;
		var itemType : gamedataItemType;
		slotTypes = Hotkey.GetScope( hotkey );
		for( i = 0; i < slotTypes.Size(); i += 1 )
		{
			freshItems = m_InventoryManager.GetPlayerItemsByType( slotTypes[ i ], , , m_itemDropQueue );
			for( k = 0; k < freshItems.Size(); k += 1 )
			{
				currentItemID = InventoryItemData.GetID( freshItems[ k ] );
				if( !( ItemID.IsValid( currentItemID ) ) || totalItems.Contains( freshItems[ k ] ) )
				{
					continue;
				}
				if( itemsToSkip.Contains( currentItemID ) )
				{
					continue;
				}
				itemType = m_transactionSystem.GetItemData( m_player, currentItemID ).GetItemType();
				if( itemType == gamedataItemType.Cyb_Ability || itemType == gamedataItemType.Cyb_Launcher )
				{
					if( !( m_equipmentSystem.IsEquipped( m_player, currentItemID ) ) )
					{
						continue;
					}
				}
				if( itemType == gamedataItemType.Cyb_HealingAbility && !( RPGManager.IsItemEquipped( m_player, currentItemID ) ) )
				{
					continue;
				}
				InventoryItemData.SetIsEquipped( freshItems[ k ], false );
				totalItems.PushBack( freshItems[ k ] );
			}
		}
		UpdateAvailableItemsGrid( totalItems );
		CreateFilterButtons( m_itemGridContainerController.GetFiltersGrid() );
	}

	private function UpdateAvailableItems()
	{
		var i : Int32;
		var availableItems : array< InventoryItemData >;
		var isWeapon, isClothing, isOutfit : Bool;
		var attachments : array< InventoryItemAttachments >;
		var attachmentsToCheck : array< TweakDBID >;
		var targetFilter : Int32;
		isWeapon = IsEquipmentAreaWeapon( m_lastEquipmentAreas );
		isClothing = IsEquipmentAreaClothing( m_lastEquipmentAreas );
		isOutfit = m_lastEquipmentAreas.Contains( gamedataEquipmentArea.Outfit );
		m_itemGridContainerController.SetSize( ( ( isOutfit ) ? ( ItemModeGridSize.Outfit ) : ( ItemModeGridSize.Default ) ) );
		if( isWeapon || isClothing )
		{
			m_InventoryManager.GetPlayerInventoryDataRef( m_lastEquipmentAreas, true, m_itemDropQueue, availableItems );
			attachments = InventoryItemData.GetAttachments( itemChooser.GetModifiedItemData() );
			if( TDBID.IsValid( itemChooser.GetSelectedSlotID() ) )
			{
				attachmentsToCheck.PushBack( itemChooser.GetSelectedSlotID() );
			}
			else
			{
				for( i = 0; i < attachments.Size(); i += 1 )
				{
					if( attachments[ i ].SlotType == InventoryItemAttachmentType.Generic )
					{
						attachmentsToCheck.PushBack( attachments[ i ].SlotID );
					}
				}
			}
			m_InventoryManager.GetPlayerInventoryPartsForItemRef( itemChooser.GetModifiedItemID(), attachmentsToCheck, availableItems );
		}
		else
		{
			if( m_viewMode == ItemViewModes.Mod )
			{
				availableItems = m_InventoryManager.GetPlayerInventoryPartsForItem( ( ( InventoryCyberwareItemChooser )( itemChooser ) ).GetModifiedItemID(), itemChooser.GetSelectedItem().GetSlotID() );
			}
			else
			{
				m_InventoryManager.GetPlayerInventoryDataRef( m_lastEquipmentAreas, true, m_itemDropQueue, availableItems );
			}
		}
		m_itemGridDataView.DisableSorting();
		UpdateAvailableItemsGrid( availableItems );
		CreateFilterButtons( m_itemGridContainerController.GetFiltersGrid() );
		m_itemGridDataView.EnableSorting();
		if( isWeapon || isClothing )
		{
			m_lastSelectedDisplay = itemChooser.GetSelectedItem();
			if( m_viewMode == ItemViewModes.Mod && ( GetFilterButtonIndex( ItemFilterCategory.Attachments ) >= 0 ) )
			{
				SelectFilterButton( ItemFilterCategory.Attachments );
			}
			else
			{
				targetFilter = -1;
				if( isWeapon )
				{
					if( m_currentFilter == ItemFilterCategory.RangedWeapons && ( GetFilterButtonIndex( ItemFilterCategory.RangedWeapons ) >= 0 ) )
					{
						targetFilter = GetFilterButtonIndex( ItemFilterCategory.RangedWeapons );
					}
					else if( m_currentFilter == ItemFilterCategory.MeleeWeapons && ( GetFilterButtonIndex( ItemFilterCategory.MeleeWeapons ) >= 0 ) )
					{
						targetFilter = GetFilterButtonIndex( ItemFilterCategory.MeleeWeapons );
					}
				}
				else if( isClothing )
				{
					targetFilter = GetFilterButtonIndex( ItemFilterCategory.Clothes );
				}
				if( targetFilter == -1 )
				{
					targetFilter = 0;
				}
				SelectFilterButtonByIndex( targetFilter );
			}
		}
		else
		{
			m_itemGridDataView.Sort();
		}
	}

	private function UpdateAvailableItemsGrid( availableItems : ref< array< InventoryItemData > > )
	{
		var i : Int32;
		var equipmentArea : gamedataEquipmentArea;
		var virtualWrappedData : array< IScriptable >;
		var data : WrappedInventoryItemData;
		var itemChooserItem : InventoryItemData;
		var sortData : InventoryItemSortData;
		m_currentItems.Clear();
		inkTextRef.SetVisible( m_emptyInventoryText, availableItems.Size() <= 0 );
		( ( weak< weak< inkCompoundWidget > > )( m_cyberwareGridContainerController.GetItemsWidget() ) ).RemoveAllChildren();
		inkWidgetRef.SetVisible( m_itemGridContainer, true );
		itemChooserItem = itemChooser.GetSelectedItem().GetItemData();
		if( InventoryItemData.IsEmpty( itemChooserItem ) )
		{
			m_comparisonResolver.ForceDisableComparison();
		}
		else
		{
			m_comparisonResolver.ForceComparedItem( itemChooserItem );
		}
		for( i = 0; i < availableItems.Size(); i += 1 )
		{
			data = new WrappedInventoryItemData;
			data.ItemData = availableItems[ i ];
			equipmentArea = InventoryItemData.GetEquipmentArea( data.ItemData );
			data.ItemTemplate = ( ( equipmentArea == gamedataEquipmentArea.Weapon ) ? ( ( ( Uint32 )( 1 ) ) ) : ( ( ( Uint32 )( 0 ) ) ) );
			data.ComparisonState = ( ( !( IsEquipmentAreaClothing( equipmentArea ) ) ) ? ( m_comparisonResolver.GetItemComparisonState( data.ItemData ) ) : ( ItemComparisonState.Default ) );
			data.IsNew = m_uiScriptableSystem.IsInventoryItemNew( InventoryItemData.GetID( availableItems[ i ] ) );
			data.IsPlayerFavourite = m_uiScriptableSystem.IsItemPlayerFavourite( InventoryItemData.GetID( availableItems[ i ] ) );
			InventoryItemData.SetGameItemData( data.ItemData, m_InventoryManager.GetPlayerItemData( InventoryItemData.GetID( availableItems[ i ] ) ) );
			sortData = InventoryItemData.GetSortData( data.ItemData );
			if( sortData.Name == "" )
			{
				sortData = ItemCompareBuilder.BuildInventoryItemSortData( data.ItemData, m_uiScriptableSystem );
				InventoryItemData.SetSortData( data.ItemData, sortData );
			}
			if( m_currentHotkey == EHotkey.INVALID )
			{
				data.DisplayContext = ItemDisplayContext.Backpack;
			}
			m_currentItems.PushBack( data );
			virtualWrappedData.PushBack( ( ( IScriptable )( data ) ) );
			m_filterManager.AddItem( InventoryItemData.GetGameItemData( data.ItemData ) );
		}
		m_itemGridDataSource.Reset( virtualWrappedData );
	}

	private function UnequipItem( controller : InventoryItemDisplayController, const itemData : ref< InventoryItemData > )
	{
		m_InventoryManager.UnequipItem( controller.GetEquipmentArea(), controller.GetSlotIndex() );
		m_InventoryManager.RemoveInventoryItemFromCache( controller.GetItemID() );
	}

	private function UninstallMod( itemID : ItemID, slotID : TweakDBID )
	{
		var removePartRequest : RemoveItemPart;
		removePartRequest = new RemoveItemPart;
		removePartRequest.obj = m_player;
		removePartRequest.baseItem = itemID;
		removePartRequest.slotToEmpty = slotID;
		GameInstance.GetScriptableSystemsContainer( m_player.GetGame() ).Get( 'ItemModificationSystem' ).QueueRequest( removePartRequest );
	}


	private var m_replaceModNotification : inkGameNotificationToken;
	private var m_installModData : InstallModConfirmationData;

	private function EquipPart( const itemData : ref< InventoryItemData >, slotID : TweakDBID )
	{
		var equippedItemData : InventoryItemData;
		var localEquippedData : weak< gameItemData >;
		var modItemType : gamedataItemType;
		var isPartEquipped, isIconicWeapon : Bool;
		equippedItemData = itemChooser.GetModifiedItemData();
		localEquippedData = InventoryItemData.GetGameItemData( equippedItemData );
		if( m_InventoryManager.CanInstallPart( itemData ) )
		{
			modItemType = InventoryItemData.GetItemType( itemData );
			isPartEquipped = localEquippedData.HasPartInSlot( slotID );
			isIconicWeapon = localEquippedData.HasTag( 'IconicWeapon' );
			if( isPartEquipped && ( RPGManager.IsClothingMod( modItemType ) || ( isIconicWeapon && RPGManager.IsWeaponMod( modItemType ) ) ) )
			{
				m_installModData = new InstallModConfirmationData;
				m_installModData.itemId = InventoryItemData.GetID( equippedItemData );
				m_installModData.partId = InventoryItemData.GetID( itemData );
				m_installModData.slotID = slotID;
				m_installModData.telemetryItemData = ToTelemetryInventoryItem( equippedItemData );
				m_installModData.telemetryPartData = ToTelemetryInventoryItem( itemData );
				m_replaceModNotification = GenericMessageNotification.Show( m_inventoryController, "Gameplay-Scanning-NPC-Warning", "UI-Notifications-ReplaceMod", GenericMessageNotificationType.YesNo );
				m_replaceModNotification.RegisterListener( this, 'OnReplaceModNotificationClosed' );
			}
			else if( isPartEquipped && RPGManager.IsWeaponMod( modItemType ) )
			{
				ShowNotification( m_player.GetGame(), UIMenuNotificationType.InventoryNoFreeSlot );
			}
			else
			{
				m_InventoryManager.InstallPart( InventoryItemData.GetID( equippedItemData ), InventoryItemData.GetID( itemData ), slotID );
				TelemetryLogPartInstalled( equippedItemData, itemData, slotID );
				SetPingTutorialFact( InventoryItemData.GetID( itemData ), false );
			}
		}
	}

	private function SetPingTutorialFact( itemID : ItemID, isUnequip : Bool )
	{
		var shard : CName;
		var questSystem : QuestsSystem;
		shard = TweakDBInterface.GetCName( ItemID.GetTDBID( itemID ) + T".shardType", '' );
		if( shard == 'Ping' )
		{
			questSystem = GameInstance.GetQuestsSystem( m_player.GetGame() );
			if( isUnequip && ( questSystem.GetFact( 'ping_installed' ) == 1 ) )
			{
				questSystem.SetFact( 'ping_installed', 0 );
			}
			else if( questSystem.GetFact( 'ping_installed' ) == 0 )
			{
				questSystem.SetFact( 'ping_installed', 1 );
			}
		}
	}

	private function TelemetryLogPartInstalled( const modifiedItem : ref< InventoryItemData >, const itemPart : ref< InventoryItemData >, slotID : TweakDBID )
	{
		TelemetryLogPartInstalled( ToTelemetryInventoryItem( modifiedItem ), ToTelemetryInventoryItem( itemPart ), slotID );
	}

	private function TelemetryLogPartInstalled( const modifiedItem : ref< TelemetryInventoryItem >, const itemPart : ref< TelemetryInventoryItem >, slotID : TweakDBID )
	{
		var telemetrySystem : weak< TelemetrySystem >;
		telemetrySystem = GameInstance.GetTelemetrySystem( m_player.GetGame() );
		if( telemetrySystem )
		{
			telemetrySystem.LogPartInstalled( modifiedItem, itemPart, slotID );
		}
	}

	protected event OnReplaceModNotificationClosed( data : inkGameNotificationData )
	{
		var closeData : GenericMessageNotificationCloseData;
		closeData = ( ( GenericMessageNotificationCloseData )( data ) );
		m_replaceModNotification = NULL;
		if( closeData && closeData.result == GenericMessageNotificationResult.Yes )
		{
			m_InventoryManager.InstallPart( m_installModData.itemId, m_installModData.partId, m_installModData.slotID );
			TelemetryLogPartInstalled( m_installModData.telemetryItemData, m_installModData.telemetryPartData, m_installModData.slotID );
		}
		m_installModData = NULL;
	}

	private function GetMatchingSlot( const itemData : ref< InventoryItemData >, const partItemData : ref< InventoryItemData > ) : TweakDBID
	{
		var i, j : Int32;
		var partType : gamedataItemType;
		var attachments : array< InventoryItemAttachments >;
		var availableSlots : array< TweakDBID >;
		var firstMatching : TweakDBID;
		attachments = InventoryItemData.GetAttachments( itemData );
		partType = InventoryItemData.GetItemType( partItemData );
		if( RPGManager.IsScopeAttachment( partType ) )
		{
			for( i = 0; i < attachments.Size(); i += 1 )
			{
				if( attachments[ i ].SlotID == T"AttachmentSlots.Scope" )
				{
					return T"AttachmentSlots.Scope";
				}
			}
		}
		else if( ( partType == gamedataItemType.Prt_Muzzle || partType == gamedataItemType.Prt_HandgunMuzzle ) || partType == gamedataItemType.Prt_RifleMuzzle )
		{
			for( i = 0; i < attachments.Size(); i += 1 )
			{
				if( attachments[ i ].SlotID == T"AttachmentSlots.PowerModule" )
				{
					return T"AttachmentSlots.PowerModule";
				}
			}
		}
		else if( RPGManager.IsWeaponMod( partType ) || RPGManager.IsClothingMod( partType ) )
		{
			availableSlots = RPGManager.GetModsSlotIDs( InventoryItemData.GetItemType( itemData ) );
			firstMatching = TDBID.None();
			for( i = 0; i < availableSlots.Size(); i += 1 )
			{
				for( j = 0; j < attachments.Size(); j += 1 )
				{
					if( attachments[ j ].SlotID == availableSlots[ i ] )
					{
						if( !( TDBID.IsValid( firstMatching ) ) )
						{
							firstMatching = attachments[ j ].SlotID;
						}
						if( InventoryItemData.IsEmpty( attachments[ j ].ItemData ) )
						{
							return attachments[ j ].SlotID;
						}
					}
				}
			}
			if( TDBID.IsValid( firstMatching ) )
			{
				return firstMatching;
			}
		}
		return TDBID.None();
	}

	private function IsMatchingSlot( const itemData : ref< InventoryItemData >, const partItemData : ref< InventoryItemData >, targetSlot : TweakDBID ) : Bool
	{
		var i : Int32;
		var partType : gamedataItemType;
		var attachments : array< InventoryItemAttachments >;
		var hasTargetSlot : Bool;
		var validSlots : array< TweakDBID >;
		attachments = InventoryItemData.GetAttachments( itemData );
		partType = InventoryItemData.GetItemType( partItemData );
		for( i = 0; i < attachments.Size(); i += 1 )
		{
			if( attachments[ i ].SlotID == targetSlot )
			{
				hasTargetSlot = true;
			}
		}
		if( !( hasTargetSlot ) )
		{
			return false;
		}
		if( RPGManager.IsScopeAttachment( partType ) )
		{
			if( targetSlot != T"AttachmentSlots.Scope" )
			{
				return false;
			}
		}
		else if( ( partType == gamedataItemType.Prt_Muzzle || partType == gamedataItemType.Prt_HandgunMuzzle ) || partType == gamedataItemType.Prt_RifleMuzzle )
		{
			if( targetSlot != T"AttachmentSlots.PowerModule" )
			{
				return false;
			}
		}
		else if( RPGManager.IsWeaponMod( partType ) || RPGManager.IsClothingMod( partType ) )
		{
			validSlots = RPGManager.GetModsSlotIDs( InventoryItemData.GetItemType( itemData ) );
			if( !( validSlots.Contains( targetSlot ) ) )
			{
				return false;
			}
		}
		return true;
	}

	private function EquipItem( const itemData : ref< InventoryItemData >, slotIndex : Int32 )
	{
		var hotkey : EHotkey;
		var slot : TweakDBID;
		if( InventoryItemData.IsPart( itemData ) )
		{
			slot = itemChooser.GetSelectedSlotID();
			if( TDBID.IsValid( slot ) && !( IsMatchingSlot( itemChooser.GetModifiedItemData(), itemData, slot ) ) )
			{
				slot = TDBID.None();
			}
			if( !( TDBID.IsValid( slot ) ) )
			{
				slot = GetMatchingSlot( itemChooser.GetModifiedItemData(), itemData );
			}
			EquipPart( itemData, slot );
			PlaySound( 'Item', 'OnBuy' );
			return;
		}
		m_InventoryManager.GetHotkeyTypeForItemID( InventoryItemData.GetID( itemData ), hotkey );
		if( InventoryItemData.IsEquipped( itemData ) && hotkey == EHotkey.INVALID )
		{
			return;
		}
		if( hotkey != EHotkey.INVALID )
		{
			m_equipmentSystem.GetPlayerData( m_player ).AssignItemToHotkey( InventoryItemData.GetID( itemData ), hotkey );
			m_viewMode = ItemViewModes.Item;
			m_currentFilter = ItemFilterCategory.Invalid;
			RefreshAvailableItems();
			NotifyItemUpdate();
			return;
		}
		if( !( InventoryItemData.IsEmpty( itemData ) ) )
		{
			m_InventoryManager.EquipItem( InventoryItemData.GetID( itemData ), slotIndex );
			PlaySound( 'Item', 'OnBuy' );
			PlayRumble( RumbleStrength.Heavy, RumbleType.Pulse, RumblePosition.Right );
		}
	}

	private function NotifyItemUpdate()
	{
		var itemChangedEvent : ItemModeItemChanged;
		var equipmentArea : gamedataEquipmentArea;
		itemChangedEvent = new ItemModeItemChanged;
		equipmentArea = itemChooser.GetEquipmentArea();
		if( m_currentHotkey == EHotkey.DPAD_UP )
		{
			equipmentArea = gamedataEquipmentArea.Consumable;
		}
		else if( m_currentHotkey == EHotkey.RB )
		{
			equipmentArea = gamedataEquipmentArea.QuickSlot;
		}
		itemChangedEvent.equipmentArea = equipmentArea;
		itemChangedEvent.slotIndex = itemChooser.GetSlotIndex();
		itemChangedEvent.hotkey = m_currentHotkey;
		QueueEvent( itemChangedEvent );
	}

	protected event OnItemChooserUnequipMod( ev : ItemChooserUnequipMod )
	{
		var modifiedItem : InventoryItemData;
		modifiedItem = itemChooser.GetModifiedItemData();
		if( !( modifiedItem.Empty ) && ( RPGManager.CanPartBeUnequipped( itemChooser.GetSelectedItem().GetItemData(), ev.slotID ) || modifiedItem.EquipmentArea == gamedataEquipmentArea.SystemReplacementCW ) )
		{
			UninstallMod( modifiedItem.ID, ev.slotID );
		}
	}

	private function IsUnequipBlocked( itemID : ItemID ) : Bool
	{
		var itemData : weak< gameItemData >;
		itemData = RPGManager.GetItemData( m_player.GetGame(), m_player, itemID );
		return itemData && itemData.HasTag( 'UnequipBlocked' );
	}

	protected event OnItemChooserUnequipVisuals( evt : ItemChooserUnequipVisuals )
	{
		m_InventoryManager.UnequipVisuals( evt.itemData.EquipmentArea );
	}

	protected event OnItemChooserUnequipItem( evt : ItemChooserUnequipItem )
	{
		var equipedItem : InventoryItemData;
		equipedItem = itemChooser.GetModifiedItemData();
		if( !( InventoryGPRestrictionHelper.CanEquip( equipedItem, m_player ) ) || IsUnequipBlocked( equipedItem.ID ) )
		{
			ShowNotification( m_player.GetGame(), UIMenuNotificationType.InventoryActionBlocked );
			return false;
		}
		if( m_currentHotkey != EHotkey.INVALID )
		{
			m_equipmentSystem.GetPlayerData( m_player ).ClearItemFromHotkey( m_currentHotkey );
			m_viewMode = ItemViewModes.Item;
			m_currentFilter = ItemFilterCategory.Invalid;
			RefreshAvailableItems();
			NotifyItemUpdate();
			itemChooser.RefreshItems();
		}
		else
		{
			if( m_lastEquipmentAreas.Contains( gamedataEquipmentArea.Outfit ) )
			{
				if( m_wardrobeSystem.GetActiveClothingSetIndex() != gameWardrobeClothingSetIndex.INVALID )
				{
					if( m_InventoryManager.IsWardrobeEnabled() )
					{
						WardrobeOutfitUnequipSet();
						UpdateOutfitWardrobe( true, -1 );
						itemChooser.RefreshItems( true, -1 );
					}
					else
					{
						ShowNotification( m_player.GetGame(), UIMenuNotificationType.InventoryActionBlocked );
					}
					return false;
				}
			}
			UnequipItem( itemChooser.GetModifiedItem(), equipedItem );
		}
	}

	protected event OnItemChooserItemHoverOver( evt : ItemChooserItemHoverOver )
	{
		var itemData : InventoryItemData;
		var slotName : String;
		itemData = evt.targetItem.GetItemData();
		if( !( InventoryItemData.IsEmpty( itemData ) ) )
		{
			SetInventoryItemButtonHintsHoverOver( itemData );
		}
		else
		{
			slotName = GetLocalizedText( evt.targetItem.GetSlotName() );
			if( evt.targetItem.GetDisplayContext() == ItemDisplayContext.Attachment && ( evt.targetItem.GetNewItems() == 0 ) )
			{
				slotName = GetLocalizedText( slotName );
				slotName += "\n";
				slotName += GetLocalizedText( "UI-Tooltips-NoModsAvailable" );
			}
			m_TooltipsManager.ShowTooltipAtWidget( 0, evt.sourceEvent.GetTarget(), m_InventoryManager.GetTooltipForEmptySlot( slotName ), gameuiETooltipPlacement.RightTop, true );
		}
	}

	protected event OnItemChooserItemHoverOut( evt : ItemChooserItemHoverOut )
	{
		SetInventoryItemButtonHintsHoverOut();
	}

	private function InvalidateItemTooltipEvent()
	{
		if( m_lastItemHoverOverEvent != NULL )
		{
			OnItemDisplayHoverOver( m_lastItemHoverOverEvent );
		}
	}

	protected event OnItemDisplayHoverOver( evt : ItemDisplayHoverOverEvent )
	{
		var equippedItem : InventoryItemData;
		var transmogMsgTooltipData : TransmogMessageTooltipData;
		var msgTooltipData : MessageTooltipData;
		var skipCompare : Bool;
		var isEmpty : Bool;
		var itemTransmogRecord : weak< Item_Record >;
		var iconsNameResolver : IconsNameResolver;
		var useMaleIcon : Bool;
		var resolvedIcon : CName;
		var iconPath : String;
		var transmogItem : ItemID;
		var isClothing : Bool;
		var useTransmogTooltip, noTransmogIcon : Bool;
		m_lastItemHoverOverEvent = evt;
		skipCompare = ( !( m_isShown ) || evt.display.GetDisplayContext() == ItemDisplayContext.Attachment ) || evt.itemData.ItemType == gamedataItemType.Prt_Program;
		isEmpty = InventoryItemData.IsEmpty( evt.itemData );
		if( !( InventoryItemData.IsEmpty( evt.itemData ) ) )
		{
			RequestItemInspected( InventoryItemData.GetID( evt.itemData ) );
		}
		if( evt.toggleVisibilityControll )
		{
			msgTooltipData = new MessageTooltipData;
			if( evt.isItemHidden )
			{
				msgTooltipData.Title = GetLocalizedText( "UI-Inventory-Tooltips-ShowItem" );
			}
			else
			{
				msgTooltipData.Title = GetLocalizedText( "UI-Inventory-Tooltips-HideItem" );
			}
			m_TooltipsManager.ShowTooltipAtWidget( 0, evt.widget, msgTooltipData, gameuiETooltipPlacement.RightTop, true, inkMargin( 2.0, 0.0, 0.0, 0.0 ) );
		}
		else if( !( isEmpty ) )
		{
			equippedItem = itemChooser.GetSelectedItem().GetItemData();
			if( m_InventoryManager.IsSlotOverriden( evt.display.GetEquipmentArea() ) )
			{
				transmogItem = m_InventoryManager.GetVisualItemInSlot( evt.display.GetEquipmentArea() );
			}
			ShowTooltipsForItemData( equippedItem, evt.widget, evt.itemData, skipCompare, evt.display.DEBUG_GetIconErrorInfo(), evt.display, transmogItem );
		}
		else
		{
			iconsNameResolver = IconsNameResolver.GetIconsNameResolver();
			useMaleIcon = m_InventoryManager.GetIconGender() == ItemIconGender.Male;
			isClothing = IsEquipmentAreaClothing( evt.display.GetEquipmentArea() );
			transmogItem = m_InventoryManager.GetVisualItemInSlot( evt.display.GetEquipmentArea() );
			if( isClothing )
			{
				if( ItemID.IsValid( transmogItem ) )
				{
					itemTransmogRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( transmogItem ) );
					iconPath = itemTransmogRecord.IconPath();
					useTransmogTooltip = true;
				}
				else if( m_wardrobeSystem.GetActiveClothingSetIndex() != gameWardrobeClothingSetIndex.INVALID )
				{
					noTransmogIcon = true;
					useTransmogTooltip = true;
				}
			}
			if( IsStringValid( iconPath ) )
			{
				resolvedIcon = StringToName( "UIIcon." + iconPath );
			}
			else
			{
				if( ItemID.IsValid( transmogItem ) )
				{
					resolvedIcon = iconsNameResolver.TranslateItemToIconName( ItemID.GetTDBID( transmogItem ), useMaleIcon );
				}
				resolvedIcon = StringToName( "UIIcon." + NameToString( resolvedIcon ) );
			}
			if( isClothing && useTransmogTooltip )
			{
				transmogMsgTooltipData = m_InventoryManager.GetTransmogTooltipForEmptySlot( evt.display.GetSlotName(), transmogItem, resolvedIcon, noTransmogIcon );
				m_TooltipsManager.ShowTooltipAtWidget( 'descriptionTooltipV3Transmog', evt.widget, transmogMsgTooltipData, gameuiETooltipPlacement.RightTop, true, inkMargin( 2.0, 0.0, 0.0, 0.0 ) );
			}
			else
			{
				msgTooltipData = m_InventoryManager.GetTooltipForEmptySlot( evt.display.GetSlotName() );
				m_TooltipsManager.ShowTooltipAtWidget( 0, evt.widget, msgTooltipData, gameuiETooltipPlacement.RightTop, true, inkMargin( 2.0, 0.0, 0.0, 0.0 ) );
			}
		}
		SetInventoryItemButtonHintsHoverOver( evt.itemData, evt.display );
		if( InventoryItemData.IsEmpty( evt.itemData ) && TDBID.IsValid( evt.display.GetSlotID() ) )
		{
			m_buttonHintsController.AddButtonHint( 'select', GetLocalizedText( "UI-UserActions-Select" ) );
		}
	}

	protected event OnItemDisplayHoverOut( evt : ItemDisplayHoverOutEvent )
	{
		HandleItemHoverOut();
		m_lastItemHoverOverEvent = NULL;
		m_pressedItemDisplay = NULL;
	}

	protected event OnItemDisplayPress( evt : ItemDisplayPressEvent )
	{
		m_pressedItemDisplay = evt.display;
	}

	private function RequestItemInspected( itemID : ItemID )
	{
		var request : UIScriptableSystemInventoryInspectItem;
		request = new UIScriptableSystemInventoryInspectItem;
		request.itemID = itemID;
		m_uiScriptableSystem.QueueRequest( request );
	}

	protected event OnInventoryItemHoverOut( evt : inkPointerEvent )
	{
		HandleItemHoverOut();
	}

	private function HandleItemHoverOut()
	{
		HideTooltips();
		SetInventoryItemButtonHintsHoverOut();
	}


	private var HACK_lastItemDisplayEvent : ItemDisplayClickEvent;

	protected event OnItemDisplayClick( evt : ItemDisplayClickEvent )
	{
		if( HACK_lastItemDisplayEvent == evt )
		{
			return false;
		}
		else if( evt.actionName.IsAction( 'equip_visuals' ) )
		{
			if( ItemID.IsValid( evt.transmogItem ) )
			{
				m_InventoryManager.UnequipVisuals( InventoryItemData.GetEquipmentArea( evt.itemData ) );
			}
			else if( itemChooser.CanEquipVisuals( InventoryItemData.GetID( evt.itemData ) ) )
			{
				m_InventoryManager.EquipVisuals( InventoryItemData.GetID( evt.itemData ) );
			}
			PlaySound( 'Item', 'ItemGeneric' );
			PlayRumble( RumbleStrength.Heavy, RumbleType.Pulse, RumblePosition.Right );
		}
		else if( m_isShown )
		{
			HandleItemClick( evt.itemData, evt.actionName, evt.displayContext, evt.display.GetIsPlayerFavourite() );
		}
		HACK_lastItemDisplayEvent = evt;
	}

	private function UpdateGridItemFavourite( itemID : ItemID, favourite : Bool )
	{
		var i, limit : Int32;
		for( i = 0, limit = m_currentItems.Size(); i < limit; i += 1 )
		{
			if( InventoryItemData.GetID( m_currentItems[ i ].ItemData ) == itemID )
			{
				m_currentItems[ i ].IsPlayerFavourite = favourite;
				break;
			}
		}
	}

	private function ShowNotification( gameInstance : GameInstance, type : UIMenuNotificationType )
	{
		var inventoryNotification : UIMenuNotificationEvent;
		if( type != m_lastNotificationType || !( m_animContainer.m_animProxy.IsPlaying() ) )
		{
			GameInstance.GetUISystem( gameInstance ).QueueEvent( new UINotificationRemoveEvent );
		}
		m_lastNotificationType = type;
		inventoryNotification = new UIMenuNotificationEvent;
		inventoryNotification.m_notificationType = type;
		inventoryNotification.m_animContainer = m_animContainer;
		GameInstance.GetUISystem( gameInstance ).QueueEvent( inventoryNotification );
	}

	protected event OnBuyShardPopupClosed( data : inkGameNotificationData )
	{
		m_tokenPopup = NULL;
		m_buttonHintsController.Show();
		PlaySound( 'Button', 'OnPress' );
	}

	private function HandleItemClick( const itemData : ref< InventoryItemData >, actionName : inkActionName, optional displayContext : ItemDisplayContext, optional isPlayerLocked : Bool )
	{
		var item : ItemModParams;
		var isEquippedItemBlocked, shouldUpdate : Bool;
		var isClothing : Bool;
		var localEquippedData : weak< gameItemData >;
		if( actionName.IsAction( 'drop_item' ) )
		{
			if( ( m_playerState == gamePSMVehicle.Default && !( InventoryItemData.IsEquipped( itemData ) ) ) && RPGManager.CanItemBeDropped( m_player, InventoryItemData.GetGameItemData( itemData ) ) )
			{
				if( isPlayerLocked )
				{
					ShowNotification( m_player.GetGame(), UIMenuNotificationType.InventoryActionBlocked );
					return;
				}
				if( InventoryItemData.GetQuantity( itemData ) > 1 )
				{
					OpenQuantityPicker( itemData, QuantityPickerActionType.Drop );
				}
				else
				{
					item.itemID = InventoryItemData.GetID( itemData );
					item.quantity = 1;
					AddToDropQueue( item );
					RefreshAvailableItems();
					PlaySound( 'Item', 'OnDrop' );
					PlayRumble( RumbleStrength.SuperLight, RumbleType.Pulse, RumblePosition.Right );
				}
			}
		}
		else if( ( ( ( actionName.IsAction( 'preview_item' ) && ( InventoryItemData.IsWeapon( itemData ) || InventoryItemData.IsGarment( itemData ) ) ) && !( InventoryItemData.IsEmpty( itemData ) ) ) && displayContext == ItemDisplayContext.Backpack ) && ( m_pressedItemDisplay != NULL ) )
		{
			PlaySound( 'MapPin', 'OnCreate' );
			m_pressedItemDisplay = NULL;
			isClothing = IsEquipmentAreaClothing( InventoryItemData.GetEquipmentArea( itemData ) ) || InventoryItemData.GetEquipmentArea( itemData ) == gamedataEquipmentArea.Outfit;
			m_itemPreviewPopupToken = ItemPreviewHelper.ShowPreviewItem( this, itemData, isClothing, 'OnItemPreviewPopup' );
		}
		else if( ( actionName.IsAction( 'click' ) && displayContext != ItemDisplayContext.Attachment ) && !( ( InventoryItemData.IsEquipped( itemData ) && m_currentHotkey == EHotkey.INVALID ) ) )
		{
			localEquippedData = InventoryItemData.GetGameItemData( itemChooser.GetModifiedItemData() );
			if( ( RPGManager.IsWeaponMod( itemData.ItemType ) && localEquippedData.HasPartInSlot( itemChooser.GetSelectedSlotID() ) ) && !( localEquippedData.HasTag( 'IconicWeapon' ) ) )
			{
				ShowNotification( m_player.GetGame(), UIMenuNotificationType.InventoryNoFreeSlot );
				return;
			}
			shouldUpdate = true;
			isEquippedItemBlocked = localEquippedData.HasTag( 'UnequipBlocked' );
			if( isEquippedItemBlocked || !( InventoryGPRestrictionHelper.CanEquip( itemData, m_player ) ) )
			{
				ShowNotification( m_player.GetGame(), DetermineUIMenuNotificationType() );
				return;
			}
			if( InventoryItemData.GetItemType( itemData ) == gamedataItemType.Clo_Outfit )
			{
				if( m_outfitInCooldown )
				{
					return;
				}
				else if( ScheduleOutfitCooldownReset() )
				{
					SetOutfitCooldown( true );
				}
			}
			EquipItem( itemData, itemChooser.GetSlotIndex() );
			PlayRumble( RumbleStrength.Heavy, RumbleType.Pulse, RumblePosition.Right );
			if( m_lastEquipmentAreas.Contains( gamedataEquipmentArea.Outfit ) )
			{
				if( m_wardrobeSystem.GetActiveClothingSetIndex() != gameWardrobeClothingSetIndex.INVALID && InventoryItemData.IsEmpty( itemData ) )
				{
					shouldUpdate = false;
				}
			}
			itemChooser.RefreshItems( shouldUpdate, -1 );
			if( !( InventoryItemData.IsPart( itemData ) ) )
			{
				m_viewMode = ItemViewModes.Item;
				m_currentFilter = ItemFilterCategory.Invalid;
				RefreshAvailableItems();
			}
			NotifyItemUpdate();
		}
	}

	private function ScheduleOutfitCooldownReset() : Bool
	{
		var callback : InventoryOutfitCooldownResetCallback;
		callback = new InventoryOutfitCooldownResetCallback;
		callback.m_controller = this;
		if( m_delaySystem && !( m_outfitInCooldown ) )
		{
			m_delaySystem.CancelCallback( m_delayedOutfitCooldownResetCallbackId );
			m_delayedOutfitCooldownResetCallbackId = m_delaySystem.DelayCallback( callback, m_outfitCooldownPeroid, false );
			return GetInvalidDelayID() != m_delayedOutfitCooldownResetCallbackId;
		}
		return false;
	}

	public function SetOutfitCooldown( inCooldown : Bool )
	{
		m_outfitInCooldown = inCooldown;
	}

	public function OpenQuantityPicker( const itemData : ref< InventoryItemData >, action : QuantityPickerActionType )
	{
		var request : OpenInventoryQuantityPickerRequest;
		request = new OpenInventoryQuantityPickerRequest;
		request.itemData = itemData;
		request.actionType = action;
		QueueEvent( request );
	}

	public function OnQuantityPickerPopupClosed( data : QuantityPickerPopupCloseData )
	{
		if( data.choosenQuantity != -1 )
		{
			switch( data.actionType )
			{
				case QuantityPickerActionType.Drop:
					OnQuantityPickerDrop( data );
				break;
				case QuantityPickerActionType.Disassembly:
					OnQuantityPickerDisassembly( data );
				break;
			}
		}
	}

	public function OnQuantityPickerDrop( data : QuantityPickerPopupCloseData )
	{
		var item : ItemModParams;
		item.itemID = InventoryItemData.GetID( data.itemData );
		item.quantity = data.choosenQuantity;
		AddToDropQueue( item );
		m_viewMode = ItemViewModes.Item;
		m_currentFilter = ItemFilterCategory.Invalid;
		RefreshAvailableItems();
		PlaySound( 'Item', 'OnDrop' );
		PlayRumble( RumbleStrength.SuperLight, RumbleType.Pulse, RumblePosition.Right );
	}

	public function OnQuantityPickerDisassembly( data : QuantityPickerPopupCloseData )
	{
		if( InventoryItemData.IsWeapon( data.itemData ) )
		{
			SelectMainItem();
		}
		ItemActionsHelper.DisassembleItem( m_player, InventoryItemData.GetID( data.itemData ), data.choosenQuantity );
		PlaySound( 'Item', 'OnDisassemble' );
		PlayRumble( RumbleStrength.Light, RumbleType.Pulse, RumblePosition.Right );
	}

	protected function AddToDropQueue( item : ItemModParams )
	{
		var i : Int32;
		var merged : Bool;
		var evt : DropQueueUpdatedEvent;
		for( i = 0; i < m_itemDropQueue.Size(); i += 1 )
		{
			if( m_itemDropQueue[ i ].itemID == item.itemID )
			{
				m_itemDropQueue[ i ].quantity += item.quantity;
				merged = true;
				break;
			}
		}
		if( !( merged ) )
		{
			m_itemDropQueue.PushBack( item );
		}
		evt = new DropQueueUpdatedEvent;
		evt.m_dropQueue = m_itemDropQueue;
		QueueEvent( evt );
	}

	protected event OnItemDisplayHold( evt : ItemDisplayHoldEvent )
	{
		HandleItemHold( evt.itemData, evt.actionName, evt.display.GetIsPlayerFavourite(), evt.display );
	}

	protected event OnItemInventoryHold( evt : inkPointerEvent )
	{
		var controller : weak< InventoryItemDisplayController >;
		var progress : Float;
		controller = GetInventoryItemDisplayControllerFromTarget( evt );
		progress = evt.GetHoldProgress();
		if( progress >= 1.0 )
		{
			HandleItemHold( controller.GetItemData(), evt.GetActionName(), controller.GetIsPlayerFavourite(), controller );
		}
	}

	private function OpenConfirmationPopupOpenConfirmationPopup( const itemData : ref< InventoryItemData > )
	{
		var data : VendorConfirmationPopupData;
		data = new VendorConfirmationPopupData;
		data.notificationName = 'base\gameplay\gui\widgets\notifications\vendor_confirmation.inkwidget';
		data.isBlocking = true;
		data.useCursor = true;
		data.queueName = 'modal_popup';
		data.itemData = itemData;
		data.quantity = InventoryItemData.GetQuantity( itemData );
		data.type = VendorConfirmationPopupType.DisassembeIconic;
		m_confirmationPopupToken = ShowGameNotification( data );
		m_confirmationPopupToken.RegisterListener( this, 'OnConfirmationPopupClosed' );
		m_buttonHintsController.Hide();
	}

	protected event OnConfirmationPopupClosed( data : inkGameNotificationData )
	{
		var resultData : VendorConfirmationPopupCloseData;
		m_confirmationPopupToken = NULL;
		resultData = ( ( VendorConfirmationPopupCloseData )( data ) );
		if( resultData.confirm )
		{
			if( InventoryItemData.IsWeapon( resultData.itemData ) )
			{
				SelectMainItem();
			}
			ItemActionsHelper.DisassembleItem( m_player, InventoryItemData.GetID( resultData.itemData ) );
			PlaySound( 'Item', 'OnDisassemble' );
			PlayRumble( RumbleStrength.Light, RumbleType.Pulse, RumblePosition.Right );
		}
		m_buttonHintsController.Show();
	}

	protected event OnItemPreviewPopup( data : inkGameNotificationData )
	{
		m_itemPreviewPopupToken = NULL;
	}

	private function HandleItemHold( const itemData : ref< InventoryItemData >, actionName : inkActionName, isPlayerLocked : Bool, controller : weak< InventoryItemDisplayController > )
	{
		var IsInUse : Bool;
		var setPlayerFavouriteRequest : UIScriptableSystemSetItemPlayerFavourite;
		IsInUse = InventoryItemData.GetSlotIndex( itemData ) > -1;
		if( ( actionName.IsAction( 'disassemble_item' ) && !( m_isE3Demo ) ) && RPGManager.CanItemBeDisassembled( m_player.GetGame(), InventoryItemData.GetGameItemData( itemData ) ) )
		{
			if( isPlayerLocked )
			{
				ShowNotification( m_player.GetGame(), UIMenuNotificationType.InventoryActionBlocked );
				return;
			}
			if( InventoryItemData.GetQuantity( itemData ) > 1 )
			{
				OpenQuantityPicker( itemData, QuantityPickerActionType.Disassembly );
			}
			else if( RPGManager.IsItemIconic( InventoryItemData.GetGameItemData( itemData ) ) && !( IsInUse ) )
			{
				OpenConfirmationPopupOpenConfirmationPopup( itemData );
			}
			else
			{
				if( InventoryItemData.IsWeapon( itemData ) )
				{
					SelectMainItem();
				}
				ItemActionsHelper.DisassembleItem( m_player, InventoryItemData.GetID( itemData ) );
				PlaySound( 'Item', 'OnDisassemble' );
				PlayRumble( RumbleStrength.Light, RumbleType.Pulse, RumblePosition.Right );
			}
		}
		else if( actionName.IsAction( 'use_item' ) )
		{
			if( InventoryItemData.GetItemType( itemData ) == gamedataItemType.Con_Inhaler || InventoryItemData.GetItemType( itemData ) == gamedataItemType.Con_Injector )
			{
				return;
			}
			if( !( InventoryGPRestrictionHelper.CanUse( itemData, m_player ) ) )
			{
				ShowNotification( m_player.GetGame(), DetermineUIMenuNotificationType() );
				return;
			}
			ItemActionsHelper.PerformItemAction( m_player, InventoryItemData.GetID( itemData ) );
			m_InventoryManager.MarkToRebuild();
		}
		else if( ( ( ( actionName.IsAction( 'favourite_item' ) && !( InventoryItemData.IsEmpty( itemData ) ) ) && InventoryItemData.IsWeapon( itemData ) ) && !( IsItemCyberware( InventoryItemData.GetItemType( itemData ) ) ) ) && ( m_pressedItemDisplay != NULL ) )
		{
			setPlayerFavouriteRequest = new UIScriptableSystemSetItemPlayerFavourite;
			setPlayerFavouriteRequest.itemID = InventoryItemData.GetID( itemData );
			setPlayerFavouriteRequest.favourite = !( controller.GetIsPlayerFavourite() );
			m_uiScriptableSystem.QueueRequest( setPlayerFavouriteRequest );
			controller.SetIsPlayerFavourite( setPlayerFavouriteRequest.favourite );
			InventoryItemData.UpdateSortData( itemData, m_uiScriptableSystem, setPlayerFavouriteRequest.favourite );
			UpdateGridItemFavourite( setPlayerFavouriteRequest.itemID, setPlayerFavouriteRequest.favourite );
			UpdateFavouriteHint( setPlayerFavouriteRequest.favourite );
			m_pressedItemDisplay = NULL;
			PlaySound( 'MapPin', 'OnEnable' );
			PlayRumble( RumbleStrength.Heavy, RumbleType.Pulse, RumblePosition.Right );
		}
	}

	private function DetermineUIMenuNotificationType() : UIMenuNotificationType
	{
		var psmBlackboard : IBlackboard;
		var inCombat : Bool;
		inCombat = false;
		psmBlackboard = m_player.GetPlayerStateMachineBlackboard();
		inCombat = psmBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Combat ) == ( ( Int32 )( gamePSMCombat.InCombat ) );
		if( inCombat )
		{
			return UIMenuNotificationType.InCombat;
		}
		else
		{
			return UIMenuNotificationType.InventoryActionBlocked;
		}
	}

	private function ShowTooltipsForItemData( equippedItem : InventoryItemData, target : weak< inkWidget >, const inspectedItemData : ref< InventoryItemData >, skipCompare : Bool, iconErrorInfo : DEBUG_IconErrorInfo, optional display : InventoryItemDisplayController, optional transmogItem : ItemID )
	{
		var tooltipsData : array< ATooltipData >;
		var canCompareItems : Bool;
		var tooltipData : InventoryTooltipData;
		var minimalTooltipData : MinimalItemTooltipData;
		var comparableProgram : InventoryItemAttachments;
		var inspectedShardType : CName;
		var equippedData : InventoryTooltipData;
		var identifiedTooltip, equippedTooltip : IdentifiedWrappedTooltipData;
		var itemTooltips : CName[ 2 ];
		var record : weak< UIStatsMap_Record >;
		var statsManager : UIInventoryItemStatsManager;
		var itemRecord : weak< Item_Record >;
		var cyberdeckTooltip : InventoryTooltipData;
		HideTooltips();
		if( InventoryItemData.IsWeapon( inspectedItemData ) )
		{
			itemTooltips[ 0 ] = 'newItemTooltip';
			itemTooltips[ 1 ] = 'newItemTooltipComparision';
		}
		else if( InventoryItemData.GetGameItemData( inspectedItemData ).HasTag( 'Cyberdeck' ) )
		{
			cyberdeckTooltip = m_InventoryManager.GetCyberdeckTooltipForInventoryItem( inspectedItemData, false, iconErrorInfo, , true );
			cyberdeckTooltip.SetManager( m_InventoryManager.GetUIInventorySystem().GetInventoryItemsManager() );
			m_TooltipsManager.ShowTooltipAtWidget( 'cyberdeckTooltip', target, cyberdeckTooltip, gameuiETooltipPlacement.RightTop, true );
		}
		else
		{
			itemTooltips[ 0 ] = 'itemTooltip';
			itemTooltips[ 1 ] = 'itemTooltipComparision';
		}
		canCompareItems = m_comparisonResolver.IsTypeComparable( equippedItem, InventoryItemData.GetItemType( inspectedItemData ) );
		if( InventoryItemData.IsEmpty( equippedItem ) && !( skipCompare ) )
		{
			equippedItem = m_comparisonResolver.GetPreferredComparisonItem( inspectedItemData );
			if( !( InventoryItemData.IsEmpty( equippedItem ) ) )
			{
				m_InventoryManager.PushMinimalIdentifiedComparisonTooltipsData( tooltipsData, itemTooltips[ 0 ], itemTooltips[ 1 ], equippedItem, inspectedItemData, iconErrorInfo );
				m_TooltipsManager.ShowTooltipsAtWidget( tooltipsData, target );
			}
			else
			{
				if( InventoryItemData.GetItemType( inspectedItemData ) == gamedataItemType.Prt_Program )
				{
					inspectedShardType = TweakDBInterface.GetCName( ItemID.GetTDBID( InventoryItemData.GetID( inspectedItemData ) ) + T".shardType", '' );
					comparableProgram = GetProgramByShardType( InventoryItemData.GetAttachments( itemChooser.GetModifiedItemData() ), inspectedShardType );
					if( TDBID.IsValid( comparableProgram.SlotID ) )
					{
						m_InventoryManager.PushIdentifiedProgramComparisionTooltipsData( tooltipsData, comparableProgram.ItemData, inspectedItemData, iconErrorInfo, false );
						m_TooltipsManager.ShowTooltipsAtWidget( tooltipsData, target );
					}
					else
					{
						m_TooltipsManager.ShowTooltipAtWidget( 'programTooltip', target, m_InventoryManager.GetTooltipDataForInventoryItem( inspectedItemData, false, iconErrorInfo, , true ), gameuiETooltipPlacement.RightTop, true );
					}
				}
				else
				{
					m_TooltipsManager.ShowTooltipAtWidget( itemTooltips[ 0 ], target, m_InventoryManager.GetMinimalTooltipDataForInventoryItem( inspectedItemData, false, iconErrorInfo, , true ), gameuiETooltipPlacement.RightTop, true );
				}
			}
		}
		else if( ( ( !( InventoryItemData.IsEmpty( equippedItem ) ) && ( InventoryItemData.GetID( equippedItem ) != InventoryItemData.GetID( inspectedItemData ) ) ) && canCompareItems ) && !( skipCompare ) )
		{
			identifiedTooltip = new IdentifiedWrappedTooltipData;
			identifiedTooltip.m_identifier = itemTooltips[ 0 ];
			identifiedTooltip.m_data = m_InventoryManager.GetMinimalComparisonTooltipsData( equippedItem, inspectedItemData, false, iconErrorInfo, true );
			tooltipsData.PushBack( identifiedTooltip );
			equippedData = m_InventoryManager.GetComparisonTooltipsData( inspectedItemData, equippedItem, true, , true );
			if( InventoryDataManagerV2.IsAttachmentType( InventoryItemData.GetItemType( equippedItem ) ) )
			{
				equippedData.displayContext = InventoryTooltipDisplayContext.Attachment;
				equippedData.parentItemData = InventoryItemData.GetGameItemData( itemChooser.GetModifiedItemData() );
				equippedData.slotID = InventoryDataManagerV2.GetAttachmentSlotByItemID( itemChooser.GetModifiedItemData(), InventoryItemData.GetID( equippedItem ) );
			}
			equippedTooltip = new IdentifiedWrappedTooltipData;
			equippedTooltip.m_identifier = itemTooltips[ 1 ];
			equippedTooltip.m_data = m_InventoryManager.MakeTooltipMinimalAndAttachManager( equippedData );
			tooltipsData.PushBack( equippedTooltip );
			m_InventoryManager.FillBarsComparisonData( ( ( MinimalItemTooltipData )( identifiedTooltip.m_data ) ), ( ( MinimalItemTooltipData )( equippedTooltip.m_data ) ) );
			m_InventoryManager.SetComparisonQualityF( ( ( MinimalItemTooltipData )( identifiedTooltip.m_data ) ), ( ( MinimalItemTooltipData )( equippedTooltip.m_data ) ) );
			if( m_isComparisionDisabled )
			{
				m_TooltipsManager.ShowTooltipAtWidget( itemTooltips[ 0 ], target, identifiedTooltip.m_data, gameuiETooltipPlacement.RightTop );
			}
			else
			{
				m_TooltipsManager.ShowTooltipsAtWidget( tooltipsData, target );
			}
		}
		else
		{
			if( InventoryItemData.GetItemType( inspectedItemData ) == gamedataItemType.Prt_Program )
			{
				tooltipData = m_InventoryManager.GetTooltipDataForInventoryItem( inspectedItemData, false, iconErrorInfo, , true );
				if( display && display.GetDisplayContext() == ItemDisplayContext.Attachment )
				{
					tooltipData.displayContext = InventoryTooltipDisplayContext.Attachment;
					tooltipData.parentItemData = display.GetParentItemData();
					tooltipData.slotID = display.GetSlotID();
				}
				m_TooltipsManager.ShowTooltipAtWidget( 'programTooltip', target, tooltipData, gameuiETooltipPlacement.RightTop, true );
			}
			else
			{
				equippedItem = m_comparisonResolver.GetPreferredComparisonItem( inspectedItemData );
				tooltipData = m_InventoryManager.GetTooltipDataForInventoryItem( inspectedItemData, false, iconErrorInfo, , true );
				if( display && display.GetDisplayContext() == ItemDisplayContext.Attachment )
				{
					tooltipData.displayContext = InventoryTooltipDisplayContext.Attachment;
					tooltipData.parentItemData = display.GetParentItemData();
					tooltipData.slotID = display.GetSlotID();
				}
				tooltipData.transmogItem = transmogItem;
				minimalTooltipData = m_InventoryManager.MakeTooltipMinimalAndAttachManager( tooltipData );
				minimalTooltipData.SetManager( m_InventoryManager.GetUIInventorySystem().GetInventoryItemsManager() );
				if( m_comparisonResolver.IsTypeComparable( equippedItem, InventoryItemData.GetItemType( inspectedItemData ) ) )
				{
					record = UIInventoryItemsManager.GetUIStatsMap( InventoryItemData.GetItemType( equippedItem ) );
					statsManager = UIInventoryItemStatsManager.Make( InventoryItemData.GetGameItemData( equippedItem ), record, m_InventoryManager.GetUIInventorySystem().GetInventoryItemsManager() );
					minimalTooltipData.GetStatsManager().GetWeaponBars().SetComparedBars( statsManager.GetWeaponBars() );
					minimalTooltipData.comparisonQualityF = UIItemsHelper.GetQualityF( equippedItem );
				}
				else
				{
					minimalTooltipData.GetStatsManagerPure().FlushComparedBars();
					minimalTooltipData.comparisonQualityF = -1.0;
				}
				if( display && display.GetDisplayContext() == ItemDisplayContext.Attachment )
				{
					minimalTooltipData.isPlus = InventoryUtils.GetInnerItemStatValueByType( InventoryItemData.GetGameItemData( inspectedItemData ), display.GetSlotID(), gamedataStatType.IsItemPlus );
					minimalTooltipData.isIconic = InventoryUtils.GetInnerItemStatValueByType( InventoryItemData.GetGameItemData( inspectedItemData ), display.GetSlotID(), gamedataStatType.IsItemIconic ) > 0.0;
					if( !( minimalTooltipData.isIconic ) )
					{
						itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( InventoryItemData.GetID( inspectedItemData ) ) );
						minimalTooltipData.isIconic = itemRecord.TagsContains( 'ChimeraMod' );
					}
				}
				m_TooltipsManager.ShowTooltipAtWidget( itemTooltips[ 0 ], target, minimalTooltipData, gameuiETooltipPlacement.RightTop, true );
			}
		}
	}

	private function HideTooltips()
	{
		m_TooltipsManager.HideTooltips();
	}

	private function SetInventoryItemButtonHintsHoverOver( const displayingData : ref< InventoryItemData >, optional display : InventoryItemDisplayController )
	{
		var isEquippedOrAttachment : Bool;
		var equipmentArea : gamedataEquipmentArea;
		var equippedItem : InventoryItemData;
		m_cursorData = new MenuCursorUserData;
		isEquippedOrAttachment = InventoryItemData.IsEquipped( displayingData ) || this.itemChooser.IsAttachmentItem( displayingData );
		if( display )
		{
			if( !( InventoryItemData.IsEmpty( displayingData ) ) )
			{
				if( itemChooser.CanEquipVisuals( InventoryItemData.GetID( displayingData ) ) )
				{
					m_buttonHintsController.AddButtonHint( 'equip_visuals', GetLocalizedText( "UI-UserActions-EquipVisuals" ) );
				}
				else
				{
					m_buttonHintsController.RemoveButtonHint( 'equip_visuals' );
				}
				if( !( isEquippedOrAttachment ) )
				{
					if( ( ( ( ( m_playerState == gamePSMVehicle.Default && RPGManager.CanItemBeDropped( m_player, InventoryItemData.GetGameItemData( displayingData ) ) ) && InventoryItemData.GetItemType( displayingData ) != gamedataItemType.Prt_Program ) && InventoryItemData.GetItemType( displayingData ) != gamedataItemType.Gad_Grenade ) && InventoryItemData.GetItemType( displayingData ) != gamedataItemType.Con_Inhaler ) && InventoryItemData.GetItemType( displayingData ) != gamedataItemType.Con_Injector )
					{
						m_buttonHintsController.AddButtonHint( 'drop_item', GetLocalizedText( "UI-ScriptExports-Drop0" ) );
					}
					if( !( InventoryItemData.IsPart( displayingData ) ) )
					{
						if( InventoryItemData.GetEquipmentArea( displayingData ) != gamedataEquipmentArea.Invalid )
						{
							m_buttonHintsController.AddButtonHint( 'equip_item', GetLocalizedText( "UI-UserActions-Equip" ) );
						}
					}
					else
					{
						if( RPGManager.IsWeaponMod( displayingData.ItemType ) )
						{
							equippedItem = itemChooser.GetSelectedItem().GetItemData();
							if( equippedItem.Empty )
							{
								m_buttonHintsController.AddButtonHint( 'equip_item', GetLocalizedText( "UI-UserActions-Equip" ) );
							}
						}
						else
						{
							m_buttonHintsController.AddButtonHint( 'equip_item', GetLocalizedText( "UI-UserActions-Equip" ) );
						}
					}
					equipmentArea = InventoryItemData.GetEquipmentArea( displayingData );
					if( ( IsEquipmentAreaClothing( equipmentArea ) || IsEquipmentAreaWeapon( equipmentArea ) ) || equipmentArea == gamedataEquipmentArea.Outfit )
					{
						m_buttonHintsController.AddButtonHint( 'preview_item', "UI-UserActions-ItemPreview" );
					}
					m_buttonHintsController.RemoveButtonHint( 'favourite_item' );
					if( IsEquipmentAreaWeapon( equipmentArea ) )
					{
						UpdateFavouriteHint( InventoryItemData.GetID( displayingData ) );
					}
					if( display.GetDisplayContext() == ItemDisplayContext.Attachment )
					{
						m_buttonHintsController.RemoveButtonHint( 'drop_item' );
						m_buttonHintsController.RemoveButtonHint( 'equip_item' );
						if( RPGManager.CanPartBeUnequipped( displayingData, display.GetSlotID() ) )
						{
							m_buttonHintsController.AddButtonHint( 'unequip_item', GetLocalizedText( "UI-UserActions-Unequip" ) );
						}
						else
						{
							m_buttonHintsController.RemoveButtonHint( 'unequip_item' );
						}
					}
				}
				else
				{
					if( ( !( InventoryItemData.IsPart( displayingData ) ) || RPGManager.CanPartBeUnequipped( displayingData, display.GetSlotID() ) ) && !( IsItemCyberware( displayingData.ItemType ) ) )
					{
						m_buttonHintsController.AddButtonHint( 'unequip_item', GetLocalizedText( "UI-UserActions-Unequip" ) );
					}
				}
				if( !( m_isE3Demo ) )
				{
					if( RPGManager.CanItemBeDisassembled( m_player.GetGame(), InventoryItemData.GetID( displayingData ) ) && !( isEquippedOrAttachment ) )
					{
						m_buttonHintsController.AddButtonHint( 'disassemble_item', ( ( "[" + GetLocalizedText( "Gameplay-Devices-Interactions-Helpers-Hold" ) ) + "] " ) + GetLocalizedText( "UI-ScriptExports-Disassemble0" ) );
						m_cursorData.AddAction( 'disassemble_item' );
					}
				}
				if( InventoryItemData.GetEquipmentArea( displayingData ) == gamedataEquipmentArea.Consumable )
				{
					if( InventoryItemData.GetItemType( displayingData ) != gamedataItemType.Con_Inhaler && InventoryItemData.GetItemType( displayingData ) != gamedataItemType.Con_Injector )
					{
						m_buttonHintsController.AddButtonHint( 'use_item', ( ( "[" + GetLocalizedText( "Gameplay-Devices-Interactions-Helpers-Hold" ) ) + "] " ) + GetLocalizedText( "UI-UserActions-Use" ) );
						m_cursorData.AddAction( 'use_item' );
					}
				}
			}
			else if( display.GetWardrobeOutfitIndex() >= 0 )
			{
				m_buttonHintsController.AddButtonHint( 'unequip_item', GetLocalizedText( "UI-UserActions-Unequip" ) );
			}
			if( m_cursorData.GetActionsListSize() >= 0 )
			{
				SetCursorContext( 'HoldToComplete', m_cursorData );
			}
			else
			{
				SetCursorContext( 'Hover' );
			}
		}
		else
		{
			SetCursorContext( 'Default' );
		}
	}

	private function UpdateFavouriteHint( itemID : ItemID )
	{
		UpdateFavouriteHint( m_uiScriptableSystem.IsItemPlayerFavourite( itemID ) );
	}

	private function UpdateFavouriteHint( state : Bool )
	{
		if( state )
		{
			m_buttonHintsController.AddButtonHint( 'favourite_item', ( ( "[" + GetLocalizedText( "Gameplay-Devices-Interactions-Helpers-Hold" ) ) + "] " ) + GetLocalizedText( "UI-UserActions-ItemRemoveFavourite" ) );
			m_cursorData.AddUniqueAction( 'favourite_item' );
		}
		else
		{
			m_buttonHintsController.AddButtonHint( 'favourite_item', ( ( "[" + GetLocalizedText( "Gameplay-Devices-Interactions-Helpers-Hold" ) ) + "] " ) + GetLocalizedText( "UI-UserActions-ItemAddFavourite" ) );
			m_cursorData.AddUniqueAction( 'favourite_item' );
		}
		if( m_cursorData.GetActionsListSize() >= 0 )
		{
			SetCursorContext( 'HoldToComplete', m_cursorData );
		}
		else
		{
			SetCursorContext( 'Hover' );
		}
	}

	private function IsItemCyberware( itemType : gamedataItemType ) : Bool
	{
		switch( itemType )
		{
			case gamedataItemType.Cyberware:
			case gamedataItemType.Cyb_Launcher:
			case gamedataItemType.Cyb_MantisBlades:
			case gamedataItemType.Cyb_NanoWires:
			case gamedataItemType.Cyb_StrongArms:
				return true;
			default:
				return false;
		}
	}

	private function SetInventoryItemButtonHintsHoverOut()
	{
		m_buttonHintsController.RemoveButtonHint( 'equip_item' );
		m_buttonHintsController.RemoveButtonHint( 'unequip_item' );
		m_buttonHintsController.RemoveButtonHint( 'disassemble_item' );
		m_buttonHintsController.RemoveButtonHint( 'use_item' );
		m_buttonHintsController.RemoveButtonHint( 'select' );
		m_buttonHintsController.RemoveButtonHint( 'drop_item' );
		m_buttonHintsController.RemoveButtonHint( 'favourite_item' );
		m_buttonHintsController.RemoveButtonHint( 'equip_visuals' );
		m_buttonHintsController.RemoveButtonHint( 'preview_item' );
	}

	private function SetEquipmentSlotButtonHintsHoverOver( controller : InventoryItemDisplayController )
	{
		var itemData : InventoryItemData;
		itemData = controller.GetItemData();
		m_buttonHintsController.AddButtonHint( 'select', GetLocalizedText( "Common-Access-Select" ) );
		if( !( InventoryItemData.IsEmpty( itemData ) ) )
		{
			m_buttonHintsController.AddButtonHint( 'unequip_item', GetLocalizedText( "UI-UserActions-Unequip" ) );
		}
		else
		{
			m_buttonHintsController.RemoveButtonHint( 'unequip_item' );
		}
	}

	private function SetEquipmentSlotButtonHintsHoverOut()
	{
		m_buttonHintsController.RemoveButtonHint( 'select' );
		m_buttonHintsController.RemoveButtonHint( 'unequip_item' );
	}

	private function GetInventoryItemDisplayControllerFromTarget( evt : inkPointerEvent ) : InventoryItemDisplayController
	{
		var widget : inkWidget;
		var controller : weak< InventoryItemDisplayController >;
		widget = evt.GetCurrentTarget();
		controller = ( ( InventoryItemDisplayController )( widget.GetController() ) );
		return controller;
	}

	private function GetProgramByShardType( const programs : ref< array< InventoryItemAttachments > >, targetShardType : CName ) : InventoryItemAttachments
	{
		var shardType : CName;
		var dummyResult : InventoryItemAttachments;
		var i : Int32;
		for( i = 0; i < programs.Size(); i += 1 )
		{
			if( InventoryItemData.IsEmpty( programs[ i ].ItemData ) )
			{
				continue;
			}
			shardType = TweakDBInterface.GetCName( ItemID.GetTDBID( InventoryItemData.GetID( programs[ i ].ItemData ) ) + T".shardType", '' );
			if( shardType == targetShardType )
			{
				return programs[ i ];
			}
		}
		return dummyResult;
	}

}

class ItemModeGridContainer extends inkLogicController
{
	protected editable var m_scrollControllerWidget : inkCompoundRef;
	protected editable var m_sliderWidget : inkWidgetRef;
	protected editable var m_itemsGridWidget : inkWidgetRef;
	protected editable var m_filterGridWidget : inkCompoundRef;
	private editable var m_F_eyesTexture : inkWidgetRef;
	private editable var m_F_systemReplacementTexture : inkWidgetRef;
	private editable var m_F_handsTexture : inkWidgetRef;
	private editable var m_M_eyesTexture : inkWidgetRef;
	private editable var m_M_systemReplacementTexture : inkWidgetRef;
	private editable var m_M_handsTexture : inkWidgetRef;
	private editable var m_inventoryWrapper : inkWidgetRef;
	private editable var m_gridWrapper : inkWidgetRef;
	private editable var m_scrollArea : inkWidgetRef;
	private var m_outroAnimation : inkAnimProxy;

	public function GetItemsGrid() : inkWidgetRef
	{
		return m_itemsGridWidget;
	}

	public function GetItemsWidget() : weak< inkWidget >
	{
		return inkWidgetRef.Get( m_itemsGridWidget );
	}

	public function GetFiltersGrid() : inkCompoundRef
	{
		return m_filterGridWidget;
	}

	public function SetSize( size : ItemModeGridSize )
	{
		if( size == ItemModeGridSize.Default )
		{
			inkWidgetRef.SetHeight( m_inventoryWrapper, 1295.0 );
			inkWidgetRef.SetHeight( m_gridWrapper, 1295.0 );
		}
		else if( size == ItemModeGridSize.Outfit )
		{
			inkWidgetRef.SetHeight( m_inventoryWrapper, 995.0 );
			inkWidgetRef.SetHeight( m_gridWrapper, 995.0 );
		}
	}

}

class ItemModeGridClassifier extends inkVirtualItemTemplateClassifier
{

	public virtual function ClassifyItem( data : Variant ) : Uint32
	{
		var listData : WrappedInventoryItemData;
		listData = ( ( WrappedInventoryItemData )( ( ( IScriptable )data ) ) );
		if( !( listData ) )
		{
			return 0;
		}
		return listData.ItemTemplate;
	}

}

class CommonItemsGridView extends ScriptableDataView
{
	protected var m_itemFilterType : ItemFilterCategory;
	protected var m_itemSortMode : ItemSortMode;
	protected var m_uiScriptableSystem : weak< UIScriptableSystem >;

	public function BindUIScriptableSystem( uiScriptableSystem : weak< UIScriptableSystem > )
	{
		m_uiScriptableSystem = uiScriptableSystem;
	}

	public function SetFilterTypeAndSortMode( type : ItemFilterCategory, mode : ItemSortMode )
	{
		var wasSortingEnabled : Bool;
		wasSortingEnabled = IsSortingEnabled();
		m_itemFilterType = type;
		m_itemSortMode = mode;
		if( wasSortingEnabled )
		{
			DisableSorting();
		}
		Filter();
		EnableSorting();
		Sort();
		if( !( wasSortingEnabled ) )
		{
			DisableSorting();
		}
	}

	public function SetFilterType( type : ItemFilterCategory )
	{
		m_itemFilterType = type;
		Filter();
	}

	public function GetFilterType() : ItemFilterCategory
	{
		return m_itemFilterType;
	}

	public function SetSortMode( mode : ItemSortMode )
	{
		var wasSortingEnabled : Bool;
		wasSortingEnabled = IsSortingEnabled();
		m_itemSortMode = mode;
		if( !( wasSortingEnabled ) )
		{
			EnableSorting();
			Sort();
			DisableSorting();
		}
		else
		{
			Sort();
		}
	}

	public function GetSortMode() : ItemSortMode
	{
		return m_itemSortMode;
	}

}

class ItemModeGridView extends CommonItemsGridView
{

	public override function SortItem( left : IScriptable, right : IScriptable ) : Bool
	{
		var leftItem, rightItem : InventoryItemSortData;
		var leftItemData, rightItemData : InventoryItemData;
		leftItem = InventoryItemData.GetSortData( ( ( WrappedInventoryItemData )( ( ( IScriptable )( left ) ) ) ).ItemData );
		rightItem = InventoryItemData.GetSortData( ( ( WrappedInventoryItemData )( ( ( IScriptable )( right ) ) ) ).ItemData );
		if( leftItem.Name == "" )
		{
			leftItemData = ( ( InventoryItemData )( ( ( WrappedInventoryItemData )( left ) ).ItemData ) );
			leftItem = ItemCompareBuilder.BuildInventoryItemSortData( leftItemData, m_uiScriptableSystem );
		}
		if( rightItem.Name == "" )
		{
			rightItemData = ( ( InventoryItemData )( ( ( WrappedInventoryItemData )( right ) ).ItemData ) );
			rightItem = ItemCompareBuilder.BuildInventoryItemSortData( rightItemData, m_uiScriptableSystem );
		}
		switch( m_itemSortMode )
		{
			case ItemSortMode.NewItems:
				return ItemCompareBuilder.Make( leftItem, rightItem ).NewItem( m_uiScriptableSystem ).FavouriteItem().DPSDesc().QualityDesc().ItemType().NameAsc().GetBool();
			case ItemSortMode.NameAsc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).FavouriteItem().NameAsc().QualityDesc().GetBool();
			case ItemSortMode.NameDesc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).FavouriteItem().NameDesc().QualityDesc().GetBool();
			case ItemSortMode.DpsAsc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).FavouriteItem().DPSAsc().QualityDesc().NameAsc().GetBool();
			case ItemSortMode.DpsDesc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).FavouriteItem().DPSDesc().QualityDesc().NameAsc().GetBool();
			case ItemSortMode.QualityAsc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).FavouriteItem().QualityDesc().NameAsc().QualityDesc().GetBool();
			case ItemSortMode.QualityDesc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).FavouriteItem().QualityAsc().NameAsc().QualityDesc().GetBool();
			case ItemSortMode.WeightAsc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).WeightAsc().NameAsc().QualityDesc().GetBool();
			case ItemSortMode.WeightDesc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).WeightDesc().NameAsc().QualityDesc().GetBool();
			case ItemSortMode.PriceAsc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).PriceAsc().NameAsc().QualityDesc().GetBool();
			case ItemSortMode.PriceDesc:
				return ItemCompareBuilder.Make( leftItem, rightItem ).PriceDesc().NameAsc().QualityDesc().GetBool();
			case ItemSortMode.ItemType:
				return ItemCompareBuilder.Make( leftItem, rightItem ).ItemType().NameAsc().QualityDesc().GetBool();
		}
		return ItemCompareBuilder.Make( leftItem, rightItem ).FavouriteItem().DPSDesc().QualityDesc().ItemType().NameAsc().GetBool();
	}

	public override function FilterItem( data : IScriptable ) : Bool
	{
		var m_wrappedData : WrappedInventoryItemData;
		m_wrappedData = ( ( WrappedInventoryItemData )( ( ( IScriptable )( data ) ) ) );
		return ItemCategoryFliter.FilterItem( m_itemFilterType, m_wrappedData );
	}

}

class ItemModeInventoryListenerCallback extends InventoryScriptCallback
{
	private var m_itemModeInstance : weak< InventoryItemModeLogicController >;

	public function Setup( itemModeInstance : weak< InventoryItemModeLogicController > )
	{
		m_itemModeInstance = itemModeInstance;
	}

	public override function OnItemRemoved( itemIDArg : ItemID, difference : Int32, currentQuantity : Int32 )
	{
		m_itemModeInstance.UpdateDisplayedItems( itemIDArg, true );
	}

	public override function OnItemQuantityChanged( itemIDArg : ItemID, diff : Int32, total : Uint32, flaggedAsSilent : Bool )
	{
		m_itemModeInstance.UpdateDisplayedItems( itemIDArg, true );
	}

}

class InstallModConfirmationData
{
	var itemId : ItemID;
	var partId : ItemID;
	var slotID : TweakDBID;
	var telemetryItemData : TelemetryInventoryItem;
	var telemetryPartData : TelemetryInventoryItem;
}

enum ItemModeGridSize
{
	Default = 0,
	Outfit = 1,
}

class OutfitWardrobeSlotSpawnData
{
	var index : Int32;
	var active : Bool;
	var equipped : Bool;
	var isNew : Bool;
}

class DelayedItemEquipped extends Event
{
}

class DelayedRefreshItems extends Event
{
}

class InventoryOutfitCooldownResetCallback extends DelayCallback
{
	var m_controller : weak< InventoryItemModeLogicController >;

	public override function Call()
	{
		m_controller.SetOutfitCooldown( false );
	}

}

