class InventoryGenericItemChooser extends inkLogicController
{
	protected editable var m_itemContainer : inkCompoundRef;
	protected editable var m_slotsCategory : inkWidgetRef;
	protected editable var m_slotsRootContainer : inkWidgetRef;
	protected editable var m_slotsRootLabel : inkTextRef;
	protected editable var m_slotsContainer : inkCompoundRef;
	protected var player : weak< PlayerPuppet >;
	protected var inventoryDataManager : InventoryDataManagerV2;
	protected var uiScriptableSystem : weak< UIScriptableSystem >;
	protected var equipmentArea : gamedataEquipmentArea;
	protected var itemDisplay : weak< InventoryItemDisplayController >;
	protected var slotIndex : Int32;
	protected var selectedItem : weak< InventoryItemDisplayController >;
	protected var tooltipsManager : weak< gameuiTooltipsManager >;
	private editable var m_transmogCtrlsContainer : inkCompoundRef;
	private var m_transmogIndicatorCtrl : weak< TransmogButtonView >;
	private var m_transmogIndicator : weak< inkWidget >;

	public function Bind( playerArg : weak< PlayerPuppet >, inventoryDataManagerArg : InventoryDataManagerV2, equipmentAreaArg : gamedataEquipmentArea, optional slotIndexArg : Int32, optional tooltipsManagerArg : weak< gameuiTooltipsManager >, optional showTransmogedIcon : Bool )
	{
		player = playerArg;
		inventoryDataManager = inventoryDataManagerArg;
		equipmentArea = equipmentAreaArg;
		slotIndex = slotIndexArg;
		tooltipsManager = tooltipsManagerArg;
		RefreshItems( false, 0, showTransmogedIcon );
		PlayLibraryAnimationOnAutoSelectedTargets( GetIntroAnimation(), GetRootWidget() );
	}

	public function BindUIScriptableSystem( scriptableSystem : weak< UIScriptableSystem > )
	{
		uiScriptableSystem = scriptableSystem;
		itemDisplay.BindUIScriptableSystem( scriptableSystem );
	}

	protected virtual function GetDisplayToSpawn() : CName
	{
		return ( ( this.equipmentArea == gamedataEquipmentArea.Outfit ) ? ( 'outfitDisplay' ) : ( 'itemDisplay' ) );
	}

	protected virtual function GetSlotDisplayToSpawn() : CName
	{
		return 'itemDisplay';
	}

	protected virtual function GetIntroAnimation() : CName
	{
		return 'genericItemChoser_intro';
	}

	public virtual function RequestClose() : Bool
	{
		return true;
	}

	public virtual function RefreshItems( optional overrideClothingSet : Bool, optional clothingSetIndex : Int32, optional showTransmogedIcon : Bool )
	{
		RefreshMainItem( overrideClothingSet, clothingSetIndex, showTransmogedIcon );
		RebuildSlots();
	}

	public virtual function RefreshSelectedItem() {}

	protected virtual function RefreshMainItem( optional overrideClothingSet : Bool, optional clothingSetIndex : Int32, optional showTransmogedIcon : Bool )
	{
		var isOutfitSlot : Bool;
		var equippedClothingSetIndex : Int32;
		var clothingSet : gameWardrobeClothingSetIndex;
		if( overrideClothingSet )
		{
			equippedClothingSetIndex = clothingSetIndex;
		}
		else
		{
			isOutfitSlot = equipmentArea == gamedataEquipmentArea.Outfit;
			if( isOutfitSlot )
			{
				clothingSet = GameInstance.GetWardrobeSystem( player.GetGame() ).GetActiveClothingSetIndex();
				equippedClothingSetIndex = WardrobeSystem.WardrobeClothingSetIndexToNumber( clothingSet );
			}
			else
			{
				equippedClothingSetIndex = -1;
			}
		}
		if( !( itemDisplay ) )
		{
			inkCompoundRef.RemoveAllChildren( m_itemContainer );
			itemDisplay = ( ( InventoryItemDisplayController )( ItemDisplayUtils.SpawnCommonSlotController( this, m_itemContainer, GetDisplayToSpawn() ) ) );
			itemDisplay.SetItemCounterDisabled( true );
			itemDisplay.Bind( inventoryDataManager, equipmentArea, slotIndex, ItemDisplayContext.GearPanel, equippedClothingSetIndex > -1, equippedClothingSetIndex );
			itemDisplay.SetTransmoged( showTransmogedIcon );
			itemDisplay.GetRootWidget().RegisterToCallback( 'OnRelease', this, 'OnItemInventoryClick' );
			itemDisplay.GetRootWidget().RegisterToCallback( 'OnHoverOver', this, 'OnInventoryItemHoverOver' );
			itemDisplay.GetRootWidget().RegisterToCallback( 'OnHoverOut', this, 'OnInventoryItemHoverOut' );
			ChangeSelectedItem( itemDisplay );
		}
		else
		{
			itemDisplay.InvalidateContent( ( equippedClothingSetIndex > -1 ) || overrideClothingSet, equippedClothingSetIndex );
			itemDisplay.SetTransmoged( showTransmogedIcon );
		}
	}

	public function CanEquipVisuals( targetItem : ItemID ) : Bool
	{
		var itemData : InventoryItemData;
		var transmogItem : ItemID;
		if( !( inventoryDataManager.IsTransmogEnabled() ) )
		{
			return false;
		}
		itemData = itemDisplay.GetItemData();
		if( ( ( !( InventoryItemData.IsEmpty( itemData ) ) && ( InventoryItemData.GetID( itemData ) != targetItem ) ) && InventoryDataManagerV2.IsAreaClothing( equipmentArea ) ) && gamedataEquipmentArea.Outfit != equipmentArea )
		{
			transmogItem = inventoryDataManager.GetVisualItemInSlot( equipmentArea );
			if( transmogItem != targetItem )
			{
				return true;
			}
		}
		return false;
	}

	protected virtual function GetSlots() : array< InventoryItemAttachments >
	{
		var itemData : InventoryItemData;
		itemData = itemDisplay.GetItemData();
		return InventoryUtils.GetMods( itemData, true );
	}

	protected virtual function ForceDisplayLabel() : Bool
	{
		return false;
	}

	protected virtual function RebuildSlots()
	{
		var itemData : InventoryItemData;
		var i, j, numberOfSlots : Int32;
		var slot : weak< InventoryItemDisplayController >;
		var slots : array< InventoryItemAttachments >;
		var allItemSlots : array< SPartSlots >;
		var itemSlot : SPartSlots;
		var quality : gamedataQuality;
		slots = GetSlots();
		numberOfSlots = slots.Size();
		itemData = itemDisplay.GetItemData();
		if( !( InventoryItemData.IsEmpty( itemData ) ) && InventoryDataManagerV2.IsEquipmentAreaCyberware( InventoryItemData.GetEquipmentArea( itemData ) ) )
		{
			numberOfSlots = 0;
		}
		inkTextRef.SetVisible( m_slotsRootLabel, ( numberOfSlots > 0 ) || ForceDisplayLabel() );
		while( inkCompoundRef.GetNumChildren( m_slotsContainer ) > numberOfSlots )
		{
			inkCompoundRef.RemoveChildByIndex( m_slotsContainer, inkCompoundRef.GetNumChildren( m_slotsContainer ) - 1 );
		}
		while( inkCompoundRef.GetNumChildren( m_slotsContainer ) < numberOfSlots )
		{
			slot = ( ( InventoryItemDisplayController )( ItemDisplayUtils.SpawnCommonSlotController( this, m_slotsContainer, GetSlotDisplayToSpawn() ) ) );
			if( slot )
			{
				slot.GetRootWidget().RegisterToCallback( 'OnRelease', this, 'OnItemInventoryClick' );
				slot.GetRootWidget().RegisterToCallback( 'OnHoverOver', this, 'OnInventoryItemHoverOver' );
				slot.GetRootWidget().RegisterToCallback( 'OnHoverOut', this, 'OnInventoryItemHoverOut' );
			}
			else
			{
				break;
			}
		}
		allItemSlots = ItemModificationSystem.GetAllSlots( this.player, InventoryItemData.GetID( itemData ) );
		for( i = 0; i < numberOfSlots; i += 1 )
		{
			slot = ( ( InventoryItemDisplayController )( inkCompoundRef.GetWidgetByIndex( m_slotsContainer, i ).GetController() ) );
			slot.SetDefaultShadowIcon( 'mod_software' );
			if( TDBID.IsValid( slots[ i ].SlotID ) )
			{
				for( j = 0; j < allItemSlots.Size(); j += 1 )
				{
					itemSlot = allItemSlots[ j ];
					if( itemSlot.slotID == InventoryItemData.GetSlotID( slots[ i ].ItemData ) )
					{
						if( InnerItemData.HasStatData( itemSlot.innerItemData, gamedataStatType.Quality ) )
						{
							quality = RPGManager.GetInnerItemDataQuality( itemSlot.innerItemData );
							InventoryItemData.SetQuality( slots[ i ].ItemData, UIItemsHelper.QualityEnumToName( quality ) );
							InventoryItemData.SetQualityF( slots[ i ].ItemData, UIItemsHelper.GetQualityF( slots[ i ].ItemData ) );
						}
					}
				}
				slot.SetParentItem( InventoryItemData.GetGameItemData( itemData ) );
				slot.Setup( inventoryDataManager, slots[ i ].ItemData, slots[ i ].SlotID, ItemDisplayContext.Attachment, true );
			}
		}
	}

	protected event OnItemInventoryClick( e : inkPointerEvent )
	{
		var widget : inkWidget;
		var controller : weak< InventoryItemDisplayController >;
		widget = e.GetCurrentTarget();
		controller = ( ( InventoryItemDisplayController )( widget.GetController() ) );
		if( !( controller ) )
		{
			return 0;
		}
		if( InventoryGPRestrictionHelper.CanUse( controller.GetItemData(), ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( inventoryDataManager.GetGame() ).GetLocalPlayerMainGameObject() ) ) ) )
		{
			if( e.IsAction( 'click' ) )
			{
				if( ( controller.GetDisplayContext() == ItemDisplayContext.Attachment && ( controller.GetNewItems() == 0 ) ) && controller.IsEmpty() )
				{
					return false;
				}
				if( this.selectedItem != controller )
				{
					ChangeSelectedItem( controller );
				}
			}
			else if( e.IsAction( 'unequip_item' ) )
			{
				PlayRumble( RumbleStrength.Light, RumbleType.Pulse, RumblePosition.Right );
				if( controller == itemDisplay )
				{
					UnequipItem( controller );
				}
				else
				{
					UnequipItemMods( controller );
					ChangeSelectedItem( controller );
				}
			}
		}
		else
		{
			if( e.IsAction( 'unequip_item' ) || e.IsAction( 'select' ) )
			{
				ShowNotification( inventoryDataManager.GetGame(), DetermineUIMenuNotificationType() );
			}
		}
	}

	public function SelectMainItem()
	{
		ChangeSelectedItem( itemDisplay );
	}

	protected function ChangeSelectedItem( controller : weak< InventoryItemDisplayController > )
	{
		var ev : ItemChooserItemChanged;
		if( this.selectedItem )
		{
			this.selectedItem.SetHighlighted( false );
		}
		this.selectedItem = controller;
		controller.SetHighlighted( true );
		if( controller )
		{
			controller.ShowSelectionArrow();
			ev = new ItemChooserItemChanged;
			ev.itemData = controller.GetItemData();
			ev.slotIndex = slotIndex;
			ev.slotID = controller.GetSlotID();
			ev.itemEquipmentArea = equipmentArea;
			QueueEvent( ev );
		}
	}

	protected function UnequipItem( controller : weak< InventoryItemDisplayController > )
	{
		var ev : ItemChooserUnequipItem;
		ev = new ItemChooserUnequipItem;
		ev.itemData = itemDisplay.GetItemData();
		QueueEvent( ev );
	}

	protected function UnequipItemMods( controller : weak< InventoryItemDisplayController > )
	{
		var ev : ItemChooserUnequipMod;
		var notification : UIMenuNotificationEvent;
		if( RPGManager.CanPartBeUnequipped( controller.GetItemData(), controller.GetSlotID() ) )
		{
			ev = new ItemChooserUnequipMod;
			ev.itemData = itemDisplay.GetItemData();
			ev.slotID = controller.GetSlotID();
			QueueEvent( ev );
		}
		else
		{
			notification = new UIMenuNotificationEvent;
			notification.m_notificationType = UIMenuNotificationType.InventoryActionBlocked;
			GameInstance.GetUISystem( inventoryDataManager.GetGame() ).QueueEvent( notification );
		}
	}

	public function GetSlotIndex() : Int32
	{
		return slotIndex;
	}

	public function GetSelectedItem() : weak< InventoryItemDisplayController >
	{
		return selectedItem;
	}

	public virtual function GetModifiedItem() : weak< InventoryItemDisplayController >
	{
		return itemDisplay;
	}

	public virtual function GetModifiedItemData() : InventoryItemData
	{
		return itemDisplay.GetItemData();
	}

	public virtual function GetModifiedItemID() : ItemID
	{
		return InventoryItemData.GetID( GetModifiedItemData() );
	}

	public virtual function GetSelectedSlotID() : TweakDBID
	{
		return selectedItem.GetSlotID();
	}

	protected event OnInventoryItemHoverOver( evt : inkPointerEvent )
	{
		var controller : weak< InventoryItemDisplayController >;
		var itemChooserItemHoverOverEvent : ItemChooserItemHoverOver;
		if( tooltipsManager )
		{
			controller = GetInventoryItemDisplayControllerFromTarget( evt );
			itemChooserItemHoverOverEvent = new ItemChooserItemHoverOver;
			itemChooserItemHoverOverEvent.sourceEvent = evt;
			itemChooserItemHoverOverEvent.targetItem = controller;
			QueueEvent( itemChooserItemHoverOverEvent );
		}
	}

	protected event OnInventoryItemHoverOut( evt : inkPointerEvent )
	{
		var itemChooserItemHoverOutEvent : ItemChooserItemHoverOut;
		HideTooltips();
		itemChooserItemHoverOutEvent = new ItemChooserItemHoverOut;
		itemChooserItemHoverOutEvent.sourceEvent = evt;
		QueueEvent( itemChooserItemHoverOutEvent );
	}

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

	private function HideTooltips()
	{
		if( tooltipsManager )
		{
			tooltipsManager.HideTooltips();
		}
	}

	public function GetEquipmentArea() : gamedataEquipmentArea
	{
		var modifiedItem : InventoryItemData;
		modifiedItem = GetModifiedItemData();
		return InventoryItemData.GetEquipmentArea( modifiedItem );
	}

	public virtual function IsAttachmentItem( const itemData : ref< InventoryItemData > ) : Bool
	{
		var i : Int32;
		var slots : array< InventoryItemAttachments >;
		slots = GetSlots();
		for( i = 0; i < slots.Size(); i += 1 )
		{
			if( slots[ i ].ItemData == itemData )
			{
				return true;
			}
		}
		return false;
	}

	private function ShowNotification( gameInstance : GameInstance, type : UIMenuNotificationType )
	{
		var inventoryNotification : UIMenuNotificationEvent;
		inventoryNotification = new UIMenuNotificationEvent;
		inventoryNotification.m_notificationType = type;
		GameInstance.GetUISystem( gameInstance ).QueueEvent( inventoryNotification );
	}

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

}

class ItemChooserItemChanged extends Event
{
	var itemData : InventoryItemData;
	var itemEquipmentArea : gamedataEquipmentArea;
	var slotIndex : Int32;
	var slotID : TweakDBID;
}

class ItemChooserUnequipItem extends Event
{
	var itemData : InventoryItemData;
}

class ItemChooserUnequipMod extends Event
{
	var itemData : InventoryItemData;
	var slotID : TweakDBID;
}

class ItemChooserItemHoverOver extends Event
{
	var sourceEvent : inkPointerEvent;
	var targetItem : weak< InventoryItemDisplayController >;
}

class ItemChooserItemHoverOut extends Event
{
	var sourceEvent : inkPointerEvent;
}

class ItemChooserUnequipVisuals extends Event
{
	var itemData : InventoryItemData;
}

