class BaseCodexLinkController extends inkLogicController
{
	protected editable var m_linkImage : inkImageRef;
	protected editable var m_linkLabel : inkTextRef;
	protected editable var m_inputContainer : inkWidgetRef;
	protected var m_animProxy : inkAnimProxy;
	protected var m_isInteractive : Bool;

	protected event OnInitialize()
	{
		RegisterToCallback( 'OnHoverOver', this, 'OnHoverOver' );
		RegisterToCallback( 'OnHoverOut', this, 'OnHoverOut' );
		RegisterToCallback( 'OnRelease', this, 'OnRelease' );
		m_isInteractive = true;
	}

	protected event OnHoverOver( evt : inkPointerEvent )
	{
		if( m_isInteractive )
		{
			ForcePlayAnimation( 'hyperlink_hover' );
			GetRootWidget().SetState( 'Hover' );
		}
	}

	protected event OnHoverOut( evt : inkPointerEvent )
	{
		if( m_isInteractive )
		{
			ForcePlayAnimation( 'clear_hyperlink_hover' );
			GetRootWidget().SetState( 'Default' );
		}
	}

	protected event OnRelease( e : inkPointerEvent )
	{
		if( m_isInteractive )
		{
			if( e.IsAction( 'click' ) )
			{
				Activate();
			}
			else if( e.IsAction( 'activate' ) )
			{
				ActivateSecondary();
			}
		}
	}

	public function EnableInputHint( value : Bool )
	{
		inkWidgetRef.SetVisible( m_inputContainer, value );
	}

	private virtual function Activate() {}

	private virtual function ActivateSecondary() {}

	private function ForcePlayAnimation( animationName : CName )
	{
		if( m_animProxy.IsPlaying() )
		{
			m_animProxy.Stop();
		}
		m_animProxy = PlayLibraryAnimationOnAutoSelectedTargets( animationName, GetRootWidget() );
	}

}

class QuestCodexLinkController extends BaseCodexLinkController
{
	protected editable var m_linkLabelContainer : inkWidgetRef;
	private var m_journalEntry : weak< JournalEntry >;

	public function Setup( journalEntry : weak< JournalEntry >, optional journalEntryReplacer : weak< JournalEntry > )
	{
		var imgEntry : JournalImageEntry;
		var codexEntry : JournalCodexEntry;
		m_journalEntry = journalEntry;
		imgEntry = ( ( JournalImageEntry )( journalEntry ) );
		if( imgEntry )
		{
			SetupImageLink( imgEntry );
		}
		else
		{
			codexEntry = ( ( journalEntryReplacer ) ? ( ( ( JournalCodexEntry )( journalEntryReplacer ) ) ) : ( ( ( JournalCodexEntry )( journalEntry ) ) ) );
			SetupCodexLink( codexEntry );
		}
	}

	private function SetupCodexLink( codexEntry : weak< JournalCodexEntry > )
	{
		inkTextRef.SetText( m_linkLabel, codexEntry.GetTitle() );
		inkTextRef.SetVisible( m_linkLabel, true );
		if( CodexUtils.IsImageValid( codexEntry.GetLinkImageID() ) )
		{
			InkImageUtils.RequestSetImage( this, m_linkImage, codexEntry.GetLinkImageID(), 'OnCallback' );
		}
		else
		{
			GetRootWidget().SetVisible( false );
			return;
		}
		GetRootWidget().SetInteractive( true );
	}

	private function SetupImageLink( imageEntry : weak< JournalImageEntry > )
	{
		if( CodexUtils.IsImageValid( imageEntry.GetThumbnailImageID() ) )
		{
			InkImageUtils.RequestSetImage( this, m_linkImage, imageEntry.GetThumbnailImageID() );
		}
		else
		{
			GetRootWidget().SetVisible( false );
			return;
		}
		m_isInteractive = TDBID.IsValid( imageEntry.GetImageID() );
		if( m_isInteractive )
		{
			inkTextRef.SetLocalizedText( m_linkLabel, 'Common-Access-Open' );
			inkWidgetRef.SetVisible( m_linkLabelContainer, true );
		}
		else
		{
			inkWidgetRef.SetVisible( m_linkLabelContainer, false );
		}
		GetRootWidget().SetInteractive( m_isInteractive );
	}

	private override function Activate()
	{
		var evt : OpenCodexPopupEvent;
		if( m_isInteractive )
		{
			evt = new OpenCodexPopupEvent;
			evt.m_entry = m_journalEntry;
			QueueBroadcastEvent( evt );
		}
	}

}

class QuestMissionLinkController extends BaseCodexLinkController
{
	private editable var m_linkContainer : inkWidgetRef;
	private editable var m_title : inkTextRef;
	private editable var m_description : inkTextRef;
	private editable var m_icon : inkImageRef;
	private var m_journalManager : weak< JournalManager >;
	private var m_questEntry : weak< JournalQuest >;
	private var m_questState : gameJournalEntryState;
	private var m_questEntryHash : Int32;

	public function Setup( journalEntry : weak< JournalQuest >, journalManager : weak< JournalManager > )
	{
		var questType : gameJournalQuestType;
		var state : CName;
		m_questEntry = ( ( JournalQuest )( journalEntry ) );
		m_journalManager = journalManager;
		questType = m_questEntry.GetType();
		m_questState = m_journalManager.GetEntryState( journalEntry );
		if( m_questState == gameJournalEntryState.Succeeded || m_questState == gameJournalEntryState.Failed )
		{
			state = 'Finished';
			GetRootWidget().SetInteractive( false );
			inkImageRef.SetTexturePart( m_icon, 'completed' );
		}
		else
		{
			state = GetState( questType );
			GetRootWidget().SetInteractive( true );
			inkImageRef.SetTexturePart( m_icon, GetIcon( questType ) );
		}
		inkWidgetRef.SetState( m_linkContainer, state );
		inkTextRef.SetLocalizedTextString( m_title, m_questEntry.GetTitle( m_journalManager ) );
		inkTextRef.SetText( m_description, GetFirstObjective().GetDescription() );
		PlayLibraryAnimation( 'introLink' );
	}

	public function GetFirstObjective() : weak< JournalQuestObjective >
	{
		var i : Int32;
		var unpackedData : array< weak< JournalEntry > >;
		QuestLogUtils.UnpackRecursive( m_journalManager, m_questEntry, unpackedData );
		for( i = 0; i < unpackedData.Size(); i += 1 )
		{
			if( ( ( JournalQuestObjective )( unpackedData[ i ] ) ) )
			{
				return ( ( JournalQuestObjective )( unpackedData[ i ] ) );
			}
		}
		return NULL;
	}

	protected event OnActivateLink( e : ActivateLink ) {}

	private override function Activate() {}

	protected event OnRelease( e : inkPointerEvent )
	{
		var evt : ScrollToJournalEntryEvent;
		if( e.IsAction( 'click' ) )
		{
			PlaySound( 'Button', 'OnPress' );
			evt = new ScrollToJournalEntryEvent;
			evt.m_hash = m_journalManager.GetEntryHash( m_questEntry );
			QueueEvent( evt );
		}
	}

	public static function GetIcon( filterType : gameJournalQuestType ) : CName
	{
		switch( filterType )
		{
			case gameJournalQuestType.MainQuest:
				return 'quest';
			case gameJournalQuestType.SideQuest:
			case gameJournalQuestType.CourierSideQuest:
				return 'minor_quest';
			case gameJournalQuestType.MinorQuest:
				return 'minor_quest';
			case gameJournalQuestType.StreetStory:
				return 'gigs';
			case gameJournalQuestType.CyberPsycho:
				return 'hunt_for_psycho';
			case gameJournalQuestType.Contract:
				return 'map_bounty';
			case gameJournalQuestType.ApartmentQuest:
				return 'apartment_to_buy';
		}
		return 'invalid';
	}

	public static function GetState( filterType : gameJournalQuestType ) : CName
	{
		switch( filterType )
		{
			case gameJournalQuestType.MainQuest:
				return 'MainQuest';
			case gameJournalQuestType.SideQuest:
			case gameJournalQuestType.CourierSideQuest:
				return 'MainQuest';
			case gameJournalQuestType.MinorQuest:
				return 'MainQuest';
			case gameJournalQuestType.StreetStory:
				return 'Gig';
			case gameJournalQuestType.CyberPsycho:
				return 'Cyberpsycho';
			case gameJournalQuestType.Contract:
				return 'Cyberpsycho';
			case gameJournalQuestType.ApartmentQuest:
				return 'Apartment';
		}
		return 'Default';
	}

}

class QuestFluffShardLinkController extends BaseCodexLinkController
{
}

class QuestContactLinkController extends BaseCodexLinkController
{
	private editable var m_msgLabel : inkTextRef;
	private editable var m_msgContainer : inkWidgetRef;
	private var m_msgCounter : Int32;
	private var m_contactEntry : JournalContact;
	private var m_journalMgr : weak< JournalManager >;
	private var m_phoneSystem : weak< PhoneSystem >;
	private var m_uiSystem : weak< UISystem >;

	public function Setup( journalEntry : JournalEntry, journalManager : weak< JournalManager >, phoneSystem : weak< PhoneSystem >, uiSystem : weak< UISystem > )
	{
		var avatarTweakId : TweakDBID;
		m_phoneSystem = phoneSystem;
		m_journalMgr = journalManager;
		m_uiSystem = uiSystem;
		m_contactEntry = ( ( JournalContact )( journalEntry ) );
		inkTextRef.SetText( m_linkLabel, m_contactEntry.GetLocalizedName( journalManager ) );
		avatarTweakId = m_contactEntry.GetAvatarID( journalManager );
		if( CodexUtils.IsImageValid( avatarTweakId ) )
		{
			InkImageUtils.RequestSetImage( this, m_linkImage, avatarTweakId );
		}
		else
		{
			GetRootWidget().SetVisible( false );
			return;
		}
		m_msgCounter = MessengerUtils.GetUnreadMessagesCount( journalManager, m_contactEntry );
		if( m_msgCounter > 0 )
		{
			inkTextRef.SetText( m_msgLabel, ( ( String )( m_msgCounter ) ) );
			inkWidgetRef.SetVisible( m_msgContainer, true );
		}
		else
		{
			inkWidgetRef.SetVisible( m_msgContainer, false );
		}
		PlayLibraryAnimation( 'introLink' );
	}

	protected event OnActivateLink( e : ActivateLink )
	{
		Activate();
	}

	private function ShowActionBlockedNotification()
	{
		var notificationEvent : UIInGameNotificationEvent;
		notificationEvent = new UIInGameNotificationEvent;
		m_uiSystem.QueueEvent( new UIInGameNotificationRemoveEvent );
		notificationEvent.m_notificationType = UIInGameNotificationType.ActionRestriction;
		m_uiSystem.QueueEvent( notificationEvent );
	}

	private override function Activate()
	{
		if( !( m_phoneSystem.IsCallingEnabled() ) )
		{
			ShowActionBlockedNotification();
			return;
		}
		CallSelectedContact();
		CloseHubMenu();
	}

	private override function ActivateSecondary() {}

	private function CloseHubMenu()
	{
		var evt : ForceCloseHubMenuEvent;
		evt = new ForceCloseHubMenuEvent;
		QueueBroadcastEvent( evt );
	}

	private function CallSelectedContact()
	{
		var callRequest : questTriggerCallRequest;
		callRequest = new questTriggerCallRequest;
		callRequest.addressee = StringToName( m_contactEntry.GetId() );
		callRequest.caller = 'Player';
		callRequest.callPhase = questPhoneCallPhase.IncomingCall;
		callRequest.callMode = questPhoneCallMode.Video;
		m_phoneSystem.QueueRequest( callRequest );
	}

}

class QuestMessageLinkController extends BaseCodexLinkController
{
	private var m_contactEntry : JournalContact;
	private var m_messageEntry : JournalPhoneMessage;
	private var m_journalManager : weak< JournalManager >;
	private var m_childEntry : weak< JournalEntry >;
	private var m_conversation : JournalPhoneConversation;
	private var m_phoneSystem : weak< PhoneSystem >;

	public function Setup( childEntry : weak< JournalEntry >, journalManager : weak< JournalManager >, phoneSystem : weak< PhoneSystem > )
	{
		var currentParent : JournalEntry;
		m_journalManager = journalManager;
		m_phoneSystem = phoneSystem;
		m_childEntry = childEntry;
		if( ( ( JournalPhoneMessage )( childEntry ) ) || ( ( JournalPhoneChoiceGroup )( childEntry ) ) )
		{
			currentParent = m_journalManager.GetParentEntry( m_childEntry );
			while( currentParent && !( ( ( JournalPhoneConversation )( currentParent ) ) ) )
			{
				currentParent = m_journalManager.GetParentEntry( currentParent );
			}
			m_conversation = ( ( JournalPhoneConversation )( currentParent ) );
		}
		else
		{
			m_conversation = ( ( JournalPhoneConversation )( childEntry ) );
		}
		m_contactEntry = ( ( JournalContact )( m_journalManager.GetParentEntry( m_conversation ) ) );
		inkTextRef.SetText( m_linkLabel, m_contactEntry.GetLocalizedName( journalManager ) );
		PlayLibraryAnimation( 'introLink' );
	}

	private override function Activate()
	{
		ShowSmsMessenger();
		CloseHubMenu();
	}

	private function CloseHubMenu()
	{
		QueueBroadcastEvent( new ForceCloseHubMenuEvent );
	}

	protected event OnActivateLink( e : ActivateLink )
	{
		Activate();
	}

	private function ShowSmsMessenger()
	{
		var request : UsePhoneRequest;
		request = new UsePhoneRequest;
		request.MessageToOpen = m_conversation;
		m_phoneSystem.QueueRequest( request );
	}

}

class QuestShardLinkController extends BaseCodexLinkController
{
	var m_journalManager : weak< JournalManager >;
	var m_journalEntry : weak< JournalOnscreen >;

	public function Setup( journalEntry : weak< JournalOnscreen >, journalManager : weak< JournalManager > )
	{
		m_journalEntry = ( ( JournalOnscreen )( journalEntry ) );
		m_journalManager = journalManager;
		inkTextRef.SetLocalizedTextString( m_linkLabel, m_journalEntry.GetTitle() );
		PlayLibraryAnimation( 'introLink' );
	}

	protected event OnActivateLink( e : ActivateLink )
	{
		Activate();
	}

	private override function Activate()
	{
		ShowShardJournalEntry();
	}

	protected function ShowShardJournalEntry()
	{
		var evt : OpenMenuRequest;
		var userData : ShardAttachmentData;
		evt = new OpenMenuRequest;
		userData = new ShardAttachmentData;
		userData.m_hash = m_journalManager.GetEntryHash( m_journalEntry );
		evt.m_menuName = 'shards';
		evt.m_isMainMenu = true;
		evt.m_eventData.userData = userData;
		evt.m_eventData.m_overrideDefaultUserData = true;
		evt.m_jumpBack = true;
		QueueBroadcastEvent( evt );
	}

}

class QuestMappinLinkController extends BaseCodexLinkController
{
	private var m_mappinEntry : JournalQuestMapPinBase;
	private var m_mappinEntryHash : JournalQuestMapPinBase;
	private var m_jumpTo : Vector3;
	private var m_hash : Int32;
	private var m_isTracked : Bool;

	public function Setup( mappinEntry : JournalQuestMapPinBase, mappinHash : Int32, jumpTo : Vector3, isTracked : Bool )
	{
		m_mappinEntry = mappinEntry;
		inkTextRef.SetText( m_linkLabel, m_mappinEntry.GetCaption() );
		m_jumpTo = jumpTo;
		m_hash = mappinHash;
		m_isTracked = isTracked;
	}

	protected event OnActivateLink( e : ActivateMapLink )
	{
		Activate();
	}

	private override function Activate()
	{
		var evt : OpenMenuRequest;
		var userData : MapMenuUserData;
		evt = new OpenMenuRequest;
		evt.m_menuName = 'world_map';
		userData = new MapMenuUserData;
		userData.m_moveTo = m_jumpTo;
		userData.m_hash = m_hash;
		userData.m_isTracked = m_isTracked;
		evt.m_eventData.userData = userData;
		evt.m_eventData.m_overrideDefaultUserData = true;
		evt.m_isMainMenu = true;
		evt.m_jumpBack = true;
		QueueBroadcastEvent( evt );
	}

}

