class MapMenuUserData extends IScriptable
{
	var m_moveTo : Vector3;
	var m_hash : Int32;
	var m_isTracked : Bool;
}

class MapNavigationDelay extends Event
{
}

import enum gameuiEWorldMapCameraMode : Uint8
{
	TopDown,
	ZoomLevels,
	COUNT,
}

enum EWorldMapView
{
	Map = 0,
}

import enum gameuiEWorldMapDistrictView
{
	None,
	Districts,
	SubDistricts,
}

import enum gameuiMappinGroupState
{
	Ungrouped,
	Grouped,
	GroupedCollection,
	GroupedHidden,
}

enum ECustomFilterDPadNavigationOption
{
	SelectNext = 0,
	SelectPrev = 1,
	Toggle = 2,
}

import class inkWorldMapPreviewGameController extends gameuiMenuGameController
{
	public import function GetCameraMode() : gameuiEWorldMapCameraMode;
	public import function SetCameraMode( cameraMode : gameuiEWorldMapCameraMode );
	public import function JumpToZoomLevel( zoomLevel : Int32 );
	public import function ZoomIn( optional strength : Float );
	public import function ZoomOut( optional strength : Float );
	public import function RotateYaw( strength : Float );
	public import function RotatePitch( strength : Float );
	public import function Move( direction : Vector4, strength : Float );
	public import function MoveTo( direction : Vector3 );
}

import class WorldMapMenuGameController extends MappinsContainerController
{
	protected import function IsEntitySetup() : Bool;
	protected import function IsEntityAttachedAndSetup() : Bool;
	protected import function GetSettings() : WorldMapSettings_Record;
	protected import function GetEntityPreview() : weak< inkWorldMapPreviewGameController >;
	protected import function SetSelectedMappin( mappinController : BaseWorldMapMappinController );
	protected import function HasCustomFilter( filter : gamedataWorldMapFilter ) : Bool;
	protected import function GetCustomFilters() : Uint32;
	protected import function SetCustomFilter( filter : gamedataWorldMapFilter );
	protected import function ClearCustomFilter( filter : gamedataWorldMapFilter );
	protected import function GetQuickFilter() : gamedataWorldMapFilter;
	protected import function SetQuickFilter( filter : gamedataWorldMapFilter );
	protected import function SetQuickFilterFromRecord( filterGroup : weak< MappinUIFilterGroup_Record > );
	protected import function SaveFilters();
	protected import function SetMapCursorEnabled( enabled : Bool );
	protected import function TrackMappin( mappinController : BaseMappinBaseController );
	protected import function UntrackMappin();
	protected import function TrackCustomPositionMappin();
	protected import function TrackDelamainTaxiMappin();
	protected import function UntrackCustomPositionMappin();
	protected import function UntrackDelamainTaxiMappin();
	protected import function ConfirmDelamainTaxiMappinPosition();
	protected import function CancelDelamainTaxiMappinPosition();
	protected import function GetTravelDistance() : Float;
	protected import function SetMappinVisited( mappinController : BaseWorldMapMappinController );
	protected import function MoveToPlayer();
	protected import function ZoomToMappin( mappinController : BaseWorldMapMappinController );
	protected import function ZoomWithMouse( zoomIn : Bool );
	protected import function FrameMappinPath( hash : Uint32, transitionTime : Float, optional margin : inkMargin );
	protected import function SetMousePanEnabled( enabled : Bool );
	protected import function SetMouseRotateEnabled( enabled : Bool );
	protected import function AreDistrictsVisible() : Bool;
	protected import function GetCurrentZoom() : Float;
	protected import function CanDebugTeleport() : Bool;

	private import editable var entityPreviewSpawnContainer : inkCompoundRef;
	private import editable var tooltipContainer : inkCompoundRef;
	private import editable var tooltipOffset : inkMargin;
	private import editable var districtsContainer : inkCompoundRef;
	private import editable var subdistrictsContainer : inkCompoundRef;
	private import const editable var isZoomToMappinEnabled : Bool;
	private editable var m_preloaderWidget : inkWidgetRef;
	private editable var m_gameTimeText : inkTextRef;
	private editable var m_fastTravelInstructions : inkWidgetRef;
	private editable var m_delamainTaxiInstructions : inkWidgetRef;
	private editable var m_filterSelector : inkWidgetRef;
	private editable var m_filterSelectorWarning : inkWidgetRef;
	private editable var m_filterText : inkTextRef;
	private editable var m_districtIconImageContainer : inkWidgetRef;
	private editable var m_districtIconImage : inkImageRef;
	private editable var m_districtNameText : inkTextRef;
	private editable var m_subdistrictNameText : inkTextRef;
	private editable var m_locationAndGangsContainer : inkWidgetRef;
	private editable var m_gangsInfoContainer : inkWidgetRef;
	private editable var m_gangsList : inkCompoundRef;
	private editable var m_questContainer : inkWidgetRef;
	private editable var m_questName : inkTextRef;
	private editable var m_openInJournalButton : inkWidgetRef;
	private editable var m_objectiveName : inkTextRef;
	private editable var m_objectiveBackground : inkWidgetRef;
	private editable var m_objectiveFrame : inkWidgetRef;
	private editable var m_topShadow : inkWidgetRef;
	private editable var m_rightAxisZoomThreshold : Float;
	default m_rightAxisZoomThreshold = 0.8f;
	private editable var m_customFilters : inkWidgetRef;
	private editable var m_filtersList : inkVerticalPanelRef;
	private editable var m_filterLeftArrow : inkWidgetRef;
	private editable var m_filterRightArrow : inkWidgetRef;
	private const editable var m_quickFilterIndicators : array< inkWidgetRef >;
	private editable var m_customFiltersListAnimationDelay : Float;
	private import const var districtView : gameuiEWorldMapDistrictView;
	private import const var selectedDistrict : gamedataDistrict;
	private import const var canChangeCustomFilter : Bool;
	private import var selectedMappin : weak< BaseWorldMapMappinController >;
	private import const var delamainTaxiMappinID : NewMappinID;
	private var m_cameraMode : gameuiEWorldMapCameraMode;
	private var m_menuEventDispatcher : weak< inkMenuEventDispatcher >;
	private var m_tooltipController : weak< WorldMapTooltipContainer >;
	private var m_gameTimeTextParams : inkTextParams;
	private var m_previousHoveredDistrict : gamedataDistrict;
	private var m_currentHoveredDistrict : gamedataDistrict;
	private var m_showedSubdistrictGangs : Bool;
	private var m_player : weak< GameObject >;
	private var m_audioSystem : weak< AudioSystem >;
	private var m_journalManager : weak< JournalManager >;
	private var m_mappinSystem : weak< MappinSystem >;
	private var m_mapBlackboard : weak< IBlackboard >;
	private var m_mapDefinition : UI_MapDef;
	private var m_trackedObjective : weak< JournalQuestObjectiveBase >;
	private var m_trackedQuest : weak< JournalQuest >;
	private var m_mappinsPositions : array< Vector3 >;
	private var m_lastRightAxisYAmount : Float;
	default m_lastRightAxisYAmount = 0.f;
	private var m_justOpenedQuestJournal : Bool;
	default m_justOpenedQuestJournal = false;
	var m_initMappinFocus : MapMenuUserData;
	private var m_currentQuickFilterIndex : Int32;
	private var m_currentCustomFilterIndex : Int32;
	private var m_spawnedCustomFilterIndex : Int32;
	private var m_gangsAsyncSpawnRequests : array< weak< inkAsyncSpawnRequest > >;
	private var m_customFiltersList : array< weak< WorldMapFiltersListItem > >;
	private var m_animationProxy : inkAnimProxy;
	private var m_entityAttached : Bool;
	private var m_readyToZoom : Bool;
	default m_readyToZoom = false;
	private var m_isHoveringOverFilters : Bool;
	private var m_isPanning : Bool;
	private var m_isZooming : Bool;
	private var m_pressedRMB : Bool;
	private var m_startedFastTraveling : Bool;

	protected event OnInitialize()
	{
		var evt : inkMenuLayer_SetCursorType;
		m_player = GetPlayerControlledObject();
		m_journalManager = GameInstance.GetJournalManager( m_player.GetGame() );
		m_mappinSystem = GameInstance.GetMappinSystem( m_player.GetGame() );
		m_audioSystem = GameInstance.GetAudioSystem( m_player.GetGame() );
		m_tooltipController = ( ( WorldMapTooltipContainer )( inkCompoundRef.GetController( tooltipContainer ) ) );
		m_previousHoveredDistrict = gamedataDistrict.Invalid;
		m_currentHoveredDistrict = gamedataDistrict.Invalid;
		m_showedSubdistrictGangs = false;
		inkWidgetRef.SetVisible( m_fastTravelInstructions, false );
		inkWidgetRef.SetVisible( m_delamainTaxiInstructions, false );
		inkWidgetRef.SetVisible( m_openInJournalButton, false );
		HideAllTooltips();
		m_cameraMode = gameuiEWorldMapCameraMode.TopDown;
		RefreshInputHints();
		UpdateGameTime();
		m_mapDefinition = GetAllBlackboardDefs().UI_Map;
		m_mapBlackboard = GetBlackboardSystem().Get( m_mapDefinition );
		m_mapBlackboard.SignalString( m_mapDefinition.currentLocation );
		m_journalManager.RegisterScriptCallback( this, 'OnTrackedEntryChanges', gameJournalListenerType.Tracked );
		UpdateTrackedQuest();
		m_mapBlackboard.SetString( m_mapDefinition.currentState, "Initialized" );
		GameInstance.GetTimeSystem( m_player.GetGame() ).SetTimeDilation( 'WorldMap', 0.0 );
		GameInstance.GetGodModeSystem( m_player.GetGame() ).AddGodMode( m_player.GetEntityID(), gameGodModeType.Invulnerable, 'WorldMap' );
		PlayLibraryAnimation( 'OnShowMenu' );
		InitializeQuickFiltersList();
		InitializeCustomFiltersList();
		inkWidgetRef.SetVisible( m_customFilters, GetQuickFilter() == gamedataWorldMapFilter.CustomFilter );
		inkWidgetRef.RegisterToCallback( m_preloaderWidget, 'OnFinished', this, 'OnRemovePreloader' );
		evt = new inkMenuLayer_SetCursorType;
		evt.Init( 'world_map' );
		QueueEvent( evt );
		inkWidgetRef.SetVisible( m_locationAndGangsContainer, false );
	}

	protected event OnUninitialize()
	{
		var evt : inkMenuLayer_SetCursorType;
		if( !( IsFastTravelEnabled() ) )
		{
			SaveFilters();
		}
		GameInstance.GetTimeSystem( m_player.GetGame() ).UnsetTimeDilation( 'WorldMap' );
		GameInstance.GetGodModeSystem( m_player.GetGame() ).RemoveGodMode( m_player.GetEntityID(), gameGodModeType.Invulnerable, 'WorldMap' );
		m_menuEventDispatcher.UnregisterFromEvent( 'OnBack', this, 'OnBack' );
		m_mapBlackboard.SetString( m_mapDefinition.currentState, "Uninitialized" );
		UninitializeCustomFiltersList();
		inkWidgetRef.UnregisterFromCallback( m_preloaderWidget, 'OnFinished', this, 'OnRemovePreloader' );
		m_audioSystem.Play( 'ui_menu_scrolling_stop' );
		if( m_startedFastTraveling )
		{
			m_audioSystem.Play( 'ui_menu_item_crafting_fail' );
		}
		evt = new inkMenuLayer_SetCursorType;
		evt.Init( 'default' );
		QueueEvent( evt );
		CancelDelamainTaxiMappinPosition();
	}

	private function InitializeQuickFiltersList()
	{
		var filterGroup : weak< MappinUIFilterGroup_Record >;
		var filtersList : weak< WorldMapFiltersList_Record >;
		var filterType : gamedataWorldMapFilter;
		var count, i : Int32;
		m_currentQuickFilterIndex = -1;
		filterType = GetQuickFilter();
		filtersList = ( ( WorldMapFiltersList_Record )( TweakDBInterface.GetWorldMapFiltersListRecord( T"WorldMap.WorldMapQuickFiltersList" ) ) );
		count = filtersList.GetListCount();
		for( i = 0; i < count; i += 1 )
		{
			filterGroup = filtersList.GetListItem( i );
			if( filterGroup.FilterType().Type() == filterType )
			{
				m_currentQuickFilterIndex = i;
				SetQuickFilterFromRecord( filterGroup );
				break;
			}
		}
		if( ( m_currentQuickFilterIndex == -1 ) && ( count > 0 ) )
		{
			m_currentQuickFilterIndex = 0;
			filterGroup = filtersList.GetListItem( m_currentQuickFilterIndex );
			SetQuickFilterFromRecord( filterGroup );
		}
		inkWidgetRef.RegisterToCallback( m_filterLeftArrow, 'OnRelease', this, 'OnFilterLeftArrowClicked' );
		inkWidgetRef.RegisterToCallback( m_filterRightArrow, 'OnRelease', this, 'OnFilterRightArrowClicked' );
		inkWidgetRef.RegisterToCallback( m_filterLeftArrow, 'OnEnter', this, 'OnFilterArrowHoverOver' );
		inkWidgetRef.RegisterToCallback( m_filterLeftArrow, 'OnLeave', this, 'OnFilterArrowHoverOut' );
		inkWidgetRef.RegisterToCallback( m_filterRightArrow, 'OnEnter', this, 'OnFilterArrowHoverOver' );
		inkWidgetRef.RegisterToCallback( m_filterRightArrow, 'OnLeave', this, 'OnFilterArrowHoverOut' );
		SetQuickFilterIndicator( m_currentQuickFilterIndex );
	}

	protected event OnFilterLeftArrowClicked( evt : inkPointerEvent )
	{
		if( evt.IsAction( 'click' ) )
		{
			evt.Consume();
			CycleQuickFilterPrev();
		}
	}

	protected event OnFilterRightArrowClicked( evt : inkPointerEvent )
	{
		if( evt.IsAction( 'click' ) )
		{
			evt.Consume();
			CycleQuickFilterNext();
		}
	}

	protected event OnFilterArrowHoverOver( e : inkPointerEvent )
	{
		m_isHoveringOverFilters = true;
	}

	protected event OnFilterArrowHoverOut( e : inkPointerEvent )
	{
		m_isHoveringOverFilters = false;
	}

	protected event OnQuickFilterChanged( filterGroup : weak< MappinUIFilterGroup_Record > )
	{
		var i, customFiltersListSize : Int32;
		inkTextRef.SetLocalizedTextScript( m_filterText, filterGroup.FilterName() );
		if( filterGroup.FilterType().Type() == gamedataWorldMapFilter.CustomFilter )
		{
			inkWidgetRef.SetVisible( m_customFilters, true );
			PlayCustomFiltersAnimations();
		}
		else
		{
			customFiltersListSize = m_customFiltersList.Size();
			for( i = 0; i < customFiltersListSize; i += 1 )
			{
				if( m_customFiltersList[ i ].IsFilterHovered() && !( m_customFiltersList[ i ].IsFilterEnabled() ) )
				{
					m_customFiltersList[ i ].SetFilterState( 'Default' );
				}
				else if( m_customFiltersList[ i ].IsFilterEnabled() )
				{
					m_customFiltersList[ i ].SetFilterState( 'Selected' );
				}
			}
			inkWidgetRef.SetVisible( m_customFilters, false );
		}
		if( filterGroup.FilterType().Type() == gamedataWorldMapFilter.NoFilter )
		{
			inkWidgetRef.SetState( m_filterSelector, 'Default' );
			inkWidgetRef.SetVisible( m_filterSelectorWarning, false );
		}
		else
		{
			inkWidgetRef.SetState( m_filterSelector, 'Selected' );
			inkWidgetRef.SetVisible( m_filterSelectorWarning, true );
		}
	}

	private function InitializeCustomFiltersList()
	{
		var filterGroup : weak< MappinUIFilterGroup_Record >;
		var filtersList : weak< WorldMapFiltersList_Record >;
		var count, i : Int32;
		m_spawnedCustomFilterIndex = 0;
		filtersList = ( ( WorldMapFiltersList_Record )( TweakDBInterface.GetWorldMapFiltersListRecord( T"WorldMap.WorldMapCustomFiltersList" ) ) );
		count = filtersList.GetListCount();
		m_customFiltersList.Resize( count );
		for( i = 0; i < count; i += 1 )
		{
			filterGroup = filtersList.GetListItem( i );
			AsyncSpawnFromLocal( inkVerticalPanelRef.Get( m_filtersList ), 'FiltersListItem', this, 'OnFilterListItemSpawned', filterGroup );
		}
	}

	private function UninitializeCustomFiltersList()
	{
		var filterWidget : weak< inkWidget >;
		var count, i : Int32;
		count = inkVerticalPanelRef.GetNumChildren( m_filtersList );
		for( i = 0; i < count; i += 1 )
		{
			filterWidget = inkVerticalPanelRef.GetWidgetByIndex( m_filtersList, i );
			filterWidget.UnregisterFromCallback( 'OnRelease', this, 'OnFilterSwitched' );
		}
		inkVerticalPanelRef.RemoveAllChildren( m_filtersList );
		m_customFiltersList.Clear();
	}

	protected event OnFilterListItemSpawned( filterWidget : inkWidget, userData : IScriptable )
	{
		var filterGroup : weak< MappinUIFilterGroup_Record >;
		var filterLogic : weak< WorldMapFiltersListItem >;
		filterGroup = ( ( MappinUIFilterGroup_Record )( userData ) );
		filterLogic = ( ( WorldMapFiltersListItem )( filterWidget.GetController() ) );
		filterLogic.SetFilterGroup( filterGroup );
		filterLogic.SetFilterState( 'Default' );
		filterLogic.EnableFilter( HasCustomFilter( filterLogic.GetFilterType() ) );
		filterWidget.RegisterToCallback( 'OnRelease', this, 'OnFilterSwitched' );
		m_customFiltersList[ m_spawnedCustomFilterIndex ] = filterLogic;
		m_spawnedCustomFilterIndex += 1;
	}

	protected event OnFilterSwitched( evt : inkPointerEvent )
	{
		var filterLogic : weak< WorldMapFiltersListItem >;
		if( evt.IsAction( 'click' ) && canChangeCustomFilter )
		{
			filterLogic = ( ( WorldMapFiltersListItem )( evt.GetTarget().GetController() ) );
			UpdateCustomFilter( filterLogic.GetFilterType(), filterLogic.SwitchFilter() );
		}
	}

	protected event OnCustomFilterChanged()
	{
		if( selectedMappin && !( selectedMappin.GetRootWidget().IsInteractive() ) )
		{
			SetSelectedMappin( NULL );
		}
	}

	protected event OnTrackedEntryChanges( hash : Uint32, className : CName, notifyOption : JournalNotifyOption, changeType : JournalChangeType )
	{
		UpdateTrackedQuest();
	}

	private function PlayCustomFiltersAnimations()
	{
		var i, filterListSize : Int32;
		var delay : Float;
		filterListSize = m_customFiltersList.Size();
		for( i = 0; i < filterListSize; i += 1 )
		{
			delay = ( ( Float )( i ) ) / m_customFiltersListAnimationDelay;
			m_customFiltersList[ i ].PlayIntroAnimation( delay );
		}
	}

	private function UpdateTrackedQuest()
	{
		var trackedPhase : weak< JournalQuestPhase >;
		var hasTrackedQuest : Bool;
		var isQuestType : Bool;
		var questType : gameJournalQuestType;
		m_mappinsPositions.Clear();
		if( IsFastTravelEnabled() || IsDelamainTaxiEnabled() )
		{
			return;
		}
		m_trackedObjective = ( ( JournalQuestObjectiveBase )( m_journalManager.GetTrackedEntry() ) );
		if( m_trackedObjective != NULL )
		{
			inkTextRef.SetText( m_objectiveName, m_trackedObjective.GetDescription() );
			m_mappinSystem.GetQuestMappinPositionsByObjective( ( ( Uint32 )( m_journalManager.GetEntryHash( m_trackedObjective ) ) ), m_mappinsPositions );
			trackedPhase = ( ( JournalQuestPhase )( m_journalManager.GetParentEntry( m_trackedObjective ) ) );
			if( trackedPhase != NULL )
			{
				m_trackedQuest = ( ( JournalQuest )( m_journalManager.GetParentEntry( trackedPhase ) ) );
				if( m_trackedQuest != NULL )
				{
					inkWidgetRef.SetVisible( m_questContainer, true );
					inkTextRef.SetText( m_questName, m_trackedQuest.GetTitle( m_journalManager ) );
					hasTrackedQuest = true;
					questType = m_journalManager.GetQuestType( m_trackedQuest );
					isQuestType = ( ( questType == gameJournalQuestType.MainQuest || questType == gameJournalQuestType.SideQuest ) || questType == gameJournalQuestType.CourierSideQuest ) || questType == gameJournalQuestType.MinorQuest;
					if( isQuestType )
					{
						inkTextRef.SetState( m_questName, 'Quest' );
						inkWidgetRef.SetState( m_objectiveFrame, 'Quest' );
					}
					else
					{
						inkTextRef.SetState( m_questName, 'Gigs' );
						inkWidgetRef.SetState( m_objectiveFrame, 'Gigs' );
					}
				}
			}
		}
		inkWidgetRef.SetVisible( m_questContainer, hasTrackedQuest );
	}

	protected event OnSetUserData( userData : IScriptable )
	{
		m_initMappinFocus = ( ( MapMenuUserData )( userData ) );
	}

	protected event OnRemovePreloader( widget : weak< inkWidget > )
	{
		GetRootCompoundWidget().RemoveChild( widget );
		m_readyToZoom = true;
		inkWidgetRef.SetVisible( m_locationAndGangsContainer, true );
	}

	protected event OnShowSpinner()
	{
		var preloaderController : weak< WorldMapPreloader >;
		preloaderController = ( ( WorldMapPreloader )( inkWidgetRef.GetController( m_preloaderWidget ) ) );
		preloaderController.ShowSpinner();
	}

	protected event OnEntityAttached()
	{
		var fastTravelEnabled : Bool;
		var delamainTaxiEnabled : Bool;
		var mappinSpawnContainer : weak< inkCompoundWidget >;
		var delayEvent : MapNavigationDelay;
		var preloaderController : weak< WorldMapPreloader >;
		mappinSpawnContainer = GetSpawnContainer();
		mappinSpawnContainer.RegisterToCallback( 'OnEnter', this, 'OnHoverOverMappin' );
		mappinSpawnContainer.RegisterToCallback( 'OnLeave', this, 'OnHoverOutMappin' );
		RegisterToGlobalInputCallback( 'OnPostOnAxis', this, 'OnAxisInput' );
		RegisterToGlobalInputCallback( 'OnPostOnPress', this, 'OnPressInput' );
		RegisterToGlobalInputCallback( 'OnPostOnRelease', this, 'OnReleaseInput' );
		RegisterToGlobalInputCallback( 'OnPostOnHold', this, 'OnHoldInput' );
		m_cameraMode = GetEntityPreview().GetCameraMode();
		fastTravelEnabled = IsFastTravelEnabled();
		UpdateFastTravelVisiblity( fastTravelEnabled );
		if( fastTravelEnabled )
		{
			SetQuickFilter( gamedataWorldMapFilter.FastTravel );
		}
		delamainTaxiEnabled = IsDelamainTaxiEnabled();
		UpdateDelamainTaxiVisiblity( delamainTaxiEnabled );
		if( m_initMappinFocus )
		{
			delayEvent = new MapNavigationDelay;
			QueueEvent( delayEvent );
		}
		m_mapBlackboard.SetString( m_mapDefinition.currentState, "EntityAttached" );
		preloaderController = ( ( WorldMapPreloader )( inkWidgetRef.GetController( m_preloaderWidget ) ) );
		preloaderController.SetMapLoaded();
		RefreshInputHints();
		m_entityAttached = true;
	}

	protected event OnMapNavigationDelay( evt : MapNavigationDelay )
	{
		if( m_initMappinFocus.m_isTracked )
		{
			FrameMappinPath( ( ( Uint32 )( m_initMappinFocus.m_hash ) ), 1.0, inkMargin( 200.0, 200.0, 200.0, 200.0 ) );
		}
		else
		{
			GetEntityPreview().MoveTo( m_initMappinFocus.m_moveTo );
		}
	}

	protected event OnEntityDetached()
	{
		var mappinSpawnContainer : weak< inkCompoundWidget >;
		mappinSpawnContainer = GetSpawnContainer();
		if( mappinSpawnContainer )
		{
			mappinSpawnContainer.UnregisterFromCallback( 'OnEnter', this, 'OnHoverOverMappin' );
			mappinSpawnContainer.UnregisterFromCallback( 'OnLeave', this, 'OnHoverOutMappin' );
		}
		UnregisterFromGlobalInputCallback( 'OnPostOnAxis', this, 'OnAxisInput' );
		UnregisterFromGlobalInputCallback( 'OnPostOnPress', this, 'OnPressInput' );
		UnregisterFromGlobalInputCallback( 'OnPostOnHold', this, 'OnHoldInput' );
		UnregisterFromGlobalInputCallback( 'OnPostOnRelease', this, 'OnReleaseInput' );
	}

	protected event OnZoomLevelChanged( oldLevel : Int32, newLevel : Int32 )
	{
		if( selectedMappin && !( selectedMappin.GetRootWidget().IsInteractive() ) )
		{
			SetSelectedMappin( NULL );
		}
	}

	protected event OnZoomTransitionFinished()
	{
		m_isZooming = false;
		UpdateSelectedMappinTooltip();
	}

	protected event OnZoomToMappinEnabledChanged( flag : Bool )
	{
		UpdateSelectedMappinTooltip();
	}

	protected event OnCanChangeCustomFilterChanged( flag : Bool )
	{
		if( flag )
		{
			inkTextRef.SetVisible( m_filterText, true );
			inkWidgetRef.SetVisible( m_customFilters, true );
			PlayCustomFiltersAnimations();
		}
		else
		{
			inkTextRef.SetVisible( m_filterText, false );
			inkWidgetRef.SetVisible( m_customFilters, false );
		}
	}

	protected event OnSelectedMappinChanged( oldController : BaseWorldMapMappinController, newController : BaseWorldMapMappinController )
	{
		if( oldController )
		{
			oldController.UnselectMappin();
			HideMappinTooltip( oldController );
		}
		if( newController )
		{
			newController.SelectMappin();
			SetMappinVisited( newController );
			ShowMappinTooltip( newController );
		}
		RefreshInputHints();
	}

	protected event OnSetZoomLevelEvent( eventData : SetZoomLevelEvent )
	{
		FTLog( "OnSetZoomLevelEvent:" + IntToString( eventData.m_value ) );
		GetEntityPreview().JumpToZoomLevel( eventData.m_value );
	}

	protected event OnHoverOverMappin( e : inkPointerEvent )
	{
		var hoveredController : BaseWorldMapMappinController;
		hoveredController = ( ( BaseWorldMapMappinController )( e.GetTarget().GetController() ) );
		if( hoveredController && hoveredController.CanSelectMappin() )
		{
			SetSelectedMappin( hoveredController );
		}
	}

	protected event OnHoverOutMappin( e : inkPointerEvent )
	{
		SetSelectedMappin( NULL );
	}

	private function GetDistrictAnimation( view : gameuiEWorldMapDistrictView, show : Bool ) : CName
	{
		switch( view )
		{
			case gameuiEWorldMapDistrictView.Districts:
				return ( ( show ) ? ( 'OnShowDistricts' ) : ( 'OnHideDistricts' ) );
			case gameuiEWorldMapDistrictView.SubDistricts:
				return ( ( show ) ? ( 'OnShowSubDistricts' ) : ( 'OnHideSubDistricts' ) );
			default:
				return '';
		}
	}

	protected event OnDistrictViewChanged( oldView : gameuiEWorldMapDistrictView, newView : gameuiEWorldMapDistrictView )
	{
		if( oldView != gameuiEWorldMapDistrictView.None )
		{
			PlayLibraryAnimation( GetDistrictAnimation( oldView, false ) );
		}
		if( newView != gameuiEWorldMapDistrictView.None )
		{
			PlayLibraryAnimation( GetDistrictAnimation( newView, true ) );
		}
	}

	protected event OnUpdateHoveredDistricts( district : gamedataDistrict, subdistrict : gamedataDistrict )
	{
		var districtRecord, subdistrictRecord : weak< District_Record >;
		m_previousHoveredDistrict = m_currentHoveredDistrict;
		m_currentHoveredDistrict = district;
		districtRecord = MappinUtils.GetDistrictRecord( district );
		subdistrictRecord = MappinUtils.GetDistrictRecord( subdistrict );
		if( district == gamedataDistrict.Dogtown )
		{
			inkTextRef.SetLocalizedTextString( m_districtNameText, "LocKey#10946" );
		}
		else
		{
			inkTextRef.SetLocalizedTextString( m_districtNameText, ( ( districtRecord ) ? ( districtRecord.LocalizedName() ) : ( "LocKey#10951" ) ) );
		}
		if( district == gamedataDistrict.Invalid )
		{
			inkWidgetRef.SetVisible( m_districtIconImageContainer, false );
		}
		else
		{
			inkWidgetRef.SetVisible( m_districtIconImageContainer, true );
			inkImageRef.SetTexturePart( m_districtIconImage, districtRecord.UiIcon() );
		}
		inkTextRef.SetLocalizedTextString( m_subdistrictNameText, ( ( subdistrictRecord ) ? ( subdistrictRecord.LocalizedName() ) : ( "LocKey#10951" ) ) );
		inkTextRef.SetVisible( m_subdistrictNameText, ( subdistrictRecord != NULL ) && subdistrictRecord.LocalizedName() != "" );
		ShowGangsInfo( district, subdistrict );
	}

	protected event OnSetMenuEventDispatcher( menuEventDispatcher : weak< inkMenuEventDispatcher > )
	{
		m_menuEventDispatcher = menuEventDispatcher;
		m_menuEventDispatcher.RegisterToEvent( 'OnBack', this, 'OnBack' );
	}

	protected event OnBack( userData : IScriptable )
	{
		var evt : BackActionCallback;
		var request : CancelDelamainRideRequest;
		request = new CancelDelamainRideRequest;
		PlaySound( 'Button', 'OnPress' );
		if( IsDelamainTaxiEnabled() && !( m_pressedRMB ) )
		{
			m_menuEventDispatcher.SpawnEvent( 'OnCancel' );
			request.forceExit = true;
			GetDelamainTaxiSystem().QueueRequest( request );
			UntrackDelamainTaxiMappin();
		}
		else if( !( StatusEffectSystem.ObjectHasStatusEffectWithTag( GetPlayerControlledObject(), 'LockInHubMenu' ) ) && !( m_pressedRMB ) )
		{
			evt = new BackActionCallback;
			QueueEvent( evt );
		}
		m_pressedRMB = false;
	}

	private function CycleQuickFilterPrev()
	{
		CycleWorldMapFilter( false );
		PlaySound( 'Button', 'OnPress' );
	}

	private function CycleQuickFilterNext()
	{
		CycleWorldMapFilter( true );
		PlaySound( 'Button', 'OnPress' );
	}

	private function UpdateFastTravelVisiblity( fastTravelEnabled : Bool )
	{
		inkWidgetRef.SetVisible( m_fastTravelInstructions, fastTravelEnabled );
		inkWidgetRef.SetVisible( m_topShadow, !( fastTravelEnabled ) );
		inkWidgetRef.SetVisible( m_openInJournalButton, !( fastTravelEnabled ) );
	}

	private function UpdateDelamainTaxiVisiblity( delamainTaxiEnabled : Bool )
	{
		inkWidgetRef.SetVisible( m_delamainTaxiInstructions, delamainTaxiEnabled );
		inkWidgetRef.SetVisible( m_topShadow, !( delamainTaxiEnabled ) );
		inkWidgetRef.SetVisible( m_openInJournalButton, !( delamainTaxiEnabled ) );
	}

	private function NavigateCustomFilters( option : ECustomFilterDPadNavigationOption )
	{
		var filtersAmount : Int32;
		if( m_customFiltersList[ m_currentCustomFilterIndex ].IsFilterEnabled() )
		{
			m_customFiltersList[ m_currentCustomFilterIndex ].SetFilterState( 'Selected' );
		}
		else
		{
			m_customFiltersList[ m_currentCustomFilterIndex ].SetFilterState( 'Default' );
		}
		filtersAmount = m_customFiltersList.Size();
		switch( option )
		{
			case ECustomFilterDPadNavigationOption.SelectNext:
				m_currentCustomFilterIndex = ( ( m_currentCustomFilterIndex < ( filtersAmount - 1 ) ) ? ( m_currentCustomFilterIndex + 1 ) : ( 0 ) );
			break;
			case ECustomFilterDPadNavigationOption.SelectPrev:
				m_currentCustomFilterIndex = ( ( m_currentCustomFilterIndex > 0 ) ? ( m_currentCustomFilterIndex - 1 ) : ( filtersAmount - 1 ) );
			break;
			case ECustomFilterDPadNavigationOption.Toggle:
				UpdateCustomFilter( m_customFiltersList[ m_currentCustomFilterIndex ].GetFilterType(), m_customFiltersList[ m_currentCustomFilterIndex ].SwitchFilter() );
			break;
		}
		m_customFiltersList[ m_currentCustomFilterIndex ].SetFilterState( 'Hover' );
	}

	private function CycleWorldMapFilter( cycleNext : Bool )
	{
		var filterGroup : weak< MappinUIFilterGroup_Record >;
		var filtersList : weak< WorldMapFiltersList_Record >;
		var count : Int32;
		filtersList = ( ( WorldMapFiltersList_Record )( TweakDBInterface.GetWorldMapFiltersListRecord( T"WorldMap.WorldMapQuickFiltersList" ) ) );
		count = filtersList.GetListCount();
		m_currentQuickFilterIndex = m_currentQuickFilterIndex + ( ( cycleNext ) ? ( 1 ) : ( -1 ) );
		if( m_currentQuickFilterIndex >= count )
		{
			m_currentQuickFilterIndex = 0;
		}
		else if( m_currentQuickFilterIndex < 0 )
		{
			m_currentQuickFilterIndex = count - 1;
		}
		m_currentCustomFilterIndex = -1;
		filterGroup = filtersList.GetListItem( m_currentQuickFilterIndex );
		SetQuickFilterIndicator( m_currentQuickFilterIndex );
		SetQuickFilterFromRecord( filterGroup );
	}

	private function SetQuickFilterIndicator( index : Int32 )
	{
		var i, arraySize : Int32;
		var animOptions : inkAnimOptions;
		animOptions.loopType = inkanimLoopType.Cycle;
		animOptions.loopInfinite = true;
		arraySize = m_quickFilterIndicators.Size();
		for( i = 0; i < arraySize; i += 1 )
		{
			inkWidgetRef.SetState( m_quickFilterIndicators[ i ], 'Default' );
		}
		inkWidgetRef.SetState( m_quickFilterIndicators[ index ], 'Selected' );
		if( m_currentQuickFilterIndex > 0 )
		{
			if( m_animationProxy && m_animationProxy.IsPlaying() )
			{
				m_animationProxy.Stop();
			}
			m_animationProxy = PlayLibraryAnimation( 'OnFilterWarning', animOptions );
		}
	}

	private function ToggleQuickFilterIndicatorsVsibility( toggle : Bool )
	{
		var i, arraySize : Int32;
		arraySize = m_quickFilterIndicators.Size();
		for( i = 0; i < arraySize; i += 1 )
		{
			inkWidgetRef.SetVisible( m_quickFilterIndicators[ i ], toggle );
		}
	}

	private function OpenSelectedQuest()
	{
		var mappin : weak< IMappin >;
		var journalEntry : weak< JournalEntry >;
		if( HasSelectedMappin() )
		{
			mappin = selectedMappin.GetMappin();
			if( CanOpenJournalForMappin( mappin ) )
			{
				journalEntry = GetMappinJournalEntry( mappin );
				OpenQuestInJournal( journalEntry );
				return;
			}
			journalEntry = GetCodexEntryForMappin( mappin );
			if( journalEntry != NULL )
			{
				OpenCodexPopup( journalEntry );
				return;
			}
		}
	}

	private function CanOpenCodexPopup( mappin : weak< IMappin > ) : Bool
	{
		return GetCodexEntryForMappin( mappin ) != NULL;
	}

	private function GetCodexEntryForMappin( mappin : weak< IMappin > ) : weak< JournalEntry >
	{
		var poiMapPin : PointOfInterestMappin;
		var slotName : String;
		poiMapPin = ( ( PointOfInterestMappin )( mappin ) );
		if( poiMapPin == NULL )
		{
			return NULL;
		}
		slotName = NameToString( poiMapPin.GetSlotName() );
		return m_journalManager.GetEntryByString( "codex/glossary/vehicles/" + slotName, "gameJournalCodexEntry" );
	}

	private function OpenCodexPopup( jurnalEntry : weak< JournalEntry > )
	{
		var evt : OpenCodexPopupEvent;
		evt = new OpenCodexPopupEvent;
		evt.m_entry = jurnalEntry;
		QueueBroadcastEvent( evt );
	}

	private function OpenTrackedQuest()
	{
		if( m_trackedQuest != NULL )
		{
			OpenQuestInJournal( m_trackedQuest );
		}
	}

	private function OpenQuestInJournal( questEntry : weak< JournalEntry > )
	{
		var userData : MessageMenuAttachmentData;
		var evt : OpenMenuRequest;
		userData = new MessageMenuAttachmentData;
		userData.m_entryHash = m_journalManager.GetEntryHash( questEntry );
		evt = new OpenMenuRequest;
		evt.m_menuName = 'quest_log';
		evt.m_eventData.userData = userData;
		evt.m_eventData.m_overrideDefaultUserData = true;
		evt.m_isMainMenu = true;
		QueueBroadcastEvent( evt );
		m_justOpenedQuestJournal = true;
	}

	private function UpdateCustomFilter( filter : gamedataWorldMapFilter, enable : Bool )
	{
		if( enable )
		{
			SetCustomFilter( filter );
			m_audioSystem.Play( 'ui_menu_value_up' );
			PlayRumble( RumbleStrength.SuperLight, RumbleType.Fast, RumblePosition.Left );
		}
		else
		{
			ClearCustomFilter( filter );
			m_audioSystem.Play( 'ui_menu_value_down' );
			PlayRumble( RumbleStrength.SuperLight, RumbleType.Pulse, RumblePosition.Left );
		}
	}

	private function SetMappinIconsVisible( visible : Bool )
	{
		var mappinSpawnContainer : weak< inkCompoundWidget >;
		mappinSpawnContainer = GetSpawnContainer();
		mappinSpawnContainer.SetVisible( visible );
	}

	private function UpdateGameTime()
	{
		GameTimeUtils.UpdateGameTimeText( GameInstance.GetTimeSystem( ( ( GameObject )( GetOwnerEntity() ) ).GetGame() ), m_gameTimeText, m_gameTimeTextParams );
	}

	private function TryFastTravel()
	{
		if( HasSelectedMappin() && ( selectedMappin.GetMappinVariant() == gamedataMappinVariant.FastTravelVariant || selectedMappin.GetMappinVariant() == gamedataMappinVariant.Zzz17_NCARTVariant ) )
		{
			FastTravel();
			m_audioSystem.Play( 'ui_menu_item_crafting_done' );
			PlayRumble( RumbleStrength.SuperLight, RumbleType.Slow, RumblePosition.Right );
		}
	}

	private function TryConfirmDelamainTaxi() : Bool
	{
		if( HasSelectedDelamainTaxiMappin() )
		{
			return CanPay();
		}
		return false;
	}

	private function PrepFastTravel()
	{
		var player : GameObject;
		var request : FastTravelPrefetchRequest;
		var pointData : FastTravelPointData;
		var mappin : FastTravelMappin;
		if( !( IsFastTravelEnabled() ) )
		{
			return;
		}
		mappin = ( ( FastTravelMappin )( selectedMappin.GetMappin() ) );
		player = GameInstance.GetPlayerSystem( GetOwner().GetGame() ).GetLocalPlayerMainGameObject();
		if( player == NULL )
		{
			return;
		}
		pointData = mappin.GetPointData();
		request = new FastTravelPrefetchRequest;
		request.destinationRef = pointData.GetMarkerRef();
		GetFastTravelSystem().QueueRequest( request );
		SetFactValue( GetOwner().GetGame(), 'ue_metro_ft_system_prefetch_click', 1 );
	}

	private function TryTrackQuestOrSetWaypoint()
	{
		if( IsFastTravelEnabled() )
		{
			return;
		}
		if( IsDelamainTaxiEnabled() )
		{
			TrackDelamainTaxiMappin();
			UpdateTravelDestination();
			UpdateSelectedMappinTooltip();
		}
		else if( selectedMappin != NULL )
		{
			if( selectedMappin.IsDelamainTaxiTracked() )
			{
				return;
			}
			if( ( selectedMappin.IsInCollection() && selectedMappin.IsCollection() ) || !( selectedMappin.IsInCollection() ) )
			{
				if( CanQuestTrackMappin( selectedMappin ) )
				{
					if( !( IsMappinQuestTracked( selectedMappin ) ) )
					{
						UntrackCustomPositionMappin();
						TrackQuestMappin( selectedMappin );
						PlaySound( 'MapPin', 'OnEnable' );
						PlayRumble( RumbleStrength.SuperLight, RumbleType.Slow, RumblePosition.Right );
					}
				}
				else if( CanPlayerTrackMappin( selectedMappin ) )
				{
					if( selectedMappin.IsCustomPositionTracked() )
					{
						UntrackCustomPositionMappin();
						SetSelectedMappin( NULL );
						PlaySound( 'MapPin', 'OnDisable' );
						PlayRumble( RumbleStrength.SuperLight, RumbleType.Pulse, RumblePosition.Right );
					}
					else if( selectedMappin.IsPlayerTracked() && selectedMappin.IsDelamainTaxiTracked() )
					{
						UntrackMappin();
						PlaySound( 'MapPin', 'OnDisable' );
						PlayRumble( RumbleStrength.SuperLight, RumbleType.Pulse, RumblePosition.Right );
					}
					else
					{
						UntrackCustomPositionMappin();
						TrackMappin( selectedMappin );
						PlaySound( 'MapPin', 'OnEnable' );
						PlayRumble( RumbleStrength.SuperLight, RumbleType.Slow, RumblePosition.Right );
					}
				}
				UpdateSelectedMappinTooltip();
			}
		}
		else
		{
			TrackCustomPositionMappin();
		}
		PlaySound( 'MapPin', 'OnCreate' );
	}

	private function TrackQuestMappin( controller : BaseMappinBaseController )
	{
		var journalEntry : JournalEntry;
		if( controller == NULL )
		{
			return;
		}
		journalEntry = GetMappinJournalEntry( controller.GetMappin() );
		if( journalEntry == NULL )
		{
			return;
		}
		m_journalManager.TrackEntry( journalEntry );
	}

	private function UpdateTravelDestination()
	{
		var request : SetTravelDestinationRequest;
		request = new SetTravelDestinationRequest;
		request.mappinID = delamainTaxiMappinID;
		request.cost = GetTravelCost();
		GetDelamainTaxiSystem().QueueRequest( request );
	}

	private function GetTravelCost() : Int32
	{
		return CeilF( GetTravelDistance() / 500.0 ) * 50;
	}

	private function FastTravel()
	{
		var player : GameObject;
		var mappin : FastTravelMappin;
		var request : PerformFastTravelRequest;
		var nextLoadingTypeEvt : inkSetNextLoadingScreenEvent;
		if( !( IsFastTravelEnabled() ) )
		{
			return;
		}
		mappin = ( ( FastTravelMappin )( selectedMappin.GetMappin() ) );
		player = GameInstance.GetPlayerSystem( GetOwner().GetGame() ).GetLocalPlayerMainGameObject();
		if( player == NULL )
		{
			return;
		}
		request = new PerformFastTravelRequest;
		request.pointData = mappin.GetPointData();
		request.player = player;
		GetFastTravelSystem().QueueRequest( request );
		nextLoadingTypeEvt = new inkSetNextLoadingScreenEvent;
		nextLoadingTypeEvt.SetNextLoadingScreenType( inkLoadingScreenType.FastTravel );
		QueueBroadcastEvent( nextLoadingTypeEvt );
		m_menuEventDispatcher.SpawnEvent( 'OnBack' );
	}

	private function DEBUG_Teleport()
	{
		var player : GameObject;
		if( !( CanDebugTeleport() ) )
		{
			return;
		}
		if( selectedMappin != NULL )
		{
			player = GameInstance.GetPlayerSystem( GetOwner().GetGame() ).GetLocalPlayerMainGameObject();
			GameInstance.GetTeleportationFacility( GetOwner().GetGame() ).Teleport( player, selectedMappin.GetMappin().GetWorldPosition(), Vector4.ToRotation( player.GetWorldForward() ) );
			m_menuEventDispatcher.SpawnEvent( 'OnCloseHubMenu' );
		}
	}

	private function HandleAxisInput( e : inkPointerEvent )
	{
		var entityPreview : weak< inkWorldMapPreviewGameController >;
		var amount : Float;
		entityPreview = GetEntityPreview();
		amount = e.GetAxisData();
		if( e.IsAction( 'world_map_menu_move_horizontal' ) )
		{
			entityPreview.Move( Vector4( 1.0, 0.0, 0.0, 0.0 ), amount );
		}
		else if( e.IsAction( 'world_map_menu_move_horizontal_alt' ) )
		{
			entityPreview.Move( Vector4( 1.0, 0.0, 0.0, 0.0 ), amount );
		}
		else if( e.IsAction( 'world_map_menu_move_vertical' ) )
		{
			entityPreview.Move( Vector4( 0.0, 1.0, 0.0, 0.0 ), amount );
		}
		else if( e.IsAction( 'world_map_menu_move_vertical_alt' ) )
		{
			entityPreview.Move( Vector4( 0.0, 1.0, 0.0, 0.0 ), amount );
		}
		else if( e.IsAction( 'left_trigger' ) )
		{
			if( amount == 0.0 )
			{
				if( m_isZooming )
				{
					m_audioSystem.Play( 'ui_menu_scrolling_stop' );
					m_isZooming = false;
				}
				return;
			}
			if( !( m_isZooming ) && ( amount > 0.0 ) )
			{
				m_audioSystem.Play( 'ui_menu_scrolling_start' );
				m_isZooming = true;
			}
			entityPreview.ZoomOut( amount );
		}
		else if( e.IsAction( 'right_trigger' ) )
		{
			if( amount == 0.0 )
			{
				if( m_isZooming )
				{
					m_audioSystem.Play( 'ui_menu_scrolling_stop' );
					m_isZooming = false;
				}
				return;
			}
			if( !( m_isZooming ) && ( amount > 0.0 ) )
			{
				m_audioSystem.Play( 'ui_menu_scrolling_start' );
				m_isZooming = true;
			}
			entityPreview.ZoomIn( amount );
		}
	}

	private function HandlePressInput( e : inkPointerEvent )
	{
		if( e.IsAction( 'world_map_menu_track_waypoint' ) )
		{
			m_pressedRMB = true;
			TryTrackQuestOrSetWaypoint();
		}
		else if( e.IsAction( 'world_map_menu_jump_to_player' ) )
		{
			if( !( m_justOpenedQuestJournal ) )
			{
				PlaySound( 'Button', 'OnPress' );
				if( ( ( WorldMapPlayerMappinController )( selectedMappin ) ) == NULL )
				{
					MoveToPlayer();
				}
				else if( m_mappinsPositions.Size() > 0 )
				{
					GetEntityPreview().MoveTo( m_mappinsPositions[ 0 ] );
				}
			}
		}
		else if( e.IsAction( 'world_map_menu_zoom_to_mappin' ) )
		{
			if( HasSelectedMappin() && CanZoomToMappin( selectedMappin ) )
			{
				PlaySound( 'Button', 'OnPress' );
				ZoomToMappin( selectedMappin );
			}
		}
		else if( e.IsAction( 'world_map_menu_zoom_in_mouse' ) )
		{
			ZoomWithMouse( true );
			if( !( m_isZooming ) )
			{
				m_audioSystem.Play( 'ui_zooming_in_step_change' );
				m_isZooming = true;
			}
		}
		else if( e.IsAction( 'world_map_menu_zoom_out_mouse' ) )
		{
			ZoomWithMouse( false );
			if( !( m_isZooming ) )
			{
				m_audioSystem.Play( 'ui_zooming_in_exit' );
				m_isZooming = true;
			}
		}
		else if( ( ( e.IsAction( 'world_map_menu_fast_travel' ) && HasSelectedMappin() ) && ( selectedMappin.GetMappinVariant() == gamedataMappinVariant.FastTravelVariant || selectedMappin.GetMappinVariant() == gamedataMappinVariant.Zzz17_NCARTVariant ) ) && IsFastTravelEnabled() )
		{
			m_audioSystem.Play( 'ui_menu_item_crafting_start' );
			PrepFastTravel();
			SetFactValue( GetOwner().GetGame(), 'ue_metro_map_ui_ft_clicked', 1 );
			m_startedFastTraveling = true;
			m_isPanning = true;
		}
		if( ( e.IsAction( 'world_map_menu_move_mouse' ) && !( m_isHoveringOverFilters ) ) && !( m_isPanning ) )
		{
			SetMousePanEnabled( true );
			SetCursorContext( 'Pan' );
			m_audioSystem.Play( 'ui_menu_scrolling_start' );
			m_isPanning = true;
		}
	}

	private function HandleReleaseInput( e : inkPointerEvent )
	{
		if( inkWidgetRef.IsVisible( m_customFilters ) )
		{
			if( e.IsAction( 'world_map_filter_navigation_down' ) )
			{
				NavigateCustomFilters( ECustomFilterDPadNavigationOption.SelectNext );
				PlaySound( 'Button', 'OnHover' );
			}
			else if( e.IsAction( 'world_map_filter_navigation_up' ) )
			{
				NavigateCustomFilters( ECustomFilterDPadNavigationOption.SelectPrev );
				PlaySound( 'Button', 'OnHover' );
			}
			else if( e.IsAction( 'world_map_menu_toggle_custom_filter' ) )
			{
				NavigateCustomFilters( ECustomFilterDPadNavigationOption.Toggle );
			}
		}
		if( m_isPanning )
		{
			SetCursorContext( 'Default' );
			SetMousePanEnabled( false );
			m_audioSystem.Play( 'ui_menu_scrolling_stop' );
			m_isPanning = false;
		}
		if( e.IsAction( 'world_map_menu_cycle_filter_prev' ) )
		{
			if( canChangeCustomFilter )
			{
				CycleQuickFilterPrev();
			}
		}
		else if( e.IsAction( 'world_map_menu_cycle_filter_next' ) )
		{
			if( canChangeCustomFilter )
			{
				CycleQuickFilterNext();
			}
		}
		else if( HasSelectedMappin() && ( e.IsAction( 'world_map_menu_open_quest' ) || e.IsAction( 'open_map_link' ) ) )
		{
			if( !( e.IsHandled() ) || !( e.IsConsumed() ) )
			{
				e.Handle();
				e.Consume();
				PlaySound( 'Button', 'OnPress' );
				OpenSelectedQuest();
			}
		}
		else if( ( e.IsAction( 'toggle_journal' ) || e.IsAction( 'world_map_menu_open_quest_static' ) ) || e.IsAction( 'open_map_link' ) )
		{
			if( !( e.IsHandled() ) || !( e.IsConsumed() ) )
			{
				e.Handle();
				e.Consume();
				PlaySound( 'Button', 'OnPress' );
				OpenTrackedQuest();
			}
		}
		else if( e.IsAction( 'world_map_menu_fast_travel' ) && IsFastTravelEnabled() )
		{
			if( m_startedFastTraveling )
			{
				m_audioSystem.Play( 'ui_menu_item_crafting_fail' );
			}
			m_startedFastTraveling = false;
		}
	}

	private function HandleHoldInput( e : inkPointerEvent )
	{
		var holdProgress : Float;
		var request : StartDelamainTaxiRequest;
		if( e.IsAction( 'world_map_menu_fast_travel' ) )
		{
			holdProgress = e.GetHoldProgress();
			if( holdProgress < 1.0 )
			{
				return;
			}
			TryFastTravel();
		}
		else if( e.IsAction( 'world_map_menu_confirm_delamain_taxi' ) )
		{
			holdProgress = e.GetHoldProgress();
			if( holdProgress < 1.0 )
			{
				return;
			}
			if( IsDelamainTaxiEnabled() && TryConfirmDelamainTaxi() )
			{
				request = new StartDelamainTaxiRequest;
				request.m_price = GetTravelCost();
				GetDelamainTaxiSystem().QueueRequest( request );
				m_menuEventDispatcher.SpawnEvent( 'OnConfirm' );
				ConfirmDelamainTaxiMappinPosition();
			}
			else
			{
				m_tooltipController.PlayPaymentErrorAnimation();
				PlaySound( 'Attributes', 'OnFail' );
			}
		}
	}

	protected event OnPressInput( e : inkPointerEvent )
	{
		if( m_readyToZoom )
		{
			HandlePressInput( e );
		}
	}

	protected event OnReleaseInput( e : inkPointerEvent )
	{
		if( m_readyToZoom )
		{
			HandleReleaseInput( e );
		}
	}

	protected event OnHoldInput( e : inkPointerEvent )
	{
		if( m_readyToZoom )
		{
			HandleHoldInput( e );
		}
	}

	protected event OnAxisInput( e : inkPointerEvent )
	{
		if( m_readyToZoom )
		{
			HandleAxisInput( e );
		}
	}

	private function IsPoliceTooltip( mappinVariant : gamedataMappinVariant ) : Bool
	{
		switch( mappinVariant )
		{
			case gamedataMappinVariant.GangWatchVariant:
			case gamedataMappinVariant.OutpostVariant:
			case gamedataMappinVariant.ResourceVariant:
			case gamedataMappinVariant.HiddenStashVariant:
			case gamedataMappinVariant.SmugglersDenVariant:
			case gamedataMappinVariant.FailedCrossingVariant:
				return true;
		}
		return false;
	}

	private function ShouldDisplayInHud( mappinVariant : gamedataMappinVariant ) : Bool
	{
		return IsPoliceTooltip( mappinVariant );
	}

	private function GetTooltipType( mappinVariant : gamedataMappinVariant ) : WorldMapTooltipType
	{
		if( IsPoliceTooltip( mappinVariant ) )
		{
			return WorldMapTooltipType.Police;
		}
		return WorldMapTooltipType.Default;
	}

	private function ShowMappinTooltip( controller : weak< BaseWorldMapMappinController > )
	{
		var mappinVariant : gamedataMappinVariant;
		var tooltipType : WorldMapTooltipType;
		if( controller != NULL )
		{
			mappinVariant = controller.GetMappinVariant();
			tooltipType = GetTooltipType( mappinVariant );
			UpdateTooltip( tooltipType, controller );
			m_tooltipController.Show( tooltipType );
		}
	}

	private function HideMappinTooltip( controller : weak< BaseWorldMapMappinController > )
	{
		var mappinVariant : gamedataMappinVariant;
		var tooltipType : WorldMapTooltipType;
		if( controller != NULL )
		{
			mappinVariant = controller.GetMappinVariant();
			tooltipType = GetTooltipType( mappinVariant );
			m_tooltipController.Hide( tooltipType );
		}
	}

	private function ShowGangsInfo( district : gamedataDistrict, sub : gamedataDistrict )
	{
		var subRecord, districtRecord : weak< District_Record >;
		var gangsRecords : array< weak< Affiliation_Record > >;
		var gangRecord : weak< Affiliation_Record >;
		var asyncSpawnRequest : weak< inkAsyncSpawnRequest >;
		var i, subTotalGangs, totalGangs : Int32;
		subRecord = MappinUtils.GetDistrictRecord( sub );
		districtRecord = MappinUtils.GetDistrictRecord( district );
		subTotalGangs = subRecord.GetGangsCount();
		totalGangs = districtRecord.GetGangsCount();
		if( subTotalGangs > 0 )
		{
			districtRecord = subRecord;
			totalGangs = subTotalGangs;
		}
		else if( !( m_showedSubdistrictGangs ) && m_previousHoveredDistrict == m_currentHoveredDistrict )
		{
			return;
		}
		m_showedSubdistrictGangs = subTotalGangs > 0;
		ClearAllAsyncSpawnRequests();
		inkWidgetRef.SetVisible( m_gangsInfoContainer, false );
		inkCompoundRef.RemoveAllChildren( m_gangsList );
		if( totalGangs > 0 )
		{
			inkWidgetRef.SetVisible( m_gangsInfoContainer, true );
			districtRecord.Gangs( gangsRecords );
			for( i = 0; i < totalGangs; i += 1 )
			{
				gangRecord = gangsRecords[ i ];
				asyncSpawnRequest = AsyncSpawnFromLocal( inkCompoundRef.Get( m_gangsList ), 'GangListItem', this, 'OnGangListItemSpawned', gangRecord );
				m_gangsAsyncSpawnRequests.PushBack( asyncSpawnRequest );
			}
		}
	}

	private function ClearAllAsyncSpawnRequests()
	{
		var i : Int32;
		for( i = 0; i < m_gangsAsyncSpawnRequests.Size(); i += 1 )
		{
			m_gangsAsyncSpawnRequests[ i ].Cancel();
			m_gangsAsyncSpawnRequests[ i ] = NULL;
		}
		m_gangsAsyncSpawnRequests.Clear();
	}

	protected event OnGangListItemSpawned( gangWidget : inkWidget, userData : IScriptable )
	{
		var gangRecord : weak< Affiliation_Record >;
		var gangController : weak< WorldMapGangItemController >;
		gangRecord = ( ( Affiliation_Record )( userData ) );
		gangController = ( ( WorldMapGangItemController )( gangWidget.GetController() ) );
		gangController.SetData( gangRecord );
	}

	private function HideAllTooltips()
	{
		m_tooltipController.HideAll();
	}

	private function UpdateTooltip( tooltipType : WorldMapTooltipType, controller : weak< BaseWorldMapMappinController > )
	{
		var toolTipData : WorldMapTooltipData;
		var transactionSystem : TransactionSystem;
		if( controller != NULL )
		{
			toolTipData.controller = controller;
			toolTipData.mappin = controller.GetMappin();
			toolTipData.journalEntry = GetMappinJournalEntry( toolTipData.mappin );
			toolTipData.readJournal = CanOpenJournalForMappin( toolTipData.mappin );
			toolTipData.moreInfo = CanOpenCodexPopup( toolTipData.mappin );
			toolTipData.isCollection = controller.IsCollection();
		}
		toolTipData.fastTravelEnabled = IsFastTravelEnabled();
		if( IsDelamainTaxiEnabled() )
		{
			toolTipData.delamainTaxiEnabled = true;
			toolTipData.travelCost = GetTravelCost();
			transactionSystem = GameInstance.GetTransactionSystem( m_player.GetGame() );
			toolTipData.playerMoney = transactionSystem.GetItemQuantity( m_player, MarketSystem.Money() );
		}
		m_tooltipController.SetData( tooltipType, toolTipData, this );
	}

	private function UpdateSelectedMappinTooltip()
	{
		if( selectedMappin )
		{
			UpdateTooltip( GetTooltipType( selectedMappin.GetMappinVariant() ), selectedMappin );
		}
	}

	private function CanOpenJournalForMappin( mappin : weak< IMappin > ) : Bool
	{
		var mappinQuest : weak< JournalQuest >;
		if( HasSelectedMappin() )
		{
			mappinQuest = questLogGameController.GetTopQuestEntry( m_journalManager, GetMappinJournalEntry( mappin ) );
			return mappinQuest != NULL;
		}
		return false;
	}

	private function RefreshInputHints()
	{
		var isFastTravelEnabled : Bool;
		var canTrackWaypoint : Bool;
		var priority : Int32;
		var evt : UpdateInputHintMultipleEvent;
		priority = 1;
		evt = new UpdateInputHintMultipleEvent;
		evt.targetHintContainer = 'WorldMapInputHints';
		if( IsEntitySetup() )
		{
			AddInputHintUpdate( evt, true, 'CloseMenuSingleKey', "Common-Access-Close", priority );
			isFastTravelEnabled = IsFastTravelEnabled();
			if( ( ( WorldMapPlayerMappinController )( selectedMappin ) ) == NULL )
			{
				AddInputHintUpdate( evt, true, 'world_map_menu_jump_to_player', "UI-ScriptExports-JumpToPlayer0", priority );
			}
			else if( m_mappinsPositions.Size() > 0 )
			{
				AddInputHintUpdate( evt, true, 'world_map_menu_jump_to_player', "UI-UserActions-JumpToObjective", priority );
			}
			else
			{
				AddInputHintUpdate( evt, false, 'world_map_menu_jump_to_player', "UI-UserActions-JumpToObjective", priority );
			}
			AddInputHintUpdate( evt, true, 'world_map_menu_zoom_in', "Gameplay-RPG-Stats-WeaponStats-ZoomLevel", priority );
			AddInputHintUpdate( evt, true, 'world_map_fake_move', "Gameplay-Player-ButtonHelper-Move", priority );
			canTrackWaypoint = !( isFastTravelEnabled );
			AddInputHintUpdate( evt, canTrackWaypoint, 'world_map_menu_track_waypoint', "UI-Settings-ButtonMappings-Actions-MapTrack", priority );
			QueueEvent( evt );
		}
	}

	protected function AddInputHintUpdate( out evt : UpdateInputHintMultipleEvent, show : Bool, action : CName, const locKey : ref< String >, out priority : Int32 )
	{
		var data : InputHintData;
		data.action = action;
		data.source = 'WorldMap';
		data.localizedLabel = GetLocalizedText( locKey );
		data.sortingPriority = priority;
		data.queuePriority = priority;
		evt.AddInputHint( data, show );
		priority += 1;
	}

	public override function CreateMappinUIProfile( mappin : weak< IMappin >, mappinVariant : gamedataMappinVariant, customData : MappinControllerCustomData ) : MappinUIProfile
	{
		var widgetResource : ResRef;
		widgetResource = R"base\gameplay\gui\fullscreen\world_map\mappins\default_mappin.inkwidget";
		if( customData )
		{
			if( customData.IsA( 'gameuiWorldMapPlayerInitData' ) )
			{
				widgetResource = R"base\gameplay\gui\fullscreen\world_map\mappins\player_mappin.inkwidget";
			}
		}
		return MappinUIProfile.Create( widgetResource, T"MappinUISpawnProfile.Always", T"MapMappinUIProfile.Default" );
	}

	public const function GetPlayer() : weak< GameObject >
	{
		return m_player;
	}

	public const function GetJournalManager() : weak< JournalManager >
	{
		return m_journalManager;
	}

	private function GetTotalZoomLevels() : Int32
	{
		var settings : WorldMapSettings_Record;
		var levels : array< weak< WorldMapZoomLevel_Record > >;
		settings = GetSettings();
		if( settings != NULL )
		{
			settings.ZoomLevels( levels );
			return levels.Size();
		}
		return 0;
	}

	private function GetFastTravelSystem() : FastTravelSystem
	{
		return ( ( FastTravelSystem )( GameInstance.GetScriptableSystemsContainer( GetOwner().GetGame() ).Get( 'FastTravelSystem' ) ) );
	}

	public function IsFastTravelEnabled() : Bool
	{
		return GetFastTravelSystem().IsFastTravelEnabledOnMap();
	}

	private function GetDelamainTaxiSystem() : DelamainTaxiSystem
	{
		return ( ( DelamainTaxiSystem )( GameInstance.GetScriptableSystemsContainer( GetOwner().GetGame() ).Get( 'DelamainTaxiSystem' ) ) );
	}

	public function IsDelamainTaxiEnabled() : Bool
	{
		return GetDelamainTaxiSystem().IsDelamainTaxiEnabledOnMap();
	}

	private function GetOwner() : GameObject
	{
		return ( ( GameObject )( GetOwnerEntity() ) );
	}

	private function HasSelectedMappin() : Bool
	{
		return selectedMappin != NULL;
	}

	private function HasSelectedDelamainTaxiMappin() : Bool
	{
		return delamainTaxiMappinID.value != 0;
	}

	private const function GetMappinJournalEntry( mappin : IMappin ) : JournalEntry
	{
		var journalPathHash : Uint32;
		journalPathHash = GetMappinJournalPathHash( mappin );
		if( ( journalPathHash != ( ( Uint32 )( 0 ) ) ) && m_journalManager )
		{
			return m_journalManager.GetEntry( journalPathHash );
		}
		return NULL;
	}

	private const function GetMappinJournalPathHash( mappin : IMappin ) : Uint32
	{
		var questMappin : QuestMappin;
		var poiMappin : PointOfInterestMappin;
		if( mappin )
		{
			questMappin = ( ( QuestMappin )( mappin ) );
			if( questMappin )
			{
				return questMappin.GetJournalPathHash();
			}
			poiMappin = ( ( PointOfInterestMappin )( mappin ) );
			if( poiMappin )
			{
				return poiMappin.GetJournalPathHash();
			}
		}
		return 0;
	}

	public const function CanQuestTrackMappin( mappin : weak< IMappin > ) : Bool
	{
		var groupName : CName;
		var mappinVariant : gamedataMappinVariant;
		var journalEntry : JournalEntry;
		var mappinsGroup : weak< MappinsGroup_Record >;
		if( mappin != NULL )
		{
			mappinVariant = mappin.GetVariant();
			if( mappinVariant == gamedataMappinVariant.Zzz18_RacingVariant )
			{
				return false;
			}
			journalEntry = GetMappinJournalEntry( mappin );
			mappinsGroup = MappinUtils.GetMappinsGroup( mappinVariant );
			if( mappinsGroup != NULL )
			{
				groupName = mappinsGroup.GroupName();
				return ( journalEntry != NULL ) && ( groupName == 'Quest' || groupName == 'SecondaryQuest' );
			}
		}
		return false;
	}

	public const function CanQuestTrackMappin( controller : weak< BaseWorldMapMappinController > ) : Bool
	{
		if( controller != NULL )
		{
			return CanQuestTrackMappin( controller.GetMappin() );
		}
		return false;
	}

	public const function IsMappinQuestTracked( mappin : weak< IMappin > ) : Bool
	{
		var journalEntry : JournalEntry;
		if( mappin != NULL )
		{
			journalEntry = GetMappinJournalEntry( mappin );
			if( journalEntry != NULL )
			{
				m_journalManager.IsEntryTracked( journalEntry );
			}
		}
		return false;
	}

	public const function IsMappinQuestTracked( controller : weak< BaseWorldMapMappinController > ) : Bool
	{
		return IsMappinQuestTracked( controller.GetMappin() );
	}

	public const function CanPlayerTrackMappin( mappin : weak< IMappin > ) : Bool
	{
		return !( CanQuestTrackMappin( mappin ) );
	}

	public const function CanPlayerTrackMappin( controller : weak< BaseWorldMapMappinController > ) : Bool
	{
		return CanPlayerTrackMappin( controller.GetMappin() );
	}

	public function CanZoomToMappin( controller : weak< BaseWorldMapMappinController > ) : Bool
	{
		return isZoomToMappinEnabled;
	}

	private function CanPay() : Bool
	{
		var gi : GameInstance;
		var autoDriveSystem : AutoDriveSystem;
		var transactionSystem : TransactionSystem;
		var playerMoney : Int32;
		var travelCost : Int32;
		gi = m_player.GetGame();
		autoDriveSystem = ( ( AutoDriveSystem )( GameInstance.GetScriptableSystemsContainer( gi ).Get( 'AutoDriveSystem' ) ) );
		travelCost = GetTravelCost();
		if( autoDriveSystem.CheckCurrentLaneValidity() != gameAutodriveLaneValidityResult.OnValidLane )
		{
			return false;
		}
		transactionSystem = GameInstance.GetTransactionSystem( gi );
		playerMoney = transactionSystem.GetItemQuantity( m_player, MarketSystem.Money() );
		if( travelCost > playerMoney )
		{
			return false;
		}
		return true;
	}

}

import class BaseWorldMapMappinController extends BaseInteractionMappinController
{
	import var selected : Bool;
	import var inZoomLevel : Bool;
	import var inCustomFilter : Bool;
	import var hasCustomFilter : Bool;
	import var isFastTravelEnabled : Bool;
	import var isVisibleInFilterAndZoom : Bool;
	private import const var groupState : gameuiMappinGroupState;
	import const var collectionCount : Uint8;
	private var m_mappin : weak< IMappin >;
	private var m_isCompletedPhase : Bool;
	default m_isCompletedPhase = false;
	private var m_resetStateWhenUntracked : Bool;
	default m_resetStateWhenUntracked = false;
	private var m_isNewAnim : inkAnimProxy;
	private var m_fadeAnim : inkAnimProxy;
	private var m_selectAnim : inkAnimProxy;
	private editable var m_fadeInOutDelay : Float;

	public import function IsGrouped() : Bool;
	public import function IsCollection() : Bool;
	public import function IsInCollection() : Bool;

	protected event OnInitialize()
	{
		var rootWidget : weak< inkWidget >;
		rootWidget = GetRootWidget();
		rootWidget.SetOpacity( 0.0 );
		rootWidget.SetInteractive( false );
	}

	protected event OnIntro()
	{
		m_mappin = GetMappin();
		Update();
		OnFiltersChanged();
	}

	protected event OnUpdate()
	{
		Update();
	}

	protected function Update()
	{
		UpdateVisibility();
		UpdateIcon();
		UpdateRootState();
		UpdateTrackedState();
	}

	protected virtual function UpdateVisibility()
	{
		var questMappin : QuestMappin;
		var wasVisible : Bool;
		var rootWidget : weak< inkWidget >;
		questMappin = ( ( QuestMappin )( m_mappin ) );
		rootWidget = GetRootWidget();
		m_isCompletedPhase = m_mappin.GetPhase() == gamedataMappinPhase.CompletedPhase;
		if( questMappin )
		{
			wasVisible = rootWidget.IsVisible();
			rootWidget.SetVisible( questMappin.IsActive() );
			if( !( wasVisible ) && questMappin.IsActive() )
			{
				rootWidget.SetOpacity( 0.01 );
			}
		}
		if( IsTracked() )
		{
			SelectMappin();
			m_resetStateWhenUntracked = true;
		}
		else if( m_resetStateWhenUntracked )
		{
			UnselectMappin();
		}
	}

	protected virtual function UpdateIcon()
	{
		var mappinVariant : gamedataMappinVariant;
		var mappinPhase : gamedataMappinPhase;
		var texturePart : CName;
		var color : CName;
		mappinVariant = m_mappin.GetVariant();
		mappinPhase = m_mappin.GetPhase();
		texturePart = MappinUIUtils.MappinToTexturePart( mappinVariant, mappinPhase );
		inkImageRef.SetTexturePart( iconWidget, texturePart );
		color = MappinUIUtils.MappinToColor( mappinVariant );
		if( color != '' )
		{
			inkImageRef.Get( iconWidget ).BindProperty( 'tintColor', color );
		}
		if( inkWidgetRef.IsValid( playerTrackedWidget ) )
		{
			inkWidgetRef.SetVisible( playerTrackedWidget, IsTracked() );
		}
		UpdateIsNew();
	}

	protected function UpdateIsNew()
	{
		var isNew : Bool;
		isNew = !( m_mappin.IsVisited() ) && !( IsCollection() );
		if( isNew && ( m_isNewAnim == NULL ) )
		{
			m_isNewAnim = PlayLibraryAnimation( 'OnNew' );
		}
		else if( !( isNew ) && ( m_isNewAnim != NULL ) )
		{
			m_isNewAnim.Stop();
			m_isNewAnim = NULL;
		}
	}

	public virtual function CanSelectMappin() : Bool
	{
		return true;
	}

	private function GetDesiredOpacityAndInteractivity( out opacity : Float, out interactive : Bool )
	{
		var visibleInGroup : Bool;
		if( hasCustomFilter )
		{
			interactive = ( inCustomFilter && !( m_isCompletedPhase ) ) || IsTracked();
		}
		else
		{
			interactive = ( inZoomLevel && !( m_isCompletedPhase ) ) || IsTracked();
		}
		isVisibleInFilterAndZoom = interactive;
		visibleInGroup = groupState != gameuiMappinGroupState.GroupedHidden;
		if( !( visibleInGroup ) )
		{
			interactive = false;
		}
		opacity = ( ( interactive ) ? ( 1.0 ) : ( 0.0 ) );
	}

	protected event OnFiltersChanged()
	{
		PlayHideShowAnim();
	}

	private function PlayHideShowAnim()
	{
		var opacity : Float;
		var interactive : Bool;
		var rootWidget : weak< inkWidget >;
		rootWidget = GetRootWidget();
		GetDesiredOpacityAndInteractivity( opacity, interactive );
		PlayFadeAnimation( opacity );
		rootWidget.SetInteractive( interactive );
	}

	protected override function ComputeRootState() : CName
	{
		var mappinsGroup : weak< MappinsGroup_Record >;
		var variant : gamedataMappinVariant;
		var stateName : CName;
		if( m_isCompletedPhase )
		{
			stateName = 'QuestComplete';
		}
		if( m_mappin.GetVariant() == gamedataMappinVariant.Zzz17_NCARTVariant )
		{
			stateName = 'FastTravelMetro';
		}
		else if( m_mappin != NULL )
		{
			mappinsGroup = MappinUtils.GetMappinsGroup( m_mappin.GetVariant() );
			variant = m_mappin.GetVariant();
			if( variant == gamedataMappinVariant.Zzz16_RelicDeviceBasicVariant )
			{
				stateName = 'Relic';
			}
			else if( mappinsGroup )
			{
				stateName = mappinsGroup.WidgetState();
			}
		}
		if( stateName == '' )
		{
			stateName = 'Quest';
		}
		return stateName;
	}

	private function PlayFadeAnimation( opacity : Float )
	{
		var widget : weak< inkWidget >;
		var animDef : inkAnimDef;
		var animInterp : inkAnimTransparency;
		StopFadeAnimation();
		widget = GetRootWidget();
		if( widget.GetOpacity() == opacity )
		{
			return;
		}
		animDef = new inkAnimDef;
		animInterp = new inkAnimTransparency;
		animInterp.SetEndTransparency( opacity );
		animInterp.SetDuration( m_fadeInOutDelay );
		animInterp.SetDirection( inkanimInterpolationDirection.To );
		animInterp.SetUseRelativeDuration( true );
		animDef.AddInterpolator( animInterp );
		m_fadeAnim = widget.PlayAnimation( animDef );
	}

	private function StopFadeAnimation()
	{
		if( m_fadeAnim != NULL )
		{
			m_fadeAnim.Stop( true );
			m_fadeAnim = NULL;
		}
	}

	public function SelectMappin()
	{
		if( m_isNewAnim != NULL )
		{
			m_isNewAnim.Stop();
			m_isNewAnim = NULL;
		}
		if( m_selectAnim != NULL )
		{
			m_selectAnim.Stop();
		}
		m_selectAnim = PlayLibraryAnimation( 'OnSelect' );
	}

	public function UnselectMappin()
	{
		if( m_selectAnim != NULL )
		{
			m_selectAnim.Stop();
		}
		if( !( IsTracked() ) )
		{
			m_selectAnim = PlayLibraryAnimation( 'OnUnselect' );
			m_resetStateWhenUntracked = false;
		}
	}

	public function GetMappinVariant() : gamedataMappinVariant
	{
		return m_mappin.GetVariant();
	}

}

import class WorldMapPlayerMappinController extends BaseWorldMapMappinController
{

	protected event OnInitialize()
	{
		var rootWidget : weak< inkWidget >;
		rootWidget = GetRootWidget();
		rootWidget.SetVisible( true );
	}

	protected event OnFiltersChanged() {}

	protected override function UpdateIcon() {}

	protected override function ComputeRootState() : CName
	{
		return 'Player';
	}

	public override function CanSelectMappin() : Bool
	{
		return false;
	}

}

import class WorldMapDistrictLogicController extends inkLogicController
{
	protected import var record : weak< District_Record >;
	protected import var type : gamedataDistrict;
	protected import var iconWidget : inkImageRef;
	protected import var selected : Bool;
	private var m_selectAnim : inkAnimProxy;
	private var rootWidget : weak< inkWidget >;

	protected event OnInitDistrict()
	{
		rootWidget = GetRootWidget();
		if( IsSubDistrict() )
		{
			rootWidget.SetState( GetParentDistrictRecord().UiState() );
			inkImageRef.SetVisible( iconWidget, false );
		}
		else
		{
			rootWidget.SetState( record.UiState() );
			inkImageRef.SetTexturePart( iconWidget, record.UiIcon() );
		}
	}

	protected event OnSetSelected( inSelected : Bool )
	{
		if( m_selectAnim )
		{
			m_selectAnim.Stop();
			m_selectAnim = NULL;
		}
		if( inSelected )
		{
			m_selectAnim = PlayLibraryAnimation( 'OnSelectDistrict' );
		}
		else
		{
			m_selectAnim = PlayLibraryAnimation( 'OnDeselectDistrict' );
		}
	}

	private function GetParentDistrictRecord() : weak< District_Record >
	{
		return record.ParentDistrict();
	}

	private function IsSubDistrict() : Bool
	{
		return GetParentDistrictRecord() != NULL;
	}

}

class WorldMapFiltersList extends inkLogicController
{

	protected event OnInitialize()
	{
		RegisterToCallback( 'OnPress', this, 'OnConsumeInput' );
		RegisterToCallback( 'OnRelease', this, 'OnConsumeInput' );
	}

	protected event OnUninitialize()
	{
		UnregisterFromCallback( 'OnPress', this, 'OnConsumeInput' );
		UnregisterFromCallback( 'OnRelease', this, 'OnConsumeInput' );
	}

	protected event OnConsumeInput( evt : inkPointerEvent )
	{
		if( evt.IsAction( 'click' ) )
		{
			evt.Consume();
		}
	}

}

class WorldMapFiltersListItem extends inkLogicController
{
	private editable var m_checker : inkWidgetRef;
	private editable var m_filterName : inkTextRef;
	private var m_filterGroup : weak< MappinUIFilterGroup_Record >;
	private var m_rootWidget : weak< inkWidget >;
	private var m_isHovered : Bool;

	protected event OnInitialize()
	{
		m_rootWidget = GetRootWidget();
		RegisterToCallback( 'OnHoverOver', this, 'OnHoverOverFilter' );
		RegisterToCallback( 'OnHoverOut', this, 'OnHoverOutFilter' );
	}

	protected event OnUninitialize()
	{
		UnregisterFromCallback( 'OnHoverOver', this, 'OnHoverOverFilter' );
		UnregisterFromCallback( 'OnHoverOut', this, 'OnHoverOutFilter' );
	}

	protected event OnHoverOverFilter( evt : inkPointerEvent )
	{
		m_isHovered = true;
		SetFilterState( 'Hover' );
	}

	protected event OnHoverOutFilter( evt : inkPointerEvent )
	{
		m_isHovered = false;
		if( IsFilterEnabled() )
		{
			SetFilterState( 'Selected' );
		}
		else
		{
			SetFilterState( 'Default' );
		}
	}

	public function PlayIntroAnimation( delay : Float )
	{
		var animOptions : inkAnimOptions;
		animOptions.executionDelay = delay;
		PlayLibraryAnimation( 'OnFiltersListItem', animOptions );
	}

	public function SwitchFilter() : Bool
	{
		EnableFilter( !( inkWidgetRef.IsVisible( m_checker ) ) );
		return IsFilterEnabled();
	}

	public function EnableFilter( enable : Bool )
	{
		inkWidgetRef.SetVisible( m_checker, enable );
		if( m_isHovered )
		{
			SetFilterState( 'Hover' );
			return;
		}
		if( enable )
		{
			SetFilterState( 'Selected' );
		}
		else
		{
			SetFilterState( 'Default' );
		}
	}

	public function IsFilterEnabled() : Bool
	{
		return inkWidgetRef.IsVisible( m_checker );
	}

	public function IsFilterHovered() : Bool
	{
		return m_rootWidget.GetState() == 'Hover';
	}

	public function SetFilterState( state : CName )
	{
		m_rootWidget.SetState( state );
	}

	public function SetFilterGroup( filterGroup : weak< MappinUIFilterGroup_Record > )
	{
		m_filterGroup = filterGroup;
		inkTextRef.SetLocalizedTextScript( m_filterName, m_filterGroup.FilterName() );
	}

	public function GetFilterType() : gamedataWorldMapFilter
	{
		return m_filterGroup.FilterType().Type();
	}

}

class WorldMapPreloader extends inkLogicController
{
	private editable var m_splashAnim : CName;
	private editable var m_spinnerAnim : CName;
	private editable var m_spinnerFadeOutAnim : CName;
	private editable var m_spinnerFadeInAnim : CName;
	private editable var m_mapFadeOutAnim : CName;
	var m_isMapLoaded : Bool;
	default m_isMapLoaded = false;
	var m_isMapFadeOutStarted : Bool;
	default m_isMapFadeOutStarted = false;
	var m_isSpinnerVisible : Bool;
	default m_isSpinnerVisible = false;
	var m_splashProxy : inkAnimProxy;
	var m_spinnerFadeOutProxy : inkAnimProxy;

	public function ShowSpinner()
	{
		m_isSpinnerVisible = true;
		m_spinnerFadeOutProxy = PlayLibraryAnimation( m_spinnerFadeOutAnim );
	}

	public function SetMapLoaded()
	{
		m_isMapLoaded = true;
		if( m_isSpinnerVisible )
		{
			m_spinnerFadeOutProxy.Stop();
			m_spinnerFadeOutProxy = NULL;
			PlayLibraryAnimation( m_spinnerFadeInAnim );
		}
	}

	protected event OnInitialize()
	{
		var loopOpts : inkAnimOptions;
		loopOpts.loopType = inkanimLoopType.Cycle;
		loopOpts.loopInfinite = true;
		m_splashProxy = PlayLibraryAnimation( m_splashAnim, loopOpts );
		m_splashProxy.RegisterToCallback( inkanimEventType.OnEndLoop, this, 'OnEndLoop' );
		PlayLibraryAnimation( m_spinnerAnim, loopOpts );
	}

	protected event OnUninitialize()
	{
		m_splashProxy.UnregisterFromCallback( inkanimEventType.OnEndLoop, this, 'OnEndLoop' );
		m_splashProxy = NULL;
	}

	protected event OnEndLoop( proxy : inkAnimProxy )
	{
		if( m_isMapLoaded && m_isMapFadeOutStarted )
		{
			m_splashProxy.UnregisterFromCallback( inkanimEventType.OnEndLoop, this, 'OnEndLoop' );
			m_splashProxy.Stop();
			m_splashProxy = NULL;
			CallCustomCallback( 'OnFinished' );
		}
	}

	protected event OnSplash()
	{
		if( m_isMapLoaded )
		{
			PlayLibraryAnimation( m_mapFadeOutAnim );
			m_isMapFadeOutStarted = true;
		}
	}

}

