import class inkItemPreviewGameController extends inkPreviewGameController
{
	protected import function PreviewItem( itemID : ItemID, forceCreate : Bool );

	protected function PreviewItem( itemID : ItemID )
	{
		PreviewItem( itemID, true );
	}

	protected import function ClearPreview();
	protected import function EnableCamera();
	protected import function DisableCamera();
}

class ItemPreviewGameController extends inkItemPreviewGameController
{
	private editable var m_colliderWidgetRef : inkWidgetRef;
	private var m_colliderWidget : weak< inkWidget >;
	private editable var m_itemNameText : inkTextRef;
	private editable var m_itemDescriptionText : inkTextRef;
	private editable var m_perkLine : inkWidgetRef;
	private editable var m_perkIcon : inkImageRef;
	private editable var m_perkText : inkTextRef;
	private editable var m_typeLine : inkWidgetRef;
	private editable var m_typeIcon : inkImageRef;
	private editable var m_typeText : inkTextRef;
	private editable var m_itemLevelText : inkTextRef;
	private editable var m_itemRarityWidget : inkWidgetRef;
	private var m_data : InventoryItemPreviewData;
	private var m_isMouseDown : Bool;
	private const var c_ITEM_ROTATION_SPEED : Float;
	default c_ITEM_ROTATION_SPEED = 2.0f;

	protected event OnInitialize()
	{
		super.OnInitialize();
		if( inkWidgetRef.IsValid( m_colliderWidgetRef ) )
		{
			m_colliderWidget = inkWidgetRef.Get( m_colliderWidgetRef );
		}
		else
		{
			m_colliderWidget = GetRootWidget();
		}
		m_data = ( ( InventoryItemPreviewData )( GetRootWidget().GetUserData( 'InventoryItemPreviewData' ) ) );
		inkTextRef.SetText( m_itemNameText, m_data.itemName );
		inkTextRef.SetText( m_itemDescriptionText, m_data.itemDescription );
		inkImageRef.SetTexturePart( m_typeIcon, UIItemsHelper.GetWeaponEvolutionTexturePart( m_data.itemEvolution ) );
		if( ( ( ( ( m_data.itemEvolution == gamedataWeaponEvolution.Power || m_data.itemEvolution == gamedataWeaponEvolution.Smart ) || m_data.itemEvolution == gamedataWeaponEvolution.Tech ) || m_data.itemEvolution == gamedataWeaponEvolution.Blunt ) || m_data.itemEvolution == gamedataWeaponEvolution.Blade ) || m_data.itemEvolution == gamedataWeaponEvolution.Throwable )
		{
			inkImageRef.SetVisible( m_typeIcon, true );
			inkTextRef.SetText( m_typeText, UIItemsHelper.WeaponEvolutionText( m_data.itemEvolution ) );
			inkTextRef.SetVisible( m_typeText, true );
			inkWidgetRef.SetVisible( m_typeLine, true );
		}
		else
		{
			inkImageRef.SetVisible( m_typeIcon, false );
			inkTextRef.SetVisible( m_typeText, false );
			inkWidgetRef.SetVisible( m_typeLine, false );
		}
		inkTextRef.SetText( m_itemLevelText, "Required level: " + IntToString( m_data.requiredLevel ) );
		inkWidgetRef.SetState( m_itemRarityWidget, m_data.itemQualityState );
		PreviewItem( m_data.itemID );
		m_colliderWidget.RegisterToCallback( 'OnPress', this, 'OnPress' );
		RegisterToGlobalInputCallback( 'OnPreOnRelease', this, 'OnGlobalRelease' );
		RegisterToGlobalInputCallback( 'OnPostOnRelative', this, 'OnRelativeInput' );
	}

	protected event OnUninitialize()
	{
		super.OnUninitialize();
		ClearPreview();
		m_colliderWidget.UnregisterFromCallback( 'OnPress', this, 'OnPress' );
		UnregisterFromGlobalInputCallback( 'OnPreOnRelease', this, 'OnGlobalRelease' );
		UnregisterFromGlobalInputCallback( 'OnPostOnRelative', this, 'OnRelativeInput' );
	}

	protected event OnPress( e : inkPointerEvent )
	{
		var evt : inkGameNotificationLayer_SetCursorVisibility;
		if( e.IsAction( 'mouse_left' ) )
		{
			m_isMouseDown = true;
			evt = new inkGameNotificationLayer_SetCursorVisibility;
			evt.Init( false );
			QueueEvent( evt );
		}
	}

	protected event OnGlobalRelease( e : inkPointerEvent )
	{
		var evt : inkGameNotificationLayer_SetCursorVisibility;
		if( m_isMouseDown )
		{
			if( e.IsAction( 'mouse_left' ) )
			{
				e.Consume();
				m_isMouseDown = false;
				evt = new inkGameNotificationLayer_SetCursorVisibility;
				evt.Init( true, Vector2( 0.5, 0.5 ) );
				QueueEvent( evt );
			}
		}
		else if( e.IsAction( 'cancel' ) )
		{
			m_data.token.TriggerCallback( NULL );
		}
	}

	protected override function HandleAxisInput( e : inkPointerEvent )
	{
		var amount : Float;
		var ration : Float;
		amount = e.GetAxisData();
		ration = 2.0;
		if( e.IsAction( 'left_trigger' ) || e.IsAction( 'character_preview_rotate' ) )
		{
			Rotate( amount * -( c_ITEM_ROTATION_SPEED ) );
		}
		else if( e.IsAction( 'right_trigger' ) || e.IsAction( 'character_preview_rotate' ) )
		{
			Rotate( amount * c_ITEM_ROTATION_SPEED );
		}
		else if( e.IsAction( 'right_stick_x' ) )
		{
			RotateVector( Vector3( 0.0, 0.0, amount * ration ) );
		}
		else if( e.IsAction( 'right_stick_y' ) )
		{
			RotateVector( Vector3( 0.0, amount * ration, 0.0 ) );
		}
	}

	protected event OnRelativeInput( e : inkPointerEvent )
	{
		var amount : Float;
		var ration : Float;
		amount = e.GetAxisData();
		ration = 0.25;
		if( m_isMouseDown )
		{
			if( e.IsAction( 'mouse_x' ) )
			{
				RotateVector( Vector3( 0.0, 0.0, amount * ration ) );
			}
			if( e.IsAction( 'mouse_y' ) )
			{
				RotateVector( Vector3( 0.0, amount * ration, 0.0 ) );
			}
		}
	}

}

class ItemCraftingPreviewGameController extends inkItemPreviewGameController
{

	protected event OnCrafrtingPreview( evt : CraftingItemPreviewEvent )
	{
		if( !( evt.isGarment ) )
		{
			if( ItemID.IsValid( evt.itemID ) )
			{
				EnableCamera();
				PreviewItem( evt.itemID, true );
			}
			else
			{
				DisableCamera();
			}
		}
		else
		{
			DisableCamera();
		}
	}

}

import class BaseGarmentItemPreviewGameController extends inkInventoryPuppetPreviewGameController
{
	protected var m_placementSlot : TweakDBID;
	protected var m_givenItem : ItemID;
	protected var m_initialItem : ItemID;

	protected event OnUninitialize()
	{
		ClearViewData();
		super.OnUninitialize();
	}

	protected function SetViewData( itemID : ItemID )
	{
		var puppet : gamePuppet;
		var transactionSystem : TransactionSystem;
		var legs : ItemID;
		var underwear : ItemID;
		if( !( ItemID.IsValid( m_givenItem ) ) )
		{
			puppet = GetGamePuppet();
			if( puppet )
			{
				transactionSystem = GameInstance.GetTransactionSystem( puppet.GetGame() );
				m_placementSlot = EquipmentSystem.GetPlacementSlot( itemID );
				m_initialItem = transactionSystem.GetItemInSlot( puppet, m_placementSlot ).GetItemID();
				transactionSystem.RemoveItemFromSlot( puppet, m_placementSlot, true );
				m_givenItem = ItemID.FromTDBID( ItemID.GetTDBID( itemID ) );
				transactionSystem.GiveItem( puppet, m_givenItem, 1 );
				transactionSystem.AddItemToSlot( puppet, m_placementSlot, m_givenItem );
				if( ItemID.IsValid( m_initialItem ) )
				{
					if( transactionSystem.MatchVisualTagByItemID( m_initialItem, puppet, 'hide_L1' ) )
					{
						legs = transactionSystem.GetItemInSlot( puppet, T"AttachmentSlots.Legs" ).GetItemID();
						if( ItemID.IsValid( legs ) )
						{
							transactionSystem.ResetItemAppearance( puppet, legs );
						}
						else if( IsBuildCensored() )
						{
							underwear = transactionSystem.GetItemInSlot( puppet, T"AttachmentSlots.UnderwearBottom" ).GetItemID();
							if( ItemID.IsValid( underwear ) )
							{
								transactionSystem.ResetItemAppearance( puppet, underwear );
							}
						}
					}
				}
			}
		}
	}

	protected function ClearViewData()
	{
		var puppet : gamePuppet;
		var transactionSystem : TransactionSystem;
		var legs : ItemID;
		var underwear : ItemID;
		if( ItemID.IsValid( m_givenItem ) )
		{
			puppet = GetGamePuppet();
			if( puppet )
			{
				transactionSystem = GameInstance.GetTransactionSystem( puppet.GetGame() );
				transactionSystem.RemoveItemFromSlot( puppet, m_placementSlot, true );
				transactionSystem.RemoveItem( puppet, m_givenItem, 1 );
				transactionSystem.AddItemToSlot( puppet, m_placementSlot, m_initialItem );
				if( ItemID.IsValid( m_initialItem ) )
				{
					if( transactionSystem.MatchVisualTagByItemID( m_initialItem, puppet, 'hide_L1' ) )
					{
						legs = transactionSystem.GetItemInSlot( puppet, T"AttachmentSlots.Legs" ).GetItemID();
						if( ItemID.IsValid( legs ) )
						{
							transactionSystem.ChangeItemAppearanceByName( puppet, legs, 'empty_appearance_default' );
						}
						else if( IsBuildCensored() )
						{
							underwear = transactionSystem.GetItemInSlot( puppet, T"AttachmentSlots.UnderwearBottom" ).GetItemID();
							if( ItemID.IsValid( underwear ) )
							{
								transactionSystem.ChangeItemAppearanceByName( puppet, underwear, 'empty_appearance_default' );
							}
						}
					}
				}
			}
			m_givenItem = ItemID.None();
		}
	}

	protected function IsBuildCensored() : Bool
	{
		var charCustomization : gameuiICharacterCustomizationSystem;
		charCustomization = GameInstance.GetCharacterCustomizationSystem( GetGamePuppet().GetGame() );
		if( charCustomization != NULL )
		{
			return !( charCustomization.IsNudityAllowed() );
		}
		return false;
	}

}

class GarmentItemPreviewGameController extends BaseGarmentItemPreviewGameController
{
	default m_maxMousePointerOffset = 40.0f;
	default m_mouseRotationSpeed = 250.0f;
	private var m_data : InventoryItemPreviewData;
	private var m_isMouseDown : Bool;
	private const var c_GARMENT_ROTATION_SPEED : Float;
	default c_GARMENT_ROTATION_SPEED = 100.0f;

	protected event OnInitialize()
	{
		super.OnInitialize();
		m_data = ( ( InventoryItemPreviewData )( GetRootWidget().GetUserData( 'InventoryItemPreviewData' ) ) );
		RegisterToGlobalInputCallback( 'OnPreOnRelease', this, 'OnGlobalRelease' );
		RegisterToGlobalInputCallback( 'OnPostOnPress', this, 'OnGlobalPress' );
		RegisterToGlobalInputCallback( 'OnPostOnRelative', this, 'OnRelativeInput' );
	}

	protected event OnUninitialize()
	{
		UnregisterFromGlobalInputCallback( 'OnPreOnRelease', this, 'OnGlobalRelease' );
		UnregisterFromGlobalInputCallback( 'OnPostOnPress', this, 'OnGlobalPress' );
		UnregisterFromGlobalInputCallback( 'OnPostOnRelative', this, 'OnRelativeInput' );
		super.OnUninitialize();
	}

	protected event OnGlobalPress( e : inkPointerEvent )
	{
		var evt : inkGameNotificationLayer_SetCursorVisibility;
		if( e.IsAction( 'mouse_left' ) )
		{
			m_isMouseDown = true;
			evt = new inkGameNotificationLayer_SetCursorVisibility;
			evt.Init( false );
			QueueEvent( evt );
		}
	}

	protected event OnGlobalRelease( e : inkPointerEvent )
	{
		var evt : inkGameNotificationLayer_SetCursorVisibility;
		if( m_isMouseDown )
		{
			if( e.IsAction( 'mouse_left' ) )
			{
				e.Consume();
				m_isMouseDown = false;
				evt = new inkGameNotificationLayer_SetCursorVisibility;
				evt.Init( true, Vector2( 0.5, 0.5 ) );
				QueueEvent( evt );
			}
		}
		else if( e.IsAction( 'cancel' ) || e.IsAction( 'click' ) )
		{
			m_data.token.TriggerCallback( NULL );
		}
	}

	protected event OnPreviewInitialized()
	{
		super.OnPreviewInitialized();
		SetViewData( m_data.itemID );
	}

	protected override function HandleAxisInput( e : inkPointerEvent )
	{
		var amount : Float;
		amount = e.GetAxisData();
		if( e.IsAction( 'left_trigger' ) || e.IsAction( 'character_preview_rotate' ) )
		{
			Rotate( amount * -( c_GARMENT_ROTATION_SPEED ) );
		}
		else if( e.IsAction( 'right_trigger' ) || e.IsAction( 'character_preview_rotate' ) )
		{
			Rotate( amount * c_GARMENT_ROTATION_SPEED );
		}
	}

	protected event OnRelativeInput( e : inkPointerEvent )
	{
		var offset, ratio, velocity : Float;
		offset = e.GetAxisData();
		if( offset > 0.0 )
		{
			ratio = ClampF( offset / m_maxMousePointerOffset, 0.5, 1.0 );
		}
		else
		{
			ratio = ClampF( offset / m_maxMousePointerOffset, -1.0, -0.5 );
		}
		velocity = ratio * m_mouseRotationSpeed;
		if( m_isMouseDown )
		{
			if( e.IsAction( 'mouse_x' ) )
			{
				Rotate( velocity );
			}
		}
	}

}

class CraftingGarmentItemPreviewGameController extends WardrobeSetPreviewGameController
{
	private var m_initialItems : array< ItemID >;
	private var m_previewedItem : ItemID;

	protected event OnPreviewInitialized()
	{
		super.OnPreviewInitialized();
		m_previewedItem = ItemID.None();
		m_initialItems = GetVisualItems();
		SetUpPuppet( m_initialItems );
		PreviewUnequipFromSlot( T"AttachmentSlots.WeaponLeft" );
		PreviewUnequipFromSlot( T"AttachmentSlots.WeaponRight" );
	}

	protected event OnCrafrtingPreview( evt : CraftingItemPreviewEvent )
	{
		var i : Int32;
		if( ItemID.IsValid( m_previewedItem ) )
		{
			PreviewUnequipItem( m_previewedItem );
			m_previewedItem = ItemID.None();
			for( i = 0; i < m_initialItems.Size(); i += 1 )
			{
				PreviewEquipItem( m_initialItems[ i ] );
			}
		}
		if( evt.isGarment )
		{
			m_previewedItem = evt.itemID;
			PreviewEquipAndForceShowItem( evt.itemID );
		}
	}

	protected event OnUninitialize()
	{
		CleanUpPuppet();
		super.OnUninitialize();
	}

}

import class WardrobeSetPreviewGameController extends BaseGarmentItemPreviewGameController
{
	default m_maxMousePointerOffset = 40.0f;
	default m_mouseRotationSpeed = 250.0f;
	private editable var m_colliderWidgetRef : inkWidgetRef;
	private var m_colliderWidget : weak< inkWidget >;
	private var m_data : InventoryItemPreviewData;
	private var m_isMouseDown : Bool;
	private var m_isNotification : Bool;
	private const var c_GARMENT_ROTATION_SPEED : Float;
	default c_GARMENT_ROTATION_SPEED = 100.0f;

	public import function PreviewEquipItem( itemID : ItemID );
	public import function PreviewEquipAndForceShowItem( itemID : ItemID );
	public import function PreviewUnequipItem( itemID : ItemID );
	public import function PreviewUnequipFromSlot( slotID : TweakDBID );
	public import function PreviewUnequipFromEquipmentArea( equipmentArea : gamedataEquipmentArea );
	public import function ClearPuppet();
	public import function RestorePuppetWeapons();
	public import function HandleUnderwearVisualTags();
	public import function SetUpPuppet( visualItems : array< ItemID > );

	protected event OnInitialize()
	{
		var evt : RegisterPreviewControllerEvent;
		super.OnInitialize();
		if( inkWidgetRef.IsValid( m_colliderWidgetRef ) )
		{
			m_colliderWidget = inkWidgetRef.Get( m_colliderWidgetRef );
		}
		else
		{
			m_colliderWidget = GetRootWidget();
		}
		m_colliderWidget.RegisterToCallback( 'OnPress', this, 'OnPress' );
		RegisterToGlobalInputCallback( 'OnPreOnRelease', this, 'OnGlobalRelease' );
		RegisterToGlobalInputCallback( 'OnPostOnRelative', this, 'OnRelativeInput' );
		m_data = ( ( InventoryItemPreviewData )( GetRootWidget().GetUserData( 'InventoryItemPreviewData' ) ) );
		m_isNotification = m_data != NULL;
		if( !( m_isNotification ) )
		{
			evt = new RegisterPreviewControllerEvent;
			evt.controller = this;
			QueueEvent( evt );
		}
	}

	protected event OnUninitialize()
	{
		m_colliderWidget.UnregisterFromCallback( 'OnPress', this, 'OnPress' );
		UnregisterFromGlobalInputCallback( 'OnPreOnRelease', this, 'OnGlobalRelease' );
		UnregisterFromGlobalInputCallback( 'OnPostOnRelative', this, 'OnRelativeInput' );
		super.OnUninitialize();
	}

	protected event OnPreviewInitialized()
	{
		super.OnPreviewInitialized();
		if( m_isNotification )
		{
			SetUpPuppet( GetVisualItems() );
			PreviewUnequipFromSlot( T"AttachmentSlots.WeaponLeft" );
			PreviewUnequipFromSlot( T"AttachmentSlots.WeaponRight" );
			PreviewEquipAndForceShowItem( m_data.itemID );
		}
	}

	public function GetVisualItems() : array< ItemID >
	{
		var visualItems : array< ItemID >;
		var i : Int32;
		var gi : GameInstance;
		var player : PlayerPuppet;
		var equipmentSystem : EquipmentSystem;
		var wardrobeSystem : WardrobeSystem;
		var clothingSet : ClothingSet;
		var slots : array< gamedataEquipmentArea >;
		var visualItem : ItemID;
		gi = GetGamePuppet().GetGame();
		player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( gi ).GetLocalPlayerControlledGameObject() ) );
		equipmentSystem = ( ( EquipmentSystem )( GameInstance.GetScriptableSystemsContainer( gi ).Get( 'EquipmentSystem' ) ) );
		wardrobeSystem = GameInstance.GetWardrobeSystem( gi );
		clothingSet = wardrobeSystem.GetActiveClothingSet();
		if( clothingSet != NULL )
		{
			for( i = 0; i < clothingSet.clothingList.Size(); i += 1 )
			{
				visualItem = clothingSet.clothingList[ i ].visualItem;
				if( ItemID.IsValid( visualItem ) )
				{
					visualItems.PushBack( visualItem );
				}
			}
		}
		else
		{
			slots = equipmentSystem.GetPaperDollSlots( player );
			for( i = 0; i < slots.Size(); i += 1 )
			{
				visualItem = equipmentSystem.GetActiveVisualItem( player, slots[ i ] );
				if( ItemID.IsValid( visualItem ) )
				{
					visualItems.PushBack( visualItem );
				}
			}
		}
		return visualItems;
	}

	public function RestorePuppetEquipment()
	{
		var i : Int32;
		var puppet : gamePuppet;
		var gi : GameInstance;
		var player : PlayerPuppet;
		var equipmentSystem : EquipmentSystem;
		var playerData : EquipmentSystemPlayerData;
		var slots : array< gamedataEquipmentArea >;
		var visualItem : ItemID;
		puppet = GetGamePuppet();
		gi = puppet.GetGame();
		player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( gi ).GetLocalPlayerControlledGameObject() ) );
		equipmentSystem = ( ( EquipmentSystem )( GameInstance.GetScriptableSystemsContainer( gi ).Get( 'EquipmentSystem' ) ) );
		playerData = EquipmentSystem.GetData( player );
		slots = equipmentSystem.GetPaperDollSlots( player );
		for( i = 0; i < slots.Size(); i += 1 )
		{
			visualItem = equipmentSystem.GetActiveVisualItem( player, slots[ i ] );
			if( ItemID.IsValid( visualItem ) && !( playerData.IsSlotHidden( slots[ i ] ) ) )
			{
				PreviewEquipItem( visualItem );
			}
		}
		HandleUnderwearVisualTags();
	}

	protected function TryRestoreActiveWardrobeSet() : Bool
	{
		var req : EquipWardrobeSetRequest;
		var activeSetIndex : gameWardrobeClothingSetIndex;
		var puppet : gamePuppet;
		var player : PlayerPuppet;
		var gi : GameInstance;
		var equipmentSystem : EquipmentSystem;
		puppet = GetGamePuppet();
		activeSetIndex = GameInstance.GetWardrobeSystem( puppet.GetGame() ).GetActiveClothingSetIndex();
		if( activeSetIndex != gameWardrobeClothingSetIndex.INVALID )
		{
			gi = puppet.GetGame();
			player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( gi ).GetLocalPlayerControlledGameObject() ) );
			equipmentSystem = ( ( EquipmentSystem )( GameInstance.GetScriptableSystemsContainer( gi ).Get( 'EquipmentSystem' ) ) );
			req = new EquipWardrobeSetRequest;
			req.setID = activeSetIndex;
			req.owner = player;
			equipmentSystem.QueueRequest( req );
			return true;
		}
		return false;
	}

	public function DelayedResetItemAppearanceInSlot( slotID : TweakDBID )
	{
		var evt : ResetItemAppearanceInSlotDelayEvent;
		var playerControlledObject : GameObject;
		playerControlledObject = GetPlayerControlledObject();
		evt = new ResetItemAppearanceInSlotDelayEvent;
		evt.slotID = slotID;
		GameInstance.GetDelaySystem( playerControlledObject.GetGame() ).DelayEventNextFrame( playerControlledObject, evt );
	}

	protected function CleanUpPuppet()
	{
		ClearPuppet();
		if( TryRestoreActiveWardrobeSet() )
		{
			SyncUnderwearToEquipmentSystem();
		}
		else
		{
			RestorePuppetEquipment();
		}
		RestorePuppetWeapons();
		DelayedResetItemAppearanceInSlot( T"AttachmentSlots.Chest" );
	}

	public function SyncUnderwearToEquipmentSystem()
	{
		var puppet : gamePuppet;
		var gi : GameInstance;
		var player : PlayerPuppet;
		var transactionSystem : TransactionSystem;
		var playerData : EquipmentSystemPlayerData;
		var underwearID, previewID : ItemID;
		puppet = GetGamePuppet();
		gi = puppet.GetGame();
		player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( gi ).GetLocalPlayerControlledGameObject() ) );
		transactionSystem = GameInstance.GetTransactionSystem( gi );
		playerData = EquipmentSystem.GetData( player );
		if( playerData.IsSlotHidden( gamedataEquipmentArea.UnderwearTop ) )
		{
			transactionSystem.RemoveItemFromSlot( puppet, T"AttachmentSlots.UnderwearTop" );
		}
		else
		{
			underwearID = transactionSystem.GetItemDataByTDBID( puppet, T"Items.Underwear_Basic_01_Top" ).GetID();
			previewID = transactionSystem.CreatePreviewItemID( underwearID );
			transactionSystem.AddItemToSlot( puppet, T"AttachmentSlots.UnderwearTop", previewID, true );
		}
		if( playerData.IsSlotHidden( gamedataEquipmentArea.UnderwearBottom ) )
		{
			transactionSystem.RemoveItemFromSlot( puppet, T"AttachmentSlots.UnderwearBottom" );
		}
		else
		{
			underwearID = transactionSystem.GetItemDataByTDBID( puppet, T"Items.Underwear_Basic_01_Bottom" ).GetID();
			previewID = transactionSystem.CreatePreviewItemID( underwearID );
			transactionSystem.AddItemToSlot( puppet, T"AttachmentSlots.UnderwearBottom", previewID, true );
		}
	}

	protected event OnPress( e : inkPointerEvent )
	{
		var menuEvt : inkMenuLayer_SetCursorVisibility;
		var notificationEvt : inkGameNotificationLayer_SetCursorVisibility;
		if( e.IsAction( 'mouse_left' ) )
		{
			m_isMouseDown = true;
			if( m_isNotification )
			{
				notificationEvt = new inkGameNotificationLayer_SetCursorVisibility;
				notificationEvt.Init( false );
				QueueEvent( notificationEvt );
			}
			else
			{
				menuEvt = new inkMenuLayer_SetCursorVisibility;
				menuEvt.Init( false );
				QueueEvent( menuEvt );
			}
		}
	}

	protected event OnGlobalRelease( e : inkPointerEvent )
	{
		var menuEvt : inkMenuLayer_SetCursorVisibility;
		var notificationEvt : inkGameNotificationLayer_SetCursorVisibility;
		if( m_isMouseDown )
		{
			if( e.IsAction( 'mouse_left' ) )
			{
				e.Consume();
				m_isMouseDown = false;
				if( m_isNotification )
				{
					notificationEvt = new inkGameNotificationLayer_SetCursorVisibility;
					notificationEvt.Init( true, Vector2( 0.5, 0.5 ) );
					QueueEvent( notificationEvt );
				}
				else
				{
					menuEvt = new inkMenuLayer_SetCursorVisibility;
					menuEvt.Init( true, Vector2( 0.25, 0.5 ) );
					QueueEvent( menuEvt );
				}
			}
		}
		else if( e.IsAction( 'cancel' ) )
		{
			if( m_isNotification )
			{
				CleanUpPuppet();
				m_data.token.TriggerCallback( NULL );
			}
		}
	}

	protected override function HandleAxisInput( e : inkPointerEvent )
	{
		var amount : Float;
		amount = e.GetAxisData();
		if( e.IsAction( 'left_trigger' ) || e.IsAction( 'character_preview_rotate' ) )
		{
			Rotate( amount * -( c_GARMENT_ROTATION_SPEED ) );
		}
		else if( e.IsAction( 'right_trigger' ) || e.IsAction( 'character_preview_rotate' ) )
		{
			Rotate( amount * c_GARMENT_ROTATION_SPEED );
		}
	}

	protected event OnRelativeInput( e : inkPointerEvent )
	{
		var offset, ratio, velocity : Float;
		if( m_isMouseDown )
		{
			offset = e.GetAxisData();
			if( offset > 0.0 )
			{
				ratio = ClampF( offset / m_maxMousePointerOffset, 0.5, 1.0 );
			}
			else
			{
				ratio = ClampF( offset / m_maxMousePointerOffset, -1.0, -0.5 );
			}
			velocity = ratio * m_mouseRotationSpeed;
			if( e.IsAction( 'mouse_x' ) )
			{
				Rotate( velocity );
			}
		}
	}

}

class RegisterPreviewControllerEvent extends Event
{
	var controller : weak< WardrobeSetPreviewGameController >;
}

abstract class ItemPreviewHelper
{

	public static function ShowPreviewItem( controller : inkGameController, const itemData : ref< InventoryItemData >, isGarment : Bool, callbackName : CName ) : inkGameNotificationToken
	{
		var token : inkGameNotificationToken;
		var previewData : InventoryItemPreviewData;
		previewData = GetPreviewData( ( ( IScriptable )( controller ) ), itemData, isGarment );
		if( previewData )
		{
			token = controller.ShowGameNotification( previewData );
			token.RegisterListener( controller, callbackName );
		}
		return token;
	}

	public static function ShowPreviewItem( controller : inkGameController, itemData : weak< UIInventoryItem >, isGarment : Bool, callbackName : CName ) : inkGameNotificationToken
	{
		var token : inkGameNotificationToken;
		var previewData : InventoryItemPreviewData;
		previewData = GetPreviewData( ( ( IScriptable )( controller ) ), itemData, isGarment );
		if( previewData )
		{
			token = controller.ShowGameNotification( previewData );
			token.RegisterListener( controller, callbackName );
		}
		return token;
	}

	public static function ShowPreviewItem( controller : inkLogicController, const itemData : ref< InventoryItemData >, isGarment : Bool, callbackName : CName ) : inkGameNotificationToken
	{
		var token : inkGameNotificationToken;
		var previewData : InventoryItemPreviewData;
		previewData = GetPreviewData( ( ( IScriptable )( controller ) ), itemData, isGarment );
		if( previewData )
		{
			token = controller.ShowGameNotification( previewData );
			token.RegisterListener( controller, callbackName );
		}
		return token;
	}

	private static function GetPreviewData( controller : IScriptable, const itemData : ref< InventoryItemData >, isGarment : Bool ) : InventoryItemPreviewData
	{
		var previewData : InventoryItemPreviewData;
		var itemID : ItemID;
		var itemRecord : Item_Record;
		var weaponRecord : weak< WeaponItem_Record >;
		itemID = InventoryItemData.GetGameItemData( itemData ).GetID();
		previewData = new InventoryItemPreviewData;
		previewData.itemID = itemID;
		previewData.itemName = InventoryItemData.GetName( itemData );
		previewData.itemDescription = InventoryItemData.GetDescription( itemData );
		previewData.itemQualityState = InventoryItemData.GetQuality( itemData );
		previewData.requiredLevel = InventoryItemData.GetRequiredLevel( itemData );
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) );
		weaponRecord = ( ( weak< weak< WeaponItem_Record > > )( itemRecord ) );
		previewData.itemEvolution = weaponRecord.Evolution().Type();
		previewData.itemPerkGroup = UIItemsHelper.GetBasicPerkRelevanceGroup( itemData.ItemType );
		previewData.queueName = 'modal_popup_fullscreen';
		previewData.notificationName = 'base\gameplay\gui\widgets\notifications\item_preview.inkwidget';
		previewData.isBlocking = true;
		previewData.useCursor = true;
		if( isGarment )
		{
			previewData.notificationName = 'base\gameplay\gui\widgets\notifications\garment_item_preview.inkwidget';
			return previewData;
		}
		else
		{
			previewData.notificationName = 'base\gameplay\gui\widgets\notifications\item_preview.inkwidget';
			return previewData;
		}
		return NULL;
	}

	private static function GetPreviewData( controller : IScriptable, itemData : weak< UIInventoryItem >, isGarment : Bool ) : InventoryItemPreviewData
	{
		var previewData : InventoryItemPreviewData;
		previewData = new InventoryItemPreviewData;
		previewData.itemID = itemData.ID;
		previewData.itemName = itemData.GetName();
		previewData.itemDescription = itemData.GetDescription();
		previewData.itemQualityState = itemData.GetQualityName();
		previewData.requiredLevel = itemData.GetRequiredLevel();
		previewData.itemEvolution = itemData.GetWeaponEvolution();
		previewData.itemPerkGroup = itemData.GetPerkGroup();
		previewData.queueName = 'modal_popup_fullscreen';
		previewData.notificationName = 'base\gameplay\gui\widgets\notifications\item_preview.inkwidget';
		previewData.isBlocking = true;
		previewData.useCursor = true;
		if( isGarment )
		{
			previewData.notificationName = 'base\gameplay\gui\widgets\notifications\garment_item_preview.inkwidget';
			return previewData;
		}
		else
		{
			previewData.notificationName = 'base\gameplay\gui\widgets\notifications\item_preview.inkwidget';
			return previewData;
		}
		return NULL;
	}

}

class InventoryItemPreviewData extends inkGameNotificationData
{
	var itemID : ItemID;
	var itemName : String;
	var itemDescription : String;
	var requiredLevel : Int32;
	var itemQualityState : CName;
	var itemEvolution : gamedataWeaponEvolution;
	var itemPerkGroup : gamedataPerkWeaponGroupType;
}

class InventoryItemPreviewPopupEvent extends Event
{
	var m_data : InventoryItemPreviewData;
}

class CraftingItemPreviewEvent extends Event
{
	var itemID : ItemID;
	var isGarment : Bool;
}

