class DpadWheelGameController extends inkHUDGameController
{
	private editable var m_haskMarkContainer : inkCompoundRef;
	private editable var m_itemContainer : inkCompoundRef;
	private editable var m_selectorWrapper : inkWidgetRef;
	private editable var m_centerIcon : inkWidgetRef;
	private editable var m_centerGlow : inkWidgetRef;
	private editable var m_itemLabel : inkTextRef;
	private editable var m_itemDesc : inkTextRef;
	private editable var m_buttonHintsManagerRef : inkWidgetRef;
	private editable var m_indicator02 : inkImageRef;
	private editable var m_indicator03 : inkImageRef;
	private editable var m_indicator04 : inkImageRef;
	private editable var m_indicator05 : inkImageRef;
	private editable var m_indicator06 : inkImageRef;
	private editable var m_indicator07 : inkImageRef;
	private editable var m_indicator08 : inkImageRef;
	private editable var m_itemDistance : Float;
	default m_itemDistance = 450.0;
	private editable var m_hashMarkDistance : Float;
	default m_hashMarkDistance = 350.0;
	private editable var m_minDistance : Float;
	default m_minDistance = 0.2;
	private var m_root : weak< inkWidget >;
	private var m_Player : weak< PlayerPuppet >;
	private var m_QuickSlotsManager : weak< QuickSlotsManager >;
	private var m_InventoryDataManager : InventoryDataManagerV2;
	private var m_dpadItemsList : array< weak< DpadWheelItemController > >;
	private var m_commandsList : array< QuickSlotCommand >;
	private var m_selectedWheelItem : weak< DpadWheelItemController >;
	private var m_buttonHintsController : weak< ButtonHints >;
	private var m_selectedIndicator : inkWidgetRef;
	private var m_angleInterval : Float;
	private var m_previousAmount : Float;
	private var m_previousAngle : Float;
	private var m_data : QuickWheelStartUIStructure;
	private var m_masterListOfAllCyberware : array< AbilityData >;
	private var m_listOfUnassignedCyberware : array< AbilityData >;
	private var m_dpadWheelOpen : Bool;
	private var m_neutralChoiceDelayId : DelayID;
	private var m_previouslySelectedData : QuickSlotCommand;
	private var m_UiQuickItemsBlackboard : weak< IBlackboard >;
	private var m_UiQuickSlotDef : UI_QuickSlotsDataDef;
	private var m_DPadWheelAngleBBID : CallbackHandle;
	private var m_DPadWheelInterationStartedBBID : CallbackHandle;
	private var m_DPadWheelInterationEndedBBID : CallbackHandle;
	private var m_DpadWheelCyberwareAssignedBBID : CallbackHandle;

	protected event OnInitialize()
	{
		var buttonHints : weak< inkWidget >;
		m_Player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( ( ( GameObject )( GetOwnerEntity() ) ).GetGame() ).GetLocalPlayerMainGameObject() ) );
		m_QuickSlotsManager = m_Player.GetQuickSlotsManager();
		m_InventoryDataManager = new InventoryDataManagerV2;
		m_InventoryDataManager.Initialize( m_Player );
		m_root = GetRootCompoundWidget();
		m_root.SetVisible( false );
		buttonHints = SpawnFromExternal( inkWidgetRef.Get( m_buttonHintsManagerRef ), R"base\gameplay\gui\common\buttonhints.inkwidget", 'Root' );
		buttonHints.SetHAlign( inkEHorizontalAlign.Right );
		m_buttonHintsController = ( ( ButtonHints )( buttonHints.GetController() ) );
		m_buttonHintsController.AddButtonHint( EInputKey.IK_Pad_B_CIRCLE, GetLocalizedText( "Common-Access-Close" ) );
		m_buttonHintsController.AddButtonHint( EInputKey.IK_Pad_A_CROSS, GetLocalizedText( "Common-Access-Select" ) );
		inkImageRef.SetVisible( m_indicator02, false );
		inkImageRef.SetVisible( m_indicator03, false );
		inkImageRef.SetVisible( m_indicator04, false );
		inkImageRef.SetVisible( m_indicator05, false );
		inkImageRef.SetVisible( m_indicator06, false );
		inkImageRef.SetVisible( m_indicator07, false );
		inkImageRef.SetVisible( m_indicator08, false );
		SetupBB();
		RegisterGameInput();
	}

	protected event OnUninitialize()
	{
		UnegisterGameInput();
		m_InventoryDataManager.UnInitialize();
		m_buttonHintsController.ClearButtonHints();
		RemoveBB();
	}

	private function SetupBB()
	{
		m_UiQuickSlotDef = GetAllBlackboardDefs().UI_QuickSlotsData;
		m_UiQuickItemsBlackboard = GetBlackboardSystem().Get( m_UiQuickSlotDef );
		if( m_UiQuickItemsBlackboard )
		{
			m_DPadWheelAngleBBID = m_UiQuickItemsBlackboard.RegisterDelayedListenerFloat( m_UiQuickSlotDef.UIRadialContextRightStickAngle, this, 'OnRadialAngleChanged' );
			m_DPadWheelInterationStartedBBID = m_UiQuickItemsBlackboard.RegisterDelayedListenerVariant( m_UiQuickSlotDef.WheelInteractionStarted, this, 'OnWheelInteractionStarted' );
			m_DPadWheelInterationEndedBBID = m_UiQuickItemsBlackboard.RegisterDelayedListenerVariant( m_UiQuickSlotDef.WheelInteractionEnded, this, 'OnWheelInteractionEnded' );
			m_DpadWheelCyberwareAssignedBBID = m_UiQuickItemsBlackboard.RegisterDelayedListenerBool( m_UiQuickSlotDef.CyberwareAssignmentComplete, this, 'OnCyberwareAssigned' );
		}
	}

	private function RemoveBB()
	{
		if( m_UiQuickItemsBlackboard )
		{
			m_UiQuickItemsBlackboard.UnregisterDelayedListener( m_UiQuickSlotDef.UIRadialContextRightStickAngle, m_DPadWheelAngleBBID );
			m_UiQuickItemsBlackboard.UnregisterDelayedListener( m_UiQuickSlotDef.WheelInteractionStarted, m_DPadWheelInterationStartedBBID );
			m_UiQuickItemsBlackboard.UnregisterDelayedListener( m_UiQuickSlotDef.WheelInteractionEnded, m_DPadWheelInterationEndedBBID );
		}
		m_UiQuickItemsBlackboard = NULL;
	}

	protected event OnRadialAngleChanged( value : Float )
	{
		UpdateRotation( value );
	}

	protected event OnWheelInteractionStarted( value : Variant )
	{
		var startEvent : QuickWheelStartUIStructure;
		startEvent = ( ( QuickWheelStartUIStructure )value );
		if( ( startEvent.WheelItems.Size() <= 0 ) && startEvent.dpadSlot == EDPadSlot.Left )
		{
			return false;
		}
		ShowDPadWheel( startEvent );
		UnselectAllItems();
		m_dpadWheelOpen = true;
		InitSelection();
	}

	private function RegisterGameInput()
	{
		m_Player.RegisterInputListener( this, 'UI_PreviousAbility' );
		m_Player.RegisterInputListener( this, 'UI_NextAbility' );
		m_Player.RegisterInputListener( this, 'UI_MoveX_Axis' );
		m_Player.RegisterInputListener( this, 'UI_MoveY_Axis' );
		m_Player.RegisterInputListener( this, 'UI_LookX_Axis' );
		m_Player.RegisterInputListener( this, 'UI_LookY_Axis' );
	}

	private function UnegisterGameInput()
	{
		m_Player.UnregisterInputListener( this, 'UI_PreviousAbility' );
		m_Player.UnregisterInputListener( this, 'UI_NextAbility' );
		m_Player.UnregisterInputListener( this, 'UI_MoveX_Axis' );
		m_Player.UnregisterInputListener( this, 'UI_MoveY_Axis' );
		m_Player.UnregisterInputListener( this, 'UI_LookX_Axis' );
		m_Player.UnregisterInputListener( this, 'UI_LookY_Axis' );
	}

	private function InitSelection()
	{
		var i : Int32;
		var slotController : weak< DpadWheelItemController >;
		var data : QuickSlotCommand;
		var activeItemId : ItemID;
		activeItemId = EquipmentSystem.GetData( m_Player ).GetActiveItem( gamedataEquipmentArea.Weapon );
		for( i = 0; i < m_dpadItemsList.Size(); i += 1 )
		{
			slotController = m_dpadItemsList[ i ];
			slotController.SetHover( false );
			data = slotController.GetData();
			if( data.ItemId == activeItemId )
			{
				slotController.SetHover( true );
				m_selectedWheelItem = slotController;
				if( data.ActionType != QuickSlotActionType.Undefined )
				{
					m_QuickSlotsManager.SetWheelItem( data );
				}
				UpdateInformationPanel( m_selectedWheelItem );
				UpdateButtonHints();
			}
		}
		inkWidgetRef.SetMargin( m_centerIcon, 0.0, 0.0, 0.0, 0.0 );
	}

	protected event OnWheelInteractionEnded( value : Variant )
	{
		HideDpadWheel();
		DelayUnselsecAllItemsCancel();
		SendSelectedItemChangeEventToEntity( m_QuickSlotsManager.GetQuickSlotCommandByDpadSlot( EDPadSlot.InteractionWheel ), true );
		UnselectAllItems();
	}

	protected event OnCyberwareAssigned( value : Bool )
	{
		var data : QuickSlotCommand;
		RefreshRadial();
		UpdateRotation( m_previousAngle );
		data = m_selectedWheelItem.GetData();
		if( data.ActionType != QuickSlotActionType.Undefined )
		{
			m_QuickSlotsManager.SetWheelItem( data );
		}
	}

	protected event OnAction( action : ListenerAction, consumer : ListenerActionConsumer )
	{
		if( !( m_dpadWheelOpen ) )
		{
			return false;
		}
		if( ListenerAction.GetType( action ) == gameinputActionType.BUTTON_RELEASED )
		{
			if( ListenerAction.GetName( action ) == 'UI_PreviousAbility' )
			{
				CycleToAbility( -1 );
			}
			else if( ListenerAction.GetName( action ) == 'UI_NextAbility' )
			{
				CycleToAbility( 1 );
			}
		}
		if( ListenerAction.GetType( action ) == gameinputActionType.AXIS_CHANGE )
		{
			if( ListenerAction.GetName( action ) == 'UI_LookX_Axis' || ListenerAction.GetName( action ) == 'UI_LookY_Axis' )
			{
				UpdateAxisIndicator( ListenerAction.GetValue( action ), ListenerAction.GetName( action ) );
			}
			if( ListenerAction.GetName( action ) == 'UI_MoveX_Axis' || ListenerAction.GetName( action ) == 'UI_MoveY_Axis' )
			{
				UpdateAxisIndicator( ListenerAction.GetValue( action ), ListenerAction.GetName( action ) );
			}
		}
	}

	private function UpdateAxisIndicator( value : Float, actionName : CName )
	{
		var amount : Float;
		var dist : Float;
		var centerIconOldMargin : inkMargin;
		var emptyDelayID : DelayID;
		var applyChange : Bool;
		dist = -30.0;
		amount = value;
		centerIconOldMargin = inkWidgetRef.GetMargin( m_centerIcon );
		if( ( ( Bool )m_previousAngle ) )
		{
			if( AbsF( amount ) > 0.0 )
			{
				if( actionName == 'UI_MoveX_Axis' || actionName == 'UI_LookX_Axis' )
				{
					centerIconOldMargin.left = dist * -( amount );
				}
				if( actionName == 'UI_MoveY_Axis' || actionName == 'UI_LookY_Axis' )
				{
					centerIconOldMargin.top = dist * amount;
				}
				inkWidgetRef.SetMargin( m_centerIcon, centerIconOldMargin );
				applyChange = true;
			}
		}
		else
		{
			inkWidgetRef.SetMargin( m_centerIcon, centerIconOldMargin );
			applyChange = true;
		}
		if( ( applyChange && ( centerIconOldMargin.left == 0.0 ) ) && ( centerIconOldMargin.top == 0.0 ) )
		{
			inkWidgetRef.SetVisible( m_centerGlow, true );
			if( m_neutralChoiceDelayId == emptyDelayID )
			{
			}
		}
		m_previousAmount = amount;
	}

	private function DelayUnselectAllItems()
	{
		var delayEvt : UndelectAllItemsDelayedEvent;
		delayEvt = new UndelectAllItemsDelayedEvent;
		m_neutralChoiceDelayId = GameInstance.GetDelaySystem( GetPlayerControlledObject().GetGame() ).DelayEvent( GetOwnerEntity(), delayEvt, 0.1, false );
	}

	private function DelayUnselsecAllItemsCancel()
	{
		var emptyDelayID : DelayID;
		if( m_neutralChoiceDelayId != emptyDelayID )
		{
			GameInstance.GetDelaySystem( GetPlayerControlledObject().GetGame() ).CancelDelay( m_neutralChoiceDelayId );
			m_neutralChoiceDelayId = emptyDelayID;
		}
	}

	protected event OnUndelectAllItemsDelayedEvent( evt : UndelectAllItemsDelayedEvent )
	{
		UnselectAllItems();
	}

	private function UnselectAllItems()
	{
		var emptyData : QuickSlotCommand;
		var emptyItem : weak< DpadWheelItemController >;
		m_previouslySelectedData = m_selectedWheelItem.GetData();
		emptyData.itemType = m_previouslySelectedData.itemType;
		inkWidgetRef.SetVisible( m_centerGlow, true );
		m_selectedWheelItem.SetHover( false );
		m_QuickSlotsManager.SetWheelItem( emptyData );
		UpdateInformationPanel( emptyItem );
		emptyData.itemType = QuickSlotItemType.Interaction;
		m_QuickSlotsManager.SetWheelItem( emptyData );
	}

	private function ShowDPadWheel( const eventData : ref< QuickWheelStartUIStructure > )
	{
		m_root.SetVisible( true );
		m_data = eventData;
		RefreshRadial();
	}

	private function RefreshRadial()
	{
		GetAllDpadCommands();
		CreateHashMarks();
		CreateWheelItems();
		UpdateVirtualAbilitiesList();
		UpdateInformationPanel( m_selectedWheelItem );
	}

	private function GetAllDpadCommands()
	{
		m_commandsList.Clear();
		SetupCommandList( m_data.WheelItems );
	}

	private function AddCommandsToList( const originalList : ref< array< QuickSlotCommand > >, newList : array< QuickSlotCommand > ) : array< QuickSlotCommand >
	{
		var i : Int32;
		for( i = 0; i < originalList.Size(); i += 1 )
		{
			newList.PushBack( originalList[ i ] );
		}
		return newList;
	}

	private function SetupCommandList( const data : ref< array< QuickSlotCommand > > )
	{
		m_commandsList = data;
		m_angleInterval = ( ( Float )( 360.0 ) ) / ( ( Float )( m_commandsList.Size() ) );
	}

	private function CreateWheelItems()
	{
		var itemController : weak< DpadWheelItemController >;
		var itemWidget : inkWidget;
		var itemAngle : Float;
		var i, limit : Int32;
		limit = m_commandsList.Size();
		while( m_dpadItemsList.Size() > limit )
		{
			itemController = m_dpadItemsList.PopBack();
			inkCompoundRef.RemoveChild( m_itemContainer, itemController.GetRootWidget() );
		}
		while( m_dpadItemsList.Size() < limit )
		{
			itemWidget = SpawnFromLocal( inkCompoundRef.Get( m_itemContainer ), 'dpadWheelItem' );
			itemController = ( ( DpadWheelItemController )( itemWidget.GetController() ) );
			m_dpadItemsList.PushBack( itemController );
		}
		for( i = 0; i < inkCompoundRef.GetNumChildren( m_itemContainer ); i += 1 )
		{
			itemAngle = m_angleInterval * ( ( Float )( i ) );
			itemWidget = inkCompoundRef.GetWidgetByIndex( m_itemContainer, i );
			itemWidget.SetMargin( CalculatePosition( i, m_itemDistance ) );
			itemWidget.SetRotation( itemAngle );
		}
		for( i = 0; i < limit; i += 1 )
		{
			itemController = m_dpadItemsList[ i ];
			if( itemController )
			{
				itemAngle = m_angleInterval * ( ( Float )( i ) );
				itemController.SetupData( m_commandsList[ i ], itemAngle, m_commandsList.Size(), m_InventoryDataManager, IsLeft( itemWidget.GetMargin() ) );
			}
		}
	}

	private function CreateHashMarks()
	{
		var itemWidget : inkWidget;
		var i : Int32;
		inkCompoundRef.RemoveAllChildren( m_haskMarkContainer );
		for( i = 0; i < m_commandsList.Size(); i += 1 )
		{
			itemWidget = SpawnFromLocal( inkCompoundRef.Get( m_haskMarkContainer ), 'hashMark' );
			itemWidget.SetMargin( CalculatePosition( i, m_hashMarkDistance ) );
			itemWidget.SetRotation( m_angleInterval * ( ( Float )( i ) ) );
		}
		inkCompoundRef.SetRotation( m_haskMarkContainer, m_angleInterval / 2.0 );
	}

	private function SetupSelectorMask()
	{
		inkImageRef.SetVisible( m_indicator02, false );
		inkImageRef.SetVisible( m_indicator03, false );
		inkImageRef.SetVisible( m_indicator04, false );
		inkImageRef.SetVisible( m_indicator05, false );
		inkImageRef.SetVisible( m_indicator06, false );
		inkImageRef.SetVisible( m_indicator07, false );
		inkImageRef.SetVisible( m_indicator08, false );
		switch( m_commandsList.Size() )
		{
			case 1:
			case 2:
				m_selectedIndicator = m_indicator02;
			break;
			case 3:
				m_selectedIndicator = m_indicator03;
			break;
			case 4:
				m_selectedIndicator = m_indicator04;
			break;
			case 5:
				m_selectedIndicator = m_indicator05;
			break;
			case 6:
				m_selectedIndicator = m_indicator06;
			break;
			case 7:
				m_selectedIndicator = m_indicator07;
			break;
			case 8:
				m_selectedIndicator = m_indicator08;
			break;
		}
		inkWidgetRef.SetVisible( m_selectedIndicator, true );
	}

	private function UpdateRotation( angleFloat : Float )
	{
		var i : Int32;
		var selectedIndex : Int32;
		var isSelected : Bool;
		var currLogicController : weak< DpadWheelItemController >;
		var tempAngle : Float;
		var data : QuickSlotCommand;
		var emptyStruct : QuickWheelStartUIStructure;
		emptyStruct = ( ( QuickWheelStartUIStructure )( GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_QuickSlotsData ).GetVariant( GetAllBlackboardDefs().UI_QuickSlotsData.WheelInteractionStarted ) ) );
		if( ( emptyStruct.WheelItems.Size() <= 0 ) && emptyStruct.dpadSlot == EDPadSlot.Left )
		{
			return;
		}
		m_previousAngle = angleFloat;
		tempAngle = angleFloat;
		tempAngle -= 45.0;
		if( tempAngle > 360.0 )
		{
			tempAngle = tempAngle - 360.0;
		}
		if( tempAngle < 0.0 )
		{
			tempAngle = 360.0 + tempAngle;
		}
		selectedIndex = -1;
		selectedIndex = RoundF( tempAngle / m_angleInterval );
		if( selectedIndex > m_dpadItemsList.Size() )
		{
			selectedIndex = 0;
		}
		for( i = 0; i < m_dpadItemsList.Size(); i += 1 )
		{
			isSelected = selectedIndex == i;
			currLogicController = m_dpadItemsList[ i ];
			currLogicController.SetHover( isSelected );
			if( isSelected && ( QuickSlotCommand.IsEmpty( m_QuickSlotsManager.GetWheelItem( currLogicController.GetData() ) ) || ( m_selectedWheelItem != currLogicController ) ) )
			{
				m_selectedWheelItem = currLogicController;
				data = m_selectedWheelItem.GetData();
				if( data.ActionType != QuickSlotActionType.Undefined )
				{
					m_QuickSlotsManager.SetWheelItem( data );
				}
				UpdateInformationPanel( m_selectedWheelItem );
				UpdateButtonHints();
			}
		}
		inkWidgetRef.SetRotation( m_selectorWrapper, angleFloat += 180.0 );
	}

	private function UpdateInformationPanel( item : weak< DpadWheelItemController > )
	{
		var itemData : InventoryItemData;
		var abilityData : AbilityData;
		var commandData : QuickSlotCommand;
		var assembledString : String;
		inkTextRef.SetText( m_itemLabel, "" );
		inkTextRef.SetText( m_itemDesc, "" );
		if( item )
		{
			itemData = item.GetItemData();
			commandData = item.GetData();
			inkTextRef.SetText( m_itemLabel, commandData.Title );
			switch( commandData.ActionType )
			{
				case QuickSlotActionType.QuickHack:
				{
					inkTextRef.SetText( m_itemDesc, commandData.Description );
					SendSelectedItemChangeEventToEntity( commandData );
					break;
				}
				case QuickSlotActionType.SelectRadioStation:
					inkTextRef.SetText( m_itemDesc, commandData.Type );
				break;
				case QuickSlotActionType.SelectItem:
				{
					if( commandData.equipType == gamedataEquipmentArea.CyberwareWheel )
					{
						abilityData = item.GetAbilityData();
						inkTextRef.SetText( m_itemLabel, abilityData.Name );
						inkTextRef.SetText( m_itemDesc, abilityData.Description );
					}
					else
					{
						if( !( itemData.Empty ) )
						{
							if( itemData.EquipmentArea == gamedataEquipmentArea.Weapon )
							{
								assembledString += ( "AMMO: " + ( ( String )( m_InventoryDataManager.GetAmmoForWeaponType( itemData ) ) ) );
								assembledString += ( ( "\n" + "DAMAGE TYPE: " ) + ( ( String )( itemData.DamageType ) ) );
								inkTextRef.SetText( m_itemDesc, assembledString );
							}
							else
							{
								inkTextRef.SetText( m_itemDesc, itemData.Description );
							}
						}
					}
					break;
				}
				case QuickSlotActionType.Undefined:
				{
					if( commandData.equipType == gamedataEquipmentArea.CyberwareWheel )
					{
						abilityData = item.GetAbilityData();
						inkTextRef.SetText( m_itemLabel, abilityData.Name );
						inkTextRef.SetText( m_itemDesc, abilityData.Description );
					}
					break;
				}
			}
		}
		else
		{
			SendSelectedItemChangeEventToEntity( m_previouslySelectedData, true );
			m_previouslySelectedData = commandData;
		}
	}

	private function SendSelectedItemChangeEventToEntity( const data : ref< QuickSlotCommand >, optional currentEmpty : Bool ) {}

	private function CycleToAbility( dir : Int32 )
	{
		var commandData : QuickSlotCommand;
		var nextAbility : AbilityData;
		if( m_selectedWheelItem )
		{
			commandData = m_selectedWheelItem.GetData();
			if( commandData.equipType == gamedataEquipmentArea.CyberwareWheel )
			{
				nextAbility = GetNextAbility( m_selectedWheelItem.GetAbilityData(), dir );
				m_selectedWheelItem.AddAbility( nextAbility );
				m_QuickSlotsManager.AssignItemToCyberwareSlot( nextAbility.ID, commandData.slotIndex );
			}
		}
	}

	private function HideDpadWheel()
	{
		var WheelAssignmentCompleteBB : IBlackboard;
		if( m_root.IsVisible() )
		{
			WheelAssignmentCompleteBB = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_QuickSlotsData );
			WheelAssignmentCompleteBB.SetBool( GetAllBlackboardDefs().UI_QuickSlotsData.WheelAssignmentComplete, true, true );
			m_root.SetVisible( false );
			m_dpadWheelOpen = false;
		}
	}

	private function UpdateButtonHints()
	{
		var commandData : QuickSlotCommand;
		if( m_selectedWheelItem )
		{
			commandData = m_selectedWheelItem.GetData();
			if( commandData.equipType == gamedataEquipmentArea.CyberwareWheel )
			{
				m_buttonHintsController.AddButtonHint( EInputKey.IK_Pad_LeftShoulder, GetLocalizedText( "Gameplay-Devices-Interactions-Previous" ) );
				m_buttonHintsController.AddButtonHint( EInputKey.IK_Pad_RightShoulder, GetLocalizedText( "Gameplay-Devices-Interactions-Next" ) );
			}
			else
			{
				m_buttonHintsController.AddButtonHint( EInputKey.IK_Pad_LeftShoulder, "" );
				m_buttonHintsController.AddButtonHint( EInputKey.IK_Pad_RightShoulder, "" );
			}
		}
	}

	private function CalculatePosition( index : Int32, dist : Float ) : inkMargin
	{
		var itemAngle : Float;
		var position : Vector2;
		var marginPosition : inkMargin;
		var itemRadian : Float;
		itemAngle = m_angleInterval * ( ( Float )( index ) );
		itemRadian = Deg2Rad( itemAngle );
		position.X = dist * CosF( itemRadian );
		position.Y = dist * SinF( itemRadian );
		marginPosition.left = -( position.X );
		marginPosition.top = -( position.Y );
		return marginPosition;
	}

	private function IsLeft( margin : inkMargin ) : Bool
	{
		var isLeft : Bool;
		if( margin.left > 0.0 )
		{
			isLeft = true;
		}
		else
		{
			isLeft = false;
		}
		return isLeft;
	}

	private function GetNextAbility( const currentAbility : ref< AbilityData >, dir : Int32 ) : AbilityData
	{
		var nextAbility : AbilityData;
		var nextIndex : Int32;
		var selectedData : AbilityData;
		var curAbilityIdx : Int32;
		selectedData = m_selectedWheelItem.GetAbilityData();
		if( currentAbility.Empty )
		{
			nextIndex = ( ( dir > 0 ) ? ( 0 ) : ( m_masterListOfAllCyberware.Size() - 1 ) );
			nextAbility = m_masterListOfAllCyberware[ nextIndex ];
			if( nextAbility == selectedData )
			{
				return selectedData;
			}
			if( CheckIfAbilityIsAssigned( nextAbility ) )
			{
				nextAbility = GetNextAbility( nextAbility, dir );
			}
		}
		else
		{
			curAbilityIdx = m_masterListOfAllCyberware.FindFirst( currentAbility );
			nextIndex = curAbilityIdx += dir;
			if( nextIndex >= m_masterListOfAllCyberware.Size() )
			{
				nextIndex = 0;
			}
			if( nextIndex < 0 )
			{
				nextIndex = m_masterListOfAllCyberware.Size() - 1;
			}
			nextAbility = m_masterListOfAllCyberware[ nextIndex ];
			if( nextAbility == selectedData )
			{
				return selectedData;
			}
			if( CheckIfAbilityIsAssigned( nextAbility ) )
			{
				nextAbility = GetNextAbility( nextAbility, dir );
			}
		}
		return nextAbility;
	}

	private function UpdateVirtualAbilitiesList()
	{
		var i, j : Int32;
		var tempDpadItem : weak< DpadWheelItemController >;
		var tempCommandData : QuickSlotCommand;
		var tempAbilityData : AbilityData;
		var matchingAbilityData : AbilityData;
		m_listOfUnassignedCyberware.Clear();
		for( i = 0; i < m_masterListOfAllCyberware.Size(); i += 1 )
		{
			m_listOfUnassignedCyberware.PushBack( m_masterListOfAllCyberware[ i ] );
		}
		for( i = 0; i < m_dpadItemsList.Size(); i += 1 )
		{
			tempDpadItem = m_dpadItemsList[ i ];
			tempCommandData = tempDpadItem.GetData();
			if( tempCommandData.equipType == gamedataEquipmentArea.CyberwareWheel )
			{
				tempAbilityData = tempDpadItem.GetAbilityData();
				if( !( tempAbilityData.Empty ) )
				{
					for( j = m_listOfUnassignedCyberware.Size() - 1; j >= 0; j -= 1 )
					{
						matchingAbilityData = m_listOfUnassignedCyberware[ j ];
						if( matchingAbilityData == tempAbilityData )
						{
							m_listOfUnassignedCyberware.Erase( j );
						}
					}
				}
			}
		}
	}

	private function CheckIfAbilityIsAssigned( const ability : ref< AbilityData > ) : Bool
	{
		var i : Int32;
		var tempAbility : AbilityData;
		for( i = 0; i < m_listOfUnassignedCyberware.Size(); i += 1 )
		{
			tempAbility = m_listOfUnassignedCyberware[ i ];
			if( ability == tempAbility )
			{
				return false;
			}
		}
		return true;
	}

}

class DpadWheelItemController extends inkLogicController
{
	private editable var m_selectorWrapper : inkWidgetRef;
	private editable var m_icon : inkImageRef;
	private editable var m_displayWrapper : inkWidgetRef;
	private editable var m_itemWrapper : inkWidgetRef;
	private editable var m_arrows : inkWidgetRef;
	private editable var m_abilityIcon : inkImageRef;
	private editable var m_quickHackIcon : inkImageRef;
	private editable var m_highlight02 : inkImageRef;
	private editable var m_highlight03 : inkImageRef;
	private editable var m_highlight04 : inkImageRef;
	private editable var m_highlight05 : inkImageRef;
	private editable var m_highlight06 : inkImageRef;
	private editable var m_highlight07 : inkImageRef;
	private editable var m_highlight08 : inkImageRef;
	private editable var m_textDist : Float;
	default m_textDist = 60;
	private editable var m_weaponTextDist : Float;
	default m_weaponTextDist = 140;
	private var m_data : QuickSlotCommand;
	private var m_root : weak< inkWidget >;
	private var m_item : weak< InventoryItemDisplay >;
	private var m_itemWidget : weak< inkWidget >;
	private var m_InventoryDataManager : InventoryDataManagerV2;
	private var m_highlight : inkImageRef;
	private var m_itemData : InventoryItemData;
	private var m_abilityData : AbilityData;
	private var m_quickHackWheelDefIcon : CName;

	protected event OnInitialize()
	{
		inkImageRef.SetVisible( m_highlight02, false );
		inkImageRef.SetVisible( m_highlight03, false );
		inkImageRef.SetVisible( m_highlight04, false );
		inkImageRef.SetVisible( m_highlight05, false );
		inkImageRef.SetVisible( m_highlight06, false );
		inkImageRef.SetVisible( m_highlight07, false );
		inkImageRef.SetVisible( m_highlight08, false );
		inkWidgetRef.SetVisible( m_arrows, false );
		inkImageRef.SetVisible( m_abilityIcon, false );
		if( m_itemWidget == NULL )
		{
			m_itemWidget = ItemDisplayUtils.SpawnCommonSlot( this, m_itemWrapper, 'inventoryItem' );
			m_itemWidget.SetScale( Vector2( 0.60000002, 0.60000002 ) );
			m_itemWidget.SetVAlign( inkEVerticalAlign.Center );
			m_itemWidget.SetHAlign( inkEHorizontalAlign.Center );
		}
	}

	public function SetupData( const data : ref< QuickSlotCommand >, rotation : Float, numOfWheelItems : Int32, inventoryManager : InventoryDataManagerV2, isLeft : Bool )
	{
		m_data = data;
		m_InventoryDataManager = inventoryManager;
		m_root = GetRootWidget();
		SetHover( false );
		SetIcon( rotation );
		SetHighlight( numOfWheelItems );
	}

	private function SetIcon( rotation : Float )
	{
		inkImageRef.SetVisible( m_abilityIcon, false );
		inkImageRef.SetVisible( m_icon, false );
		m_itemWidget.SetVisible( false );
		inkImageRef.SetVisible( m_quickHackIcon, false );
		switch( m_data.ActionType )
		{
			case QuickSlotActionType.SelectItem:
			{
				if( ItemID.IsValid( m_data.ItemId ) )
				{
					if( m_data.equipType == gamedataEquipmentArea.CyberwareWheel )
					{
						m_abilityData = m_InventoryDataManager.GetAbilityData( m_data.ItemId );
						inkImageRef.SetVisible( m_abilityIcon, true );
					}
					else
					{
						m_itemData = m_InventoryDataManager.GetItemDataFromIDInLoadout( m_data.ItemId );
						m_item = ( ( InventoryItemDisplay )( m_itemWidget.GetController() ) );
						m_item.Setup( m_itemData );
						m_itemWidget.SetVisible( true );
					}
				}
			}
			break;
			case QuickSlotActionType.QuickHack:
			{
				if( m_quickHackWheelDefIcon == '' )
				{
					m_quickHackWheelDefIcon = inkImageRef.GetTexturePart( m_quickHackIcon );
				}
				inkImageRef.SetVisible( m_quickHackIcon, true );
				if( m_data.IconName != '' )
				{
					inkImageRef.SetTexturePart( m_quickHackIcon, m_data.IconName );
				}
				else
				{
					inkImageRef.SetTexturePart( m_quickHackIcon, m_quickHackWheelDefIcon );
				}
				if( m_data.IsLocked )
				{
					inkImageRef.SetOpacity( m_quickHackIcon, 0.30000001 );
				}
				else
				{
					inkImageRef.SetOpacity( m_quickHackIcon, 1.0 );
				}
			}
			break;
			default:
				inkImageRef.SetVisible( m_icon, true );
			inkImageRef.SetTexturePart( m_icon, m_data.IconName );
			break;
		}
		inkWidgetRef.SetRotation( m_displayWrapper, -( rotation ) );
		if( m_data.equipType == gamedataEquipmentArea.CyberwareWheel )
		{
			inkWidgetRef.SetVisible( m_arrows, true );
		}
		else
		{
			inkWidgetRef.SetVisible( m_arrows, false );
		}
	}

	private function SetHighlight( numOfWheelItems : Int32 )
	{
		switch( numOfWheelItems )
		{
			case 1:
			case 2:
				m_highlight = m_highlight02;
			break;
			case 3:
				m_highlight = m_highlight03;
			break;
			case 4:
				m_highlight = m_highlight04;
			break;
			case 5:
				m_highlight = m_highlight05;
			break;
			case 6:
				m_highlight = m_highlight06;
			break;
			case 7:
				m_highlight = m_highlight07;
			break;
			case 8:
				m_highlight = m_highlight08;
			break;
			default:
				inkImageRef.SetVisible( m_highlight, false );
			break;
		}
		if( numOfWheelItems <= 8 )
		{
			inkImageRef.SetVisible( m_highlight, true );
		}
	}

	public function SetHover( isHover : Bool )
	{
		if( isHover )
		{
			m_root.SetOpacity( 1.0 );
			inkWidgetRef.SetVisible( m_selectorWrapper, true );
		}
		else
		{
			m_root.SetOpacity( 0.30000001 );
			inkWidgetRef.SetVisible( m_selectorWrapper, false );
		}
	}

	public function AddAbility( const abilityData : ref< AbilityData > )
	{
		if( !( abilityData.Empty ) )
		{
			inkImageRef.SetVisible( m_abilityIcon, true );
			m_abilityData = abilityData;
		}
	}

	public function GetData() : QuickSlotCommand
	{
		return m_data;
	}

	public function GetItemData() : InventoryItemData
	{
		return m_itemData;
	}

	public function GetAbilityData() : AbilityData
	{
		return m_abilityData;
	}

}

class QHackWheelItemChangedEvent extends Event
{
	var commandData : QuickhackData;
	var currentEmpty : Bool;
}

class UndelectAllItemsDelayedEvent extends Event
{
}

