class MorphMenuUserData extends inkUserData
{
	var m_optionsListInitialized : Bool;
	var m_updatingFinalizedState : Bool;
	editable var m_editMode : gameuiCharacterCustomizationEditTag;
	default m_editMode = gameuiCharacterCustomizationEditTag.NewGame;
}

class characterCreationBodyMorphMenu extends BaseCharacterCreationController
{
	editable var m_defaultPreviewSlot : CName;
	default m_defaultPreviewSlot = 'UI_Skin';
	editable var m_optionsList : inkCompoundRef;
	editable var m_colorPicker : inkWidgetRef;
	editable var m_colorPickerBG : inkWidgetRef;
	editable var m_colorPickerClose : inkWidgetRef;
	editable var m_scrollWidget : inkWidgetRef;
	editable var m_scrollArea : inkScrollAreaRef;
	editable var m_optionList : weak< inkCompoundWidget >;
	editable var m_slider : inkWidgetRef;
	editable var m_previousPageBtn : inkWidgetRef;
	editable var m_previousPageBtnBg : inkImageRef;
	editable var m_previousPageBtnText : inkTextRef;
	editable var m_nextPageBtnBg : inkImageRef;
	editable var m_nextPageBtnText : inkTextRef;
	editable var m_backConfirmation : inkWidgetRef;
	editable var m_backConfirmationWidget : inkWidgetRef;
	editable var m_ConfirmationConfirmBtn : inkWidgetRef;
	editable var m_ConfirmationCloseBtn : inkWidgetRef;
	editable var m_preset1Group : inkWidgetRef;
	editable var m_preset2Group : inkWidgetRef;
	editable var m_preset3Group : inkWidgetRef;
	editable var m_randomizeGroup : inkWidgetRef;
	editable var m_presetsLabel : inkWidgetRef;
	editable var m_preset1 : inkWidgetRef;
	editable var m_preset2 : inkWidgetRef;
	editable var m_preset3 : inkWidgetRef;
	editable var m_randomize : inkWidgetRef;
	editable var m_preset1Thumbnail : inkImageRef;
	editable var m_preset2Thumbnail : inkImageRef;
	editable var m_preset3Thumbnail : inkImageRef;
	editable var m_randomizThumbnail : inkImageRef;
	editable var m_preset1Bg : inkImageRef;
	editable var m_preset2Bg : inkImageRef;
	editable var m_preset3Bg : inkImageRef;
	editable var m_randomizBg : inkImageRef;
	editable var m_navigationButtons : inkWidgetRef;
	var m_hideColorPickerNextFrame : Bool;
	default m_hideColorPickerNextFrame = false;
	var m_colorPickerOwner : weak< inkWidget >;
	var m_animationProxy : inkAnimProxy;
	var m_confirmAnimationProxy : inkAnimProxy;
	var m_optionListAnimationProxy : inkAnimProxy;
	var m_optionsListInitialized : Bool;
	default m_optionsListInitialized = false;
	var m_introPlayed : Bool;
	default m_introPlayed = false;
	var m_navigationControllers : array< weak< inkDiscreteNavigationController > >;
	var m_menuListController : weak< ListController >;
	var m_cachedCursor : weak< inkWidget >;
	var m_updatingFinalizedState : Bool;
	default m_updatingFinalizedState = false;
	var m_editMode : gameuiCharacterCustomizationEditTag;
	default m_editMode = gameuiCharacterCustomizationEditTag.NewGame;
	var m_randomizing : Bool;
	default m_randomizing = false;
	private var m_scrollController : weak< inkScrollController >;
	private var m_sliderController : weak< inkSliderController >;
	private var m_inputDisabled : Bool;
	private var m_isPresetHoveredOver : Bool;

	protected event OnSetUserData( userData : IScriptable )
	{
		var morphMenuUserData : MorphMenuUserData;
		morphMenuUserData = ( ( MorphMenuUserData )( userData ) );
		m_optionsListInitialized = morphMenuUserData && morphMenuUserData.m_optionsListInitialized;
		m_updatingFinalizedState = morphMenuUserData.m_updatingFinalizedState;
		m_editMode = morphMenuUserData.m_editMode;
	}

	protected event OnInitialize()
	{
		super.OnInitialize();
		if( !( m_updatingFinalizedState ) )
		{
			inkTextRef.SetLocalizedTextString( m_previousPageBtnText, "LocKey#35476" );
			inkTextRef.SetLocalizedTextString( m_nextPageBtnText, "LocKey#23407" );
			inkWidgetRef.RegisterToCallback( m_preset1, 'OnRelease', this, 'OnPreset1' );
			inkWidgetRef.RegisterToCallback( m_preset2, 'OnRelease', this, 'OnPreset2' );
			inkWidgetRef.RegisterToCallback( m_preset3, 'OnRelease', this, 'OnPreset3' );
			inkWidgetRef.RegisterToCallback( m_preset1, 'OnHoverOver', this, 'OnHoverOverPreset1' );
			inkWidgetRef.RegisterToCallback( m_preset1, 'OnHoverOut', this, 'OnHoverOutPreset1' );
			inkWidgetRef.RegisterToCallback( m_preset2, 'OnHoverOver', this, 'OnHoverOverPreset2' );
			inkWidgetRef.RegisterToCallback( m_preset2, 'OnHoverOut', this, 'OnHoverOutPreset2' );
			inkWidgetRef.RegisterToCallback( m_preset3, 'OnHoverOver', this, 'OnHoverOverPreset3' );
			inkWidgetRef.RegisterToCallback( m_preset3, 'OnHoverOut', this, 'OnHoverOutPreset3' );
		}
		else
		{
			inkTextRef.SetLocalizedTextString( m_previousPageBtnText, "LocKey#35476" );
			inkTextRef.SetLocalizedTextString( m_nextPageBtnText, "LocKey#23123" );
			inkWidgetRef.SetVisible( m_presetsLabel, false );
			inkWidgetRef.SetVisible( m_preset1, false );
			inkWidgetRef.SetVisible( m_preset2, false );
			inkWidgetRef.SetVisible( m_preset3, false );
			inkWidgetRef.SetInteractive( m_preset1, false );
			inkWidgetRef.SetInteractive( m_preset2, false );
			inkWidgetRef.SetInteractive( m_preset3, false );
			inkImageRef.SetVisible( m_preset1Thumbnail, false );
			inkImageRef.SetVisible( m_preset2Thumbnail, false );
			inkImageRef.SetVisible( m_preset3Thumbnail, false );
			inkImageRef.SetVisible( m_preset1Bg, false );
			inkImageRef.SetVisible( m_preset2Bg, false );
			inkImageRef.SetVisible( m_preset3Bg, false );
		}
		inkWidgetRef.RegisterToCallback( m_randomize, 'OnRelease', this, 'OnRandomize' );
		inkWidgetRef.RegisterToCallback( m_randomize, 'OnHoverOver', this, 'OnHoverOverRandomize' );
		inkWidgetRef.RegisterToCallback( m_randomize, 'OnHoverOut', this, 'OnHoverOutRandomize' );
		m_optionList.RegisterToCallback( 'OnRelease', this, 'OnListRelease' );
		inkWidgetRef.RegisterToCallback( m_colorPickerClose, 'OnRelease', this, 'OnColorPickerClose' );
		inkWidgetRef.RegisterToCallback( m_previousPageBtn, 'OnRelease', this, 'OnPrevious' );
		inkWidgetRef.RegisterToCallback( m_previousPageBtn, 'OnHoverOver', this, 'OnHoverOverPreviousPageBtn' );
		inkWidgetRef.RegisterToCallback( m_previousPageBtn, 'OnHoverOut', this, 'OnHoverOutPreviousPageBtn' );
		inkWidgetRef.RegisterToCallback( m_nextPageHitArea, 'OnHoverOver', this, 'OnHoverOverNextPageBtn' );
		inkWidgetRef.RegisterToCallback( m_nextPageHitArea, 'OnHoverOut', this, 'OnHoverOutNextPageBtn' );
		inkWidgetRef.RegisterToCallback( m_ConfirmationConfirmBtn, 'OnRelease', this, 'OnConfirmationConfirm' );
		inkWidgetRef.RegisterToCallback( m_ConfirmationCloseBtn, 'OnRelease', this, 'OnConfirmationClose' );
		inkWidgetRef.SetVisible( m_colorPicker, false );
		inkWidgetRef.SetVisible( m_colorPickerBG, false );
		inkWidgetRef.RegisterToCallback( m_colorPicker, 'OnHoverOver', this, 'OnHoverOverColorPicker' );
		inkWidgetRef.RegisterToCallback( m_colorPicker, 'OnColorSelected', this, 'OnColorSelected' );
		GetTelemetrySystem().LogInitialChoiceSetStatege( telemetryInitalChoiceStage.Customizations );
		if( m_optionsListInitialized )
		{
			InitializeList();
			OnIntro();
		}
		m_menuListController = ( ( ListController )( inkCompoundRef.GetController( m_optionsList ) ) );
		m_scrollController = ( ( inkScrollController )( inkWidgetRef.GetControllerByType( m_scrollWidget, 'inkScrollController' ) ) );
		m_sliderController = ( ( inkSliderController )( inkWidgetRef.GetControllerByType( m_slider, 'inkSliderController' ) ) );
		m_navigationControllers.PushBack( ( ( inkDiscreteNavigationController )( inkWidgetRef.GetController( m_preset1Group ) ) ) );
		m_navigationControllers.PushBack( ( ( inkDiscreteNavigationController )( inkWidgetRef.GetController( m_preset2Group ) ) ) );
		m_navigationControllers.PushBack( ( ( inkDiscreteNavigationController )( inkWidgetRef.GetController( m_preset3Group ) ) ) );
		m_navigationControllers.PushBack( ( ( inkDiscreteNavigationController )( inkWidgetRef.GetController( m_randomizeGroup ) ) ) );
		if( m_editMode != gameuiCharacterCustomizationEditTag.NewGame )
		{
			SetTimeDilatation( true );
		}
		m_inputDisabled = false;
	}

	protected event OnUninitialize()
	{
		var uiSystem : UISystem;
		super.OnUninitialize();
		if( !( m_updatingFinalizedState ) )
		{
			inkWidgetRef.UnregisterFromCallback( m_preset1, 'OnRelease', this, 'OnPreset1' );
			inkWidgetRef.UnregisterFromCallback( m_preset2, 'OnRelease', this, 'OnPreset2' );
			inkWidgetRef.UnregisterFromCallback( m_preset3, 'OnRelease', this, 'OnPreset3' );
			inkWidgetRef.UnregisterFromCallback( m_preset1, 'OnHoverOver', this, 'OnHoverOverPreset1' );
			inkWidgetRef.UnregisterFromCallback( m_preset1, 'OnHoverOut', this, 'OnHoverOutPreset1' );
			inkWidgetRef.UnregisterFromCallback( m_preset2, 'OnHoverOver', this, 'OnHoverOverPreset2' );
			inkWidgetRef.UnregisterFromCallback( m_preset2, 'OnHoverOut', this, 'OnHoverOutPreset2' );
			inkWidgetRef.UnregisterFromCallback( m_preset3, 'OnHoverOver', this, 'OnHoverOverPreset3' );
			inkWidgetRef.UnregisterFromCallback( m_preset3, 'OnHoverOut', this, 'OnHoverOutPreset3' );
		}
		else
		{
			uiSystem = GameInstance.GetUISystem( GetPlayerControlledObject().GetGame() );
			uiSystem.RestorePreviousVisualState( 'inkInGameMenuStateSolid' );
		}
		inkWidgetRef.UnregisterFromCallback( m_randomize, 'OnRelease', this, 'OnRandomize' );
		inkWidgetRef.UnregisterFromCallback( m_randomize, 'OnHoverOver', this, 'OnHoverOverRandomize' );
		inkWidgetRef.UnregisterFromCallback( m_randomize, 'OnHoverOut', this, 'OnHoverOutRandomize' );
		m_optionList.UnregisterFromCallback( 'OnRelease', this, 'OnListRelease' );
		inkWidgetRef.UnregisterFromCallback( m_colorPickerClose, 'OnRelease', this, 'OnColorPickerClose' );
		inkWidgetRef.UnregisterFromCallback( m_previousPageBtn, 'OnRelease', this, 'OnPrevious' );
		inkWidgetRef.UnregisterFromCallback( m_previousPageBtn, 'OnHoverOver', this, 'OnHoverOverPreviousPageBtn' );
		inkWidgetRef.UnregisterFromCallback( m_previousPageBtn, 'OnHoverOut', this, 'OnHoverOutPreviousPageBtn' );
		inkWidgetRef.UnregisterFromCallback( m_nextPageHitArea, 'OnHoverOver', this, 'OnHoverOverNextPageBtn' );
		inkWidgetRef.UnregisterFromCallback( m_nextPageHitArea, 'OnHoverOut', this, 'OnHoverOutNextPageBtn' );
		inkWidgetRef.UnregisterFromCallback( m_ConfirmationConfirmBtn, 'OnRelease', this, 'OnConfirmationConfirm' );
		inkWidgetRef.UnregisterFromCallback( m_ConfirmationCloseBtn, 'OnRelease', this, 'OnConfirmationClose' );
		inkWidgetRef.UnregisterFromCallback( m_colorPicker, 'OnHoverOver', this, 'OnHoverOverColorPicker' );
		inkWidgetRef.UnregisterFromCallback( m_colorPicker, 'OnColorSelected', this, 'OnColorSelected' );
		if( m_editMode != gameuiCharacterCustomizationEditTag.NewGame )
		{
			SetTimeDilatation( false );
		}
		OnOutro();
	}

	protected event OnRelease( e : inkPointerEvent )
	{
		var target : weak< inkWidget >;
		target = e.GetTarget();
		if( e.IsAction( 'click' ) )
		{
			PlaySound( 'Button', 'OnPress' );
			if( target == inkWidgetRef.Get( m_nextPageHitArea ) )
			{
				ConfirmCustomizedCharacter();
			}
		}
	}

	protected event OnInitializeOptionsList( evt : gameuiCharacterCustomizationSystem_OnInitializeOptionsListEvent )
	{
		var uiSystem : UISystem;
		if( m_updatingFinalizedState )
		{
			GetCharacterCustomizationSystem().InitializeOptionsFromFinalizedState();
			ReInitializeOptionsList();
			uiSystem = GameInstance.GetUISystem( GetPlayerControlledObject().GetGame() );
			uiSystem.RequestNewVisualState( 'inkInGameMenuStateSolid' );
		}
		else
		{
			if( m_characterCustomizationState.GetLifePath() == T"LifePaths.Nomad" )
			{
				ApplyUIPreset( 'nomad', true );
			}
			else if( m_characterCustomizationState.GetLifePath() == T"LifePaths.StreetKid" )
			{
				ApplyUIPreset( 'street', true );
			}
			else if( m_characterCustomizationState.GetLifePath() == T"LifePaths.Corporate" )
			{
				ApplyUIPreset( 'corpo', true );
			}
		}
	}

	protected event OnPresetAppliedEvent( evt : gameuiCharacterCustomizationSystem_OnPresetAppliedEvent )
	{
		ReInitializeOptionsList();
	}

	public function ReInitializeOptionsList()
	{
		if( !( m_introPlayed ) )
		{
			InitializeList();
			OnIntro();
			m_introPlayed = true;
		}
		else
		{
			RefreshList();
		}
	}

	public function RefreshList()
	{
		var system : gameuiICharacterCustomizationSystem;
		var options : array< CharacterCustomizationOption >;
		const var option : CharacterCustomizationOption;
		var i, j : Int32;
		RequestCameraChange( m_defaultPreviewSlot );
		system = GetCharacterCustomizationSystem();
		options = system.GetUnitedOptions( true, true, true );
		UpdateVoiceOverWidget();
		i = ( ( UpdateVoiceOverWidget() ) ? ( 1 ) : ( 0 ) );
		for( j = 0; j < options.Size(); j += 1 )
		{
			option = options[ j ];
			if( ( option.isEditable && option.isActive ) && !( option.isCensored ) )
			{
				UpdateOption( i, option, option );
				i = i + 1;
			}
		}
	}

	public function UpdateVoiceOverWidget() : Bool
	{
		var switcherController : weak< characterCreationVoiceOverSwitcher >;
		switcherController = ( ( characterCreationVoiceOverSwitcher )( inkCompoundRef.GetWidgetByIndex( m_optionsList, 0 ).GetController() ) );
		if( switcherController )
		{
			switcherController.SetIsBrainGenderMale( m_characterCustomizationState.IsBrainGenderMale() );
			return true;
		}
		return false;
	}

	protected event OnRandomizeComplete( evt : gameuiCharacterCustomizationSystem_OnRandomizeCompleteEvent )
	{
		RequestCameraChange( m_defaultPreviewSlot );
		m_randomizing = false;
	}

	protected event OnAppearanceSwitched( evt : gameuiCharacterCustomizationSystem_OnAppearanceSwitchedEvent )
	{
		var i, j : Int32;
		var pair : gameuiSwitchPair;
		for( j = 0; j < evt.pairs.Size(); j += 1 )
		{
			pair = evt.pairs[ j ];
			if( pair.prevOption )
			{
				for( i = 0; i < inkCompoundRef.GetNumChildren( m_optionsList ); i += 1 )
				{
					if( UpdateOption( i, pair.prevOption, pair.currOption ) )
					{
						break;
					}
				}
			}
			else if( pair.currOption )
			{
				for( i = 0; i < inkCompoundRef.GetNumChildren( m_optionsList ); i += 1 )
				{
					if( UpdateOption( i, pair.currOption, pair.currOption ) )
					{
						break;
					}
				}
			}
		}
	}

	protected event OnOptionUpdated( evt : gameuiCharacterCustomizationSystem_OnOptionUpdatedEvent )
	{
		var i : Int32;
		for( i = 0; i < inkCompoundRef.GetNumChildren( m_optionsList ); i += 1 )
		{
			if( UpdateOption( i, evt.option, evt.option ) )
			{
				break;
			}
		}
	}

	protected event OnReFinalizeComplete( evt : gameuiCharacterCustomizationSystem_OnReFinalizeStateCompleteEvent )
	{
		NextMenu();
	}

	protected event OnCancelFinalizedStateUpdate( evt : gameuiCharacterCustomizationSystem_OnCancelFinalizedStateUpdateEvent )
	{
		OnOutro();
		m_eventDispatcher.SpawnEvent( 'OnCancel' );
	}

	public function UpdateOption( i : Int32, const lookupOption : weak< CharacterCustomizationOption >, const newOption : weak< CharacterCustomizationOption > ) : Bool
	{
		var optionController : characterCreationBodyMorphOption;
		var colorOptionController : characterCreationBodyMorphColorOption;
		const var option : weak< CharacterCustomizationOption >;
		optionController = ( ( characterCreationBodyMorphOption )( inkCompoundRef.GetWidgetByIndex( m_optionsList, i ).GetController() ) );
		if( optionController )
		{
			option = optionController.GetSelectorOption();
			if( lookupOption.info.uiSlot == option.info.uiSlot )
			{
				if( ( newOption && newOption.isActive ) && !( newOption.isCensored ) )
				{
					optionController.SetOption( newOption );
				}
				else
				{
					optionController.ResetOption();
				}
				return true;
			}
		}
		colorOptionController = ( ( characterCreationBodyMorphColorOption )( inkCompoundRef.GetWidgetByIndex( m_optionsList, i ).GetController() ) );
		if( colorOptionController )
		{
			option = colorOptionController.GetColorPickerOption();
			if( lookupOption.info.uiSlot == option.info.uiSlot )
			{
				if( ( newOption && newOption.isActive ) && !( newOption.isCensored ) )
				{
					colorOptionController.SetOption( newOption );
				}
				else
				{
					colorOptionController.ResetOption();
				}
				return true;
			}
		}
		return false;
	}

	protected event OnNextFrame( evt : NextFrameEvent )
	{
		if( m_hideColorPickerNextFrame )
		{
			HideColorPicker( -1 );
			m_scrollController.SetInputDisabled( false );
		}
	}

	protected event OnSliderChange( widget : weak< inkWidget > )
	{
		var optionController : weak< characterCreationBodyMorphOption >;
		const var option : CharacterCustomizationOption;
		var index : Uint32;
		optionController = ( ( characterCreationBodyMorphOption )( widget.GetController() ) );
		option = optionController.GetSelectorOption();
		index = optionController.GetSelectorIndex();
		GetCharacterCustomizationSystem().ApplyChangeToOption( option, index );
		if( !( m_randomizing ) )
		{
			RequestCameraChange( GetSlotName( option ) );
		}
		GetTelemetrySystem().LogInitialChoiceOptionSelected( option, index );
	}

	protected event OnColorPickerTriggered( widget : weak< inkWidget > )
	{
		var colorOptionController : weak< characterCreationBodyMorphColorOption >;
		var pickerController : weak< characterCreationBodyMorphOptionColorPicker >;
		const var appearanceInfo : gameuiAppearanceInfo;
		colorOptionController = ( ( characterCreationBodyMorphColorOption )( widget.GetController() ) );
		if( colorOptionController.IsColorPickerTriggered() )
		{
			m_colorPickerOwner = widget;
			m_colorPickerOwner.RegisterToCallback( 'OnHoverOver', this, 'OnHoverOverColorPickerOwner' );
			pickerController = ( ( characterCreationBodyMorphOptionColorPicker )( inkWidgetRef.GetController( m_colorPicker ) ) );
			pickerController.FillGrid( colorOptionController.GetColorPickerOption() );
			appearanceInfo = ( ( gameuiAppearanceInfo )( colorOptionController.GetColorPickerOption().info ) );
			pickerController.SetTitle( appearanceInfo.localizedName );
			inkWidgetRef.SetVisible( m_colorPicker, true );
			inkWidgetRef.SetVisible( m_colorPickerBG, true );
			m_animationProxy = inkWidgetRef.GetController( m_colorPickerBG ).PlayLibraryAnimation( 'color_picker_panel_intro' );
			m_animationProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnPanelIntroAnimFinished' );
			m_confirmAnimationProxy = PlayLibraryAnimation( 'color_picker_bg_intro' );
			m_optionListAnimationProxy = PlayLibraryAnimation( 'option_list_hide' );
			PlaySound( 'CharacterCreationConfirmationAnimation', 'OnClose' );
			m_cachedCursor = widget;
			RequestCameraChange( GetSlotName( colorOptionController.GetColorPickerOption() ) );
		}
		m_scrollController.SetInputDisabled( true );
	}

	protected event OnPanelIntroAnimFinished( proxy : inkAnimProxy )
	{
		var pickerController : weak< characterCreationBodyMorphOptionColorPicker >;
		if( !( GetPlayerControlledObject().PlayerLastUsedKBM() ) )
		{
			pickerController = ( ( characterCreationBodyMorphOptionColorPicker )( inkWidgetRef.GetController( m_colorPicker ) ) );
			pickerController.MoveCursorToSelected();
		}
	}

	protected event OnPreset1( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			if( e.IsAction( 'click' ) )
			{
				ApplyUIPreset( 'nomad' );
			}
		}
	}

	protected event OnPreset2( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			if( e.IsAction( 'click' ) )
			{
				ApplyUIPreset( 'street' );
			}
		}
	}

	protected event OnPreset3( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			if( e.IsAction( 'click' ) )
			{
				ApplyUIPreset( 'corpo' );
			}
		}
	}

	protected event OnRandomize( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			if( e.IsAction( 'click' ) )
			{
				GetCharacterCustomizationSystem().RandomizeOptions();
				GetTelemetrySystem().LogInitialChoicePresetSelected( 'random' );
				m_randomizing = true;
			}
		}
	}

	protected event OnHoverOverPreset1( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			inkImageRef.SetTexturePart( m_preset1Bg, 'preset_active' );
			m_isPresetHoveredOver = true;
		}
	}

	protected event OnHoverOverPreset2( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			inkImageRef.SetTexturePart( m_preset2Bg, 'preset_active' );
			m_isPresetHoveredOver = true;
		}
	}

	protected event OnHoverOverPreset3( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			inkImageRef.SetTexturePart( m_preset3Bg, 'preset_active' );
			m_isPresetHoveredOver = true;
		}
	}

	protected event OnHoverOverRandomize( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			inkImageRef.SetTexturePart( m_randomizBg, 'preset_active' );
			inkImageRef.SetState( m_randomizThumbnail, 'Hover' );
			m_isPresetHoveredOver = true;
		}
	}

	protected event OnHoverOutPreset1( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			inkImageRef.SetTexturePart( m_preset1Bg, 'preset_idle' );
		}
		m_isPresetHoveredOver = false;
	}

	protected event OnHoverOutPreset2( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			inkImageRef.SetTexturePart( m_preset2Bg, 'preset_idle' );
		}
		m_isPresetHoveredOver = false;
	}

	protected event OnHoverOutPreset3( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			inkImageRef.SetTexturePart( m_preset3Bg, 'preset_idle' );
		}
		m_isPresetHoveredOver = false;
	}

	protected event OnHoverOutRandomize( e : inkPointerEvent )
	{
		if( !( m_inputDisabled ) )
		{
			inkImageRef.SetTexturePart( m_randomizBg, 'preset_idle' );
			inkImageRef.SetState( m_randomizThumbnail, 'DEfault' );
		}
		m_isPresetHoveredOver = false;
	}

	protected event OnColorPickerClose( e : inkPointerEvent )
	{
		if( e.IsAction( 'click' ) )
		{
			m_hideColorPickerNextFrame = true;
			QueueEvent( new NextFrameEvent );
		}
	}

	protected event OnConfirmationClose( e : inkPointerEvent )
	{
		if( e.IsAction( 'click' ) )
		{
			HideConfirmation();
		}
	}

	protected event OnConfirmationConfirm( e : inkPointerEvent )
	{
		if( e.IsAction( 'click' ) )
		{
			ConfirmBackConfirmation();
		}
	}

	public function ConfirmBackConfirmation()
	{
		var system : gameuiICharacterCustomizationSystem;
		if( m_updatingFinalizedState )
		{
			PlaySound( 'Button', 'OnPress' );
			GetTelemetrySystem().LogInitialChoiceSetStatege( telemetryInitalChoiceStage.None );
			GetTelemetrySystem().LogCharacterCustomizationCancelled();
			system = GetCharacterCustomizationSystem();
			system.CancelFinalizedStateUpdate();
		}
		else
		{
			PriorMenu();
		}
	}

	public function ConfirmCustomizedCharacter()
	{
		var system : gameuiICharacterCustomizationSystem;
		if( m_updatingFinalizedState )
		{
			PlaySound( 'Button', 'OnPress' );
			GetTelemetrySystem().LogInitialChoiceSetStatege( telemetryInitalChoiceStage.Finished );
			GetTelemetrySystem().LogCharacterCustomizationChanged();
			system = GetCharacterCustomizationSystem();
			system.ReFinalizeState();
		}
		else
		{
			NextMenu();
		}
	}

	protected event OnPrevious( e : inkPointerEvent )
	{
		if( e.IsAction( 'click' ) )
		{
			if( !( inkWidgetRef.IsVisible( m_backConfirmation ) ) )
			{
				ShowConfirmation();
			}
			else
			{
				PriorMenu();
			}
		}
	}

	protected event OnListRelease( e : inkPointerEvent )
	{
		if( e.IsHandled() )
		{
			return false;
		}
		m_menuListController.HandleInput( e, this );
	}

	protected event OnHoverOutPreviousPageBtn( e : inkPointerEvent )
	{
		inkImageRef.SetTexturePart( m_previousPageBtnBg, 'button_prev_idle' );
	}

	protected event OnHoverOverPreviousPageBtn( e : inkPointerEvent )
	{
		inkImageRef.SetTexturePart( m_previousPageBtnBg, 'button_prev_active' );
	}

	protected event OnHoverOutNextPageBtn( e : inkPointerEvent )
	{
		inkImageRef.SetTexturePart( m_nextPageBtnBg, 'button_next_idle' );
	}

	protected event OnHoverOverNextPageBtn( e : inkPointerEvent )
	{
		inkImageRef.SetTexturePart( m_nextPageBtnBg, 'button_next_active' );
	}

	protected event OnHoverOverColorPickerOwner( e : inkPointerEvent )
	{
		if( e.GetTarget() == m_colorPickerOwner )
		{
			m_hideColorPickerNextFrame = false;
		}
	}

	protected event OnButtonRelease( evt : inkPointerEvent )
	{
		if( !( evt.IsHandled() ) )
		{
			if( evt.IsAction( 'back' ) && !( m_animationProxy.IsPlaying() ) )
			{
				if( inkWidgetRef.IsVisible( m_colorPicker ) )
				{
					m_hideColorPickerNextFrame = true;
					QueueEvent( new NextFrameEvent );
				}
				else if( inkWidgetRef.IsVisible( m_backConfirmation ) )
				{
					PlaySound( 'Button', 'OnPress' );
					HideConfirmation();
				}
				else
				{
					ShowConfirmation();
				}
			}
			else if( evt.IsAction( 'system_notification_confirm' ) && inkWidgetRef.IsVisible( m_backConfirmation ) )
			{
				ConfirmBackConfirmation();
			}
			else if( ( ( evt.IsAction( 'one_click_confirm' ) && !( inkWidgetRef.IsVisible( m_colorPicker ) ) ) && !( inkWidgetRef.IsVisible( m_backConfirmation ) ) ) && !( IsOptionHoveredOver() ) )
			{
				ConfirmCustomizedCharacter();
			}
			else
			{
				return false;
			}
			evt.Handle();
		}
	}

	private function IsOptionHoveredOver() : Bool
	{
		var controller : CharacterCreationBodyMorphBaseOption;
		var i : Int32;
		if( m_isPresetHoveredOver )
		{
			return true;
		}
		for( i = 0; i < inkCompoundRef.GetNumChildren( m_optionsList ); i += 1 )
		{
			controller = ( ( CharacterCreationBodyMorphBaseOption )( inkCompoundRef.GetWidget( m_optionsList, i ).GetController() ) );
			if( controller && controller.IsPrevOrNextBtnHoveredOver() )
			{
				return true;
			}
		}
		return false;
	}

	protected event OnHoverOverColorPicker( e : inkPointerEvent )
	{
		if( e.GetTarget() == inkWidgetRef.Get( m_colorPicker ) )
		{
			m_hideColorPickerNextFrame = false;
		}
	}

	protected event OnColorSelected( widget : weak< inkWidget > )
	{
		var pickerController : weak< characterCreationBodyMorphOptionColorPicker >;
		var colorOptionController : weak< characterCreationBodyMorphColorOption >;
		const var option : CharacterCustomizationOption;
		var index : Uint32;
		pickerController = ( ( characterCreationBodyMorphOptionColorPicker )( inkWidgetRef.GetController( m_colorPicker ) ) );
		option = pickerController.GetOption();
		index = ( ( Uint32 )( pickerController.GetSelectedIndex() ) );
		GetCharacterCustomizationSystem().ApplyChangeToOption( option, index );
		RequestCameraChange( GetSlotName( option ) );
		GetTelemetrySystem().LogInitialChoiceOptionSelected( option, index );
		colorOptionController = ( ( characterCreationBodyMorphColorOption )( m_colorPickerOwner.GetController() ) );
		colorOptionController.RefreshColorPicker( ( ( Int32 )( index ) ), false );
	}

	protected event OnColorChange( widget : weak< inkWidget > )
	{
		var optionController : weak< characterCreationBodyMorphColorOption >;
		const var option : CharacterCustomizationOption;
		var index : Uint32;
		optionController = ( ( characterCreationBodyMorphColorOption )( widget.GetController() ) );
		option = optionController.GetColorPickerOption();
		index = optionController.GetColorIndex();
		GetCharacterCustomizationSystem().ApplyChangeToOption( option, index );
		if( !( m_randomizing ) )
		{
			RequestCameraChange( GetSlotName( option ) );
		}
		GetTelemetrySystem().LogInitialChoiceOptionSelected( option, index );
	}

	protected event OnVoiceOverSwitched( widget : weak< inkWidget > )
	{
		var switcherController : weak< characterCreationVoiceOverSwitcher >;
		var isMale : Bool;
		switcherController = ( ( characterCreationVoiceOverSwitcher )( widget.GetController() ) );
		isMale = switcherController.IsBrainGenderMale();
		if( isMale != m_characterCustomizationState.IsBrainGenderMale() )
		{
			m_characterCustomizationState.SetIsBrainGenderMale( isMale );
			GetCharacterCustomizationSystem().TriggerVoiceToneSample();
			GetTelemetrySystem().LogInitialChoiceBrainGenderSelected( isMale );
		}
	}

	protected event OnHoverOverOption( e : inkPointerEvent )
	{
		var voiceOverSwitcher : weak< characterCreationVoiceOverSwitcher >;
		var optionController : weak< characterCreationBodyMorphOption >;
		var colorOptionController : weak< characterCreationBodyMorphColorOption >;
		if( !( m_colorPickerOwner ) )
		{
			voiceOverSwitcher = ( ( characterCreationVoiceOverSwitcher )( e.GetTarget().GetController() ) );
			if( voiceOverSwitcher )
			{
				RequestCameraChange( 'UI_Skin', true );
			}
			optionController = ( ( characterCreationBodyMorphOption )( e.GetTarget().GetController() ) );
			if( optionController )
			{
				RequestCameraChange( GetSlotName( optionController.GetSelectorOption() ), true );
			}
			colorOptionController = ( ( characterCreationBodyMorphColorOption )( e.GetTarget().GetController() ) );
			if( colorOptionController )
			{
				RequestCameraChange( GetSlotName( colorOptionController.GetColorPickerOption() ), true );
			}
		}
	}

	public function InitializeList()
	{
		var system : gameuiICharacterCustomizationSystem;
		var options : array< CharacterCustomizationOption >;
		const var option : CharacterCustomizationOption;
		var i : Int32;
		if( m_characterCustomizationState.IsBodyGenderMale() )
		{
			inkImageRef.SetTexturePart( m_preset1Thumbnail, 'preset_nom_m' );
			inkImageRef.SetTexturePart( m_preset2Thumbnail, 'preset_str_m' );
			inkImageRef.SetTexturePart( m_preset3Thumbnail, 'preset_cor_m' );
			inkImageRef.SetTexturePart( m_randomizThumbnail, 'preset_random_m' );
		}
		else
		{
			inkImageRef.SetTexturePart( m_preset1Thumbnail, 'preset_nom_f' );
			inkImageRef.SetTexturePart( m_preset2Thumbnail, 'preset_str_f' );
			inkImageRef.SetTexturePart( m_preset3Thumbnail, 'preset_cor_f' );
			inkImageRef.SetTexturePart( m_randomizThumbnail, 'preset_random_f' );
		}
		RequestCameraChange( m_defaultPreviewSlot );
		system = GetCharacterCustomizationSystem();
		system.ApplyEditTag( m_editMode );
		options = system.GetUnitedOptions( true, true, true );
		inkCompoundRef.RemoveAllChildren( m_optionsList );
		if( system.IsTransgenderAllowed() && m_editMode == gameuiCharacterCustomizationEditTag.NewGame )
		{
			CreateVoiceOverSwitcher();
		}
		for( i = 0; i < options.Size(); i += 1 )
		{
			option = options[ i ];
			if( ( option.isEditable && option.isActive ) && !( option.isCensored ) )
			{
				CreateEntry( option );
			}
		}
	}

	public function CreateVoiceOverSwitcher()
	{
		var switcherWidget : weak< inkWidget >;
		var switcherController : weak< characterCreationVoiceOverSwitcher >;
		switcherWidget = SpawnFromLocal( inkCompoundRef.Get( m_optionsList ), 'VoiceOverSwitcher' );
		switcherController = ( ( characterCreationVoiceOverSwitcher )( switcherWidget.GetController() ) );
		switcherController.RegisterToCallback( 'OnVoiceOverSwitched', this, 'OnVoiceOverSwitched' );
		switcherWidget.RegisterToCallback( 'OnHoverOver', this, 'OnHoverOverOption' );
		switcherController.SetIsBrainGenderMale( m_characterCustomizationState.IsBrainGenderMale() );
	}

	public function CreateEntry( const option : CharacterCustomizationOption ) : weak< inkWidget >
	{
		const var appearanceInfo : weak< gameuiAppearanceInfo >;
		var optionWidget : weak< inkWidget >;
		var optionController : weak< characterCreationBodyMorphOption >;
		var colorOptionController : weak< characterCreationBodyMorphColorOption >;
		appearanceInfo = ( ( gameuiAppearanceInfo )( option.info ) );
		if( appearanceInfo && appearanceInfo.useThumbnails )
		{
			optionWidget = SpawnFromLocal( inkCompoundRef.Get( m_optionsList ), 'ColorPicker' );
			colorOptionController = ( ( characterCreationBodyMorphColorOption )( optionWidget.GetController() ) );
			colorOptionController.SetOption( option );
			colorOptionController.RegisterToCallback( 'OnColorPickerTriggered', this, 'OnColorPickerTriggered' );
			optionWidget.RegisterToCallback( 'OnHoverOver', this, 'OnHoverOverOption' );
			colorOptionController.RegisterToCallback( 'OnColorChange', this, 'OnColorChange' );
		}
		else
		{
			optionWidget = SpawnFromLocal( inkCompoundRef.Get( m_optionsList ), 'Selector' );
			optionController = ( ( characterCreationBodyMorphOption )( optionWidget.GetController() ) );
			optionController.SetOption( option );
			optionController.RegisterToCallback( 'OnSliderChange', this, 'OnSliderChange' );
			optionWidget.RegisterToCallback( 'OnHoverOver', this, 'OnHoverOverOption' );
		}
		return optionWidget;
	}

	public function HideColorPicker( index : Int32 )
	{
		var colorOptionController : weak< characterCreationBodyMorphColorOption >;
		if( inkWidgetRef.IsVisible( m_colorPicker ) )
		{
			if( m_colorPickerOwner )
			{
				colorOptionController = ( ( characterCreationBodyMorphColorOption )( m_colorPickerOwner.GetController() ) );
				if( colorOptionController )
				{
					colorOptionController.RefreshColorPicker( ( ( Int32 )( colorOptionController.GetColorIndex() ) ), false );
				}
			}
			m_colorPickerOwner.UnregisterFromCallback( 'OnHoverOver', this, 'OnHoverOverColorPickerOwner' );
			m_colorPickerOwner = NULL;
			m_optionList.SetVisible( true );
			m_optionListAnimationProxy = PlayLibraryAnimation( 'option_list_show' );
			inkWidgetRef.SetVisible( m_colorPicker, false );
			inkWidgetRef.SetVisible( m_colorPickerBG, false );
			SetCursorOverWidget( m_cachedCursor );
			PlaySound( 'CharacterCreationConfirmationAnimation', 'OnClose' );
		}
	}

	public function ApplyUIPreset( presetName : CName, optional fromInit : Bool )
	{
		GetCharacterCustomizationSystem().ApplyUIPreset( presetName );
		GetTelemetrySystem().LogInitialChoicePresetSelected( presetName, fromInit );
	}

	public function OnIntro()
	{
		PlayAnim( 'intro', 'OnIntroComplete', m_animationProxy );
	}

	public function OnOutro()
	{
		PlayAnim( 'outro', , m_animationProxy );
	}

	public function DisableInputBelowConfirmationPopup( disabled : Bool )
	{
		var i : Int32;
		var optionController : characterCreationBodyMorphOption;
		var colorOptionController : characterCreationBodyMorphColorOption;
		var switcherController : weak< characterCreationVoiceOverSwitcher >;
		var puppetPreviewGameController : weak< inkCharacterCreationPuppetPreviewGameController >;
		for( i = 0; i < inkCompoundRef.GetNumChildren( m_optionsList ); i += 1 )
		{
			optionController = ( ( characterCreationBodyMorphOption )( inkCompoundRef.GetWidgetByIndex( m_optionsList, i ).GetController() ) );
			if( optionController )
			{
				optionController.SetInputDisabled( disabled );
			}
			colorOptionController = ( ( characterCreationBodyMorphColorOption )( inkCompoundRef.GetWidgetByIndex( m_optionsList, i ).GetController() ) );
			if( colorOptionController )
			{
				colorOptionController.SetInputDisabled( disabled );
			}
		}
		for( i = 0; i < m_navigationControllers.Size(); i += 1 )
		{
			m_navigationControllers[ i ].SetInputDisabled( disabled );
		}
		switcherController = ( ( characterCreationVoiceOverSwitcher )( inkCompoundRef.GetWidgetByIndex( m_optionsList, 0 ).GetController() ) );
		if( switcherController )
		{
			switcherController.SetInputDisabled( disabled );
		}
		m_scrollController.SetInputDisabled( disabled );
		m_sliderController.SetInputDisabled( disabled );
		puppetPreviewGameController = GetCharacterCustomizationSystem().GetPuppetPreviewGameController();
		if( puppetPreviewGameController )
		{
			puppetPreviewGameController.SetInputDisabled( disabled );
		}
		inkImageRef.SetTexturePart( m_preset1Bg, 'preset_idle' );
		inkImageRef.SetTexturePart( m_preset2Bg, 'preset_idle' );
		inkImageRef.SetTexturePart( m_preset3Bg, 'preset_idle' );
		inkImageRef.SetTexturePart( m_randomizBg, 'preset_idle' );
		inkImageRef.SetState( m_randomizThumbnail, 'Default' );
		m_inputDisabled = disabled;
	}

	public function ShowConfirmation()
	{
		PlaySound( 'SaveDeleteButton', 'OnPress' );
		inkWidgetRef.SetVisible( m_backConfirmation, true );
		inkWidgetRef.SetVisible( m_navigationButtons, false );
		m_animationProxy = inkWidgetRef.GetController( m_backConfirmationWidget ).PlayLibraryAnimation( 'confirmation_intro' );
		m_confirmAnimationProxy = inkWidgetRef.GetController( m_backConfirmation ).PlayLibraryAnimation( 'confirmation_popup_btns' );
		DisableInputBelowConfirmationPopup( true );
	}

	public function HideConfirmation()
	{
		inkWidgetRef.SetVisible( m_backConfirmation, false );
		inkWidgetRef.SetVisible( m_navigationButtons, true );
		DisableInputBelowConfirmationPopup( false );
	}

	protected override function PriorMenu()
	{
		OnOutro();
		super.PriorMenu();
		PlaySound( 'Button', 'OnPress' );
	}

	protected override function NextMenu()
	{
		OnOutro();
		super.NextMenu();
	}

	public function PlayAnim( animName : CName, optional callBack : CName, animProxy : inkAnimProxy )
	{
		if( animProxy && animProxy.IsPlaying() )
		{
			animProxy.Stop();
		}
		animProxy = PlayLibraryAnimation( animName );
		if( callBack != '' )
		{
			animProxy.RegisterToCallback( inkanimEventType.OnFinish, this, callBack );
		}
	}

	public function GetSlotName( option : CharacterCustomizationOption ) : CName
	{
		if( option.bodyPart == gameuiCharacterCustomizationPart.Head )
		{
			if( option.info.name == 'skin_color' || option.info.name == 'skin_type' )
			{
				return 'UI_Skin';
			}
			else if( option.info.uiSlot == 'hairstyle' || option.info.uiSlot == 'hair_color' )
			{
				return 'UI_Hairs';
			}
			else if( ( ( ( ( ( option.info.name == 'eyes' || option.info.name == 'eyes_color' ) || option.info.name == 'eyebrows' ) || option.info.uiSlot == 'eyesbrows_color' ) || option.info.name == 'eyelash_color' ) || option.info.name == 'makeupEyes' ) || option.info.uiSlot == 'makeupEyes_color' )
			{
				return 'UI_Eyes';
			}
			else if( option.info.name == 'teeth' )
			{
				return 'UI_Teeth';
			}
			else if( option.info.name == 'nose' )
			{
				return 'UI_Nose';
			}
			else if( ( ( option.info.name == 'makeupLips_type' || option.info.name == 'makeupLips' ) || option.info.uiSlot == 'makeupLips_color' ) || option.info.name == 'mouth' )
			{
				return 'UI_Lips';
			}
			else if( ( ( option.info.name == 'jaw' || option.info.name == 'beard' ) || option.info.uiSlot == 'beard_part' ) || option.info.uiSlot == 'beard_color' )
			{
				return 'UI_Jaw';
			}
			else
			{
				return 'UI_HeadPreview';
			}
		}
		else if( option.bodyPart == gameuiCharacterCustomizationPart.Arms )
		{
			return 'UI_FingerNails';
		}
		return 'UI_Preview';
	}

	private function SetTimeDilatation( enable : Bool )
	{
		var timeSystem : TimeSystem;
		var timeDilationReason : CName;
		timeDilationReason = 'VendorStash';
		timeSystem = GameInstance.GetTimeSystem( GetPlayerControlledObject().GetGame() );
		if( enable )
		{
			timeSystem.SetTimeDilation( timeDilationReason, 0.0, , 'Linear', 'Linear' );
			timeSystem.SetTimeDilationOnLocalPlayerZero( timeDilationReason, 0.0, , 'Linear', 'Linear' );
		}
		else
		{
			timeSystem.UnsetTimeDilation( timeDilationReason );
			timeSystem.UnsetTimeDilationOnLocalPlayerZero( timeDilationReason );
		}
	}

}

class NextFrameEvent extends Event
{
}

