class QuestDetailsPanelController extends inkLogicController
{
	private editable var m_questTitle : inkTextRef;
	private editable var m_questDescription : inkTextRef;
	private editable var m_questLevel : inkTextRef;
	private editable var m_activeObjectives : inkCompoundRef;
	private editable var m_optionalObjectives : inkCompoundRef;
	private editable var m_completedObjectives : inkCompoundRef;
	private editable var m_codexLinksContainer : inkCompoundRef;
	private editable var m_missionLinksContainer : inkCompoundRef;
	private editable var m_fluffLinksContainer : inkCompoundRef;
	private editable var m_mapLinksContainer : inkCompoundRef;
	private editable var m_missionLinkLine : inkCompoundRef;
	private editable var m_fluffShardLinkLine : inkCompoundRef;
	private editable var m_codexLinkLine : inkCompoundRef;
	private editable var m_contentContainer : inkWidgetRef;
	private editable var m_scrollContainer : inkWidgetRef;
	private editable var m_noSelectedQuestContainer : inkWidgetRef;
	private editable var m_ep1Marker : inkWidgetRef;
	private var m_scrollContainerCtrl : weak< inkScrollController >;
	private var m_currentQuestData : weak< JournalQuest >;
	private var m_journalManager : weak< JournalManager >;
	private var m_shardEntry : weak< JournalOnscreen >;
	private var m_phoneSystem : weak< PhoneSystem >;
	private var m_mappinSystem : weak< MappinSystem >;
	private var m_uiSystem : weak< UISystem >;
	private var m_trackedObjective : weak< JournalQuestObjective >;
	private var m_canUsePhone : Bool;
	private var m_objectiveOffset : Float;
	default m_objectiveOffset = 20;
	private var m_objectiveActionOffset : Float;
	default m_objectiveActionOffset = 124;
	private var m_objectiveActionsCount : Int32;

	protected event OnInitialize()
	{
		inkWidgetRef.SetVisible( m_noSelectedQuestContainer, true );
		inkWidgetRef.SetVisible( m_contentContainer, false );
		m_scrollContainerCtrl = ( ( inkScrollController )( inkWidgetRef.GetControllerByType( m_scrollContainer, 'inkScrollController' ) ) );
	}

	public function Setup( questData : weak< JournalQuest >, journalManager : weak< JournalManager >, phoneSystem : weak< PhoneSystem >, mappinSystem : weak< MappinSystem >, uiSystem : weak< UISystem >, game : GameInstance, optional skipAnimation : Bool )
	{
		var playerLevel : Float;
		var recommendedLevel : Int32;
		if( m_currentQuestData == questData )
		{
			return;
		}
		m_scrollContainerCtrl.SetScrollPosition( 0.0 );
		playerLevel = GameInstance.GetStatsSystem( game ).GetStatValue( GameInstance.GetPlayerSystem( game ).GetLocalPlayerMainGameObject().GetEntityID(), gamedataStatType.Level );
		recommendedLevel = GameInstance.GetLevelAssignmentSystem( game ).GetLevelAssignment( questData.GetRecommendedLevelID() );
		m_currentQuestData = questData;
		m_journalManager = journalManager;
		m_phoneSystem = phoneSystem;
		m_mappinSystem = mappinSystem;
		m_uiSystem = uiSystem;
		inkWidgetRef.SetVisible( m_noSelectedQuestContainer, false );
		inkWidgetRef.SetVisible( m_contentContainer, true );
		inkTextRef.SetText( m_questTitle, questData.GetTitle( journalManager ) );
		inkTextRef.SetState( m_questLevel, QuestLogUtils.GetLevelState( RoundMath( playerLevel ), recommendedLevel ) );
		inkTextRef.SetText( m_questLevel, QuestLogUtils.GetThreatText( RoundMath( playerLevel ), recommendedLevel ) );
		inkWidgetRef.SetVisible( m_ep1Marker, journalManager.IsEp1Entry( m_currentQuestData ) );
		inkTextRef.SetText( m_questDescription, "" );
		m_trackedObjective = ( ( weak< weak< JournalQuestObjective > > )( journalManager.GetTrackedEntry() ) );
		inkCompoundRef.RemoveAllChildren( m_codexLinksContainer );
		inkCompoundRef.RemoveAllChildren( m_missionLinksContainer );
		inkCompoundRef.RemoveAllChildren( m_fluffLinksContainer );
		PopulateObjectives();
	}

	public function HasMultipleActionLinks() : Bool
	{
		return m_objectiveActionsCount > 1;
	}

	public function SetPhoneAvailable( value : Bool )
	{
		m_canUsePhone = value;
	}

	private function PopulateObjectives()
	{
		var i : Int32;
		var currentCounter, totalCounter : Int32;
		var currentEntry : weak< JournalEntry >;
		var childEntries : array< weak< JournalEntry > >;
		var objectiveEntry : weak< JournalQuestObjective >;
		var codexLinksObjectiveEntry : weak< JournalQuestObjective >;
		var widget : weak< inkWidget >;
		var controller : QuestDetailsObjectiveController;
		var descriptionEntries : array< weak< JournalQuestDescription > >;
		var description : String;
		var contextFilter : JournalRequestStateFilter;
		var codexLink : weak< JournalQuestCodexLink >;
		var childEntryState : gameJournalEntryState;
		var isObjectiveTracked : Bool;
		var uniqueQuestDescriptions : array< String >;
		var nextLine : Bool;
		nextLine = false;
		contextFilter.active = true;
		contextFilter.inactive = true;
		contextFilter.succeeded = true;
		contextFilter.failed = true;
		inkCompoundRef.RemoveAllChildren( m_activeObjectives );
		inkCompoundRef.RemoveAllChildren( m_optionalObjectives );
		inkCompoundRef.RemoveAllChildren( m_fluffLinksContainer );
		inkCompoundRef.SetVisible( m_fluffShardLinkLine, false );
		m_objectiveActionsCount = CalcObjectiveActionsCount( m_currentQuestData );
		m_journalManager.GetChildren( m_currentQuestData, contextFilter, childEntries );
		for( i = 0; i < childEntries.Size(); i += 1 )
		{
			codexLink = ( ( JournalQuestCodexLink )( childEntries[ i ] ) );
			if( codexLink )
			{
				currentEntry = ( ( JournalEntry )( m_journalManager.GetEntry( codexLink.GetLinkPathHash() ) ) );
				childEntryState = m_journalManager.GetEntryState( currentEntry );
				if( ( ( JournalOnscreen )( currentEntry ) ) && childEntryState == gameJournalEntryState.Active )
				{
					SpawnFluffShardLink( ( ( JournalOnscreen )( currentEntry ) ) );
					inkCompoundRef.SetVisible( m_fluffShardLinkLine, true );
				}
			}
		}
		QuestLogUtils.UnpackRecursive( m_journalManager, m_currentQuestData, childEntries );
		for( i = 0; i < childEntries.Size(); i += 1 )
		{
			currentEntry = childEntries[ i ];
			objectiveEntry = ( ( JournalQuestObjective )( currentEntry ) );
			if( objectiveEntry )
			{
				isObjectiveTracked = m_trackedObjective == objectiveEntry;
				widget = SpawnFromLocal( inkCompoundRef.Get( m_activeObjectives ), 'questObjective' );
				widget.SetHAlign( inkEHorizontalAlign.Left );
				widget.SetVAlign( inkEVerticalAlign.Top );
				currentCounter = m_journalManager.GetObjectiveCurrentCounter( objectiveEntry );
				totalCounter = m_journalManager.GetObjectiveTotalCounter( objectiveEntry );
				controller = ( ( QuestDetailsObjectiveController )( widget.GetController() ) );
				controller.Setup( objectiveEntry, m_journalManager, currentCounter, totalCounter, isObjectiveTracked );
				PopulateObjectiveActionLinks( objectiveEntry, m_activeObjectives );
				if( isObjectiveTracked || !( codexLinksObjectiveEntry ) )
				{
					codexLinksObjectiveEntry = objectiveEntry;
				}
			}
		}
		if( codexLinksObjectiveEntry )
		{
			PopulateCodexLinks( codexLinksObjectiveEntry );
		}
		descriptionEntries = QuestLogUtils.GetDescriptions( m_journalManager, m_currentQuestData );
		description = "";
		for( i = 0; i < descriptionEntries.Size(); i += 1 )
		{
			if( uniqueQuestDescriptions.Contains( GetLocalizedText( descriptionEntries[ i ].GetDescription() ) ) )
			{
				continue;
			}
			uniqueQuestDescriptions.PushBack( GetLocalizedText( descriptionEntries[ i ].GetDescription() ) );
			description = ( ( nextLine ) ? ( ( description + " " ) + GetLocalizedText( descriptionEntries[ i ].GetDescription() ) ) : ( description + GetLocalizedText( descriptionEntries[ i ].GetDescription() ) ) );
			if( i < ( descriptionEntries.Size() - 1 ) )
			{
				description + "\n";
			}
			nextLine = true;
		}
		inkTextRef.SetText( m_questDescription, description );
	}

	protected event OnUpdateTrackedObjectiveEvent( e : UpdateTrackedObjectiveEvent )
	{
		m_trackedObjective = e.m_trackedObjective;
		if( m_trackedObjective )
		{
			PopulateCodexLinks( m_trackedObjective );
		}
	}

	public function PopulateCodexLinks( objective : JournalQuestObjective )
	{
		var codexLink : weak< JournalQuestCodexLink >;
		var childEntries : array< weak< JournalEntry > >;
		var childEntriesSorted : array< weak< JournalEntry > >;
		var childEntry : weak< JournalEntry >;
		var childEntryHash : Int32;
		var childEntryState : gameJournalEntryState;
		var replacerEntry : weak< JournalCodexEntry >;
		var mappinPosition : Vector3;
		var mappinLinkAdded : Bool;
		var i : Int32;
		var codexLinksSpawned : Int32;
		var unpackFilter : JournalRequestStateFilter;
		unpackFilter.active = true;
		unpackFilter.inactive = true;
		QuestLogUtils.UnpackRecursiveWithFilter( m_journalManager, objective, unpackFilter, childEntries, true );
		inkCompoundRef.RemoveAllChildren( m_codexLinksContainer );
		inkCompoundRef.RemoveAllChildren( m_missionLinksContainer );
		inkCompoundRef.RemoveAllChildren( m_mapLinksContainer );
		inkCompoundRef.SetVisible( m_codexLinkLine, false );
		inkCompoundRef.SetVisible( m_missionLinkLine, false );
		for( i = 0; i < childEntries.Size(); i += 1 )
		{
			if( ( ( JournalQuestMapPinBase )( childEntries[ i ] ) ) )
			{
				if( !( mappinLinkAdded ) )
				{
					childEntriesSorted.Insert( 0, childEntries[ i ] );
					mappinLinkAdded = true;
				}
			}
			else
			{
				codexLink = ( ( JournalQuestCodexLink )( childEntries[ i ] ) );
				childEntry = ( ( JournalEntry )( m_journalManager.GetEntry( codexLink.GetLinkPathHash() ) ) );
				childEntryState = m_journalManager.GetEntryState( childEntry );
				if( childEntryState == gameJournalEntryState.Succeeded || childEntryState == gameJournalEntryState.Failed )
				{
					childEntriesSorted.PushBack( childEntries[ i ] );
				}
				else
				{
					childEntriesSorted.Insert( 0, childEntries[ i ] );
				}
			}
		}
		for( i = 0; i < childEntriesSorted.Size(); i += 1 )
		{
			codexLink = ( ( JournalQuestCodexLink )( childEntriesSorted[ i ] ) );
			if( codexLink )
			{
				childEntry = ( ( JournalEntry )( m_journalManager.GetEntry( codexLink.GetLinkPathHash() ) ) );
				childEntryState = m_journalManager.GetEntryState( childEntry );
				if( ( ( childEntryState == gameJournalEntryState.Inactive && !( ( ( JournalPhoneMessage )( childEntry ) ) ) ) && !( ( ( JournalOnscreen )( childEntry ) ) ) ) && !( ( ( JournalQuest )( childEntry ) ) ) )
				{
					childEntryHash = m_journalManager.GetEntryHash( childEntry );
					m_journalManager.ChangeEntryStateByHash( ( ( Uint32 )( childEntryHash ) ), gameJournalEntryState.Active, JournalNotifyOption.DoNotNotify );
				}
				if( ( ( JournalCodexEntry )( childEntry ) ) && ( codexLinksSpawned < 4 ) )
				{
					replacerEntry = CodexUtils.GetCodexReplacementRecord( m_journalManager, ( ( JournalCodexEntry )( childEntry ) ) );
					SpawnCodexLink( childEntry, replacerEntry );
					inkCompoundRef.SetVisible( m_codexLinkLine, true );
					codexLinksSpawned += 1;
				}
				else if( ( ( JournalQuest )( childEntry ) ) && childEntryState != gameJournalEntryState.Inactive )
				{
					SpawnQuestLink( ( ( JournalQuest )( childEntry ) ) );
					inkCompoundRef.SetVisible( m_missionLinkLine, true );
				}
			}
			else if( ( ( JournalImageEntry )( childEntriesSorted[ i ] ) ) && ( codexLinksSpawned < 4 ) )
			{
				SpawnCodexLink( childEntriesSorted[ i ] );
				codexLinksSpawned += 1;
			}
			else if( ( ( JournalQuestMapPinBase )( childEntriesSorted[ i ] ) ) )
			{
				m_mappinSystem.GetQuestMappinPosition( ( ( Uint32 )( m_journalManager.GetEntryHash( childEntriesSorted[ i ] ) ) ), mappinPosition );
				SpawnMappinLink( ( ( JournalQuestMapPinBase )( childEntriesSorted[ i ] ) ), mappinPosition, m_trackedObjective == objective );
			}
		}
	}

	public function CalcObjectiveActionsCount( entry : weak< JournalContainerEntry > ) : Int32
	{
		var codexLink : weak< JournalQuestCodexLink >;
		var childEntries : array< weak< JournalEntry > >;
		var childEntry : weak< JournalEntry >;
		var i, objectiveActionsCount : Int32;
		var unpackFilter : JournalRequestStateFilter;
		unpackFilter.active = true;
		unpackFilter.inactive = false;
		objectiveActionsCount = 0;
		QuestLogUtils.UnpackRecursiveWithFilter( m_journalManager, entry, unpackFilter, childEntries, true );
		for( i = 0; i < childEntries.Size(); i += 1 )
		{
			codexLink = ( ( JournalQuestCodexLink )( childEntries[ i ] ) );
			if( codexLink )
			{
				childEntry = ( ( JournalEntry )( m_journalManager.GetEntry( codexLink.GetLinkPathHash() ) ) );
				if( ( ( JournalContact )( childEntry ) ) && m_canUsePhone )
				{
					objectiveActionsCount += 1;
				}
				else if( ( ( ( JournalPhoneMessage )( childEntry ) ) || ( ( JournalPhoneChoiceGroup )( childEntry ) ) ) || ( ( JournalPhoneConversation )( childEntry ) ) )
				{
					objectiveActionsCount += 1;
				}
				else if( ( ( JournalOnscreen )( childEntry ) ) )
				{
					objectiveActionsCount += 1;
				}
			}
		}
		return objectiveActionsCount;
	}

	public function PopulateObjectiveActionLinks( trackedObjective : JournalQuestObjective, container : inkCompoundRef )
	{
		var codexLink : weak< JournalQuestCodexLink >;
		var childEntries : array< weak< JournalEntry > >;
		var childEntry : weak< JournalEntry >;
		var i : Int32;
		var unpackFilter : JournalRequestStateFilter;
		var enableInput : Bool;
		unpackFilter.active = true;
		unpackFilter.inactive = true;
		QuestLogUtils.UnpackRecursiveWithFilter( m_journalManager, trackedObjective, unpackFilter, childEntries, true );
		enableInput = m_objectiveActionsCount < 2;
		for( i = 0; i < childEntries.Size(); i += 1 )
		{
			codexLink = ( ( JournalQuestCodexLink )( childEntries[ i ] ) );
			if( codexLink )
			{
				childEntry = ( ( JournalEntry )( m_journalManager.GetEntry( codexLink.GetLinkPathHash() ) ) );
				if( ( ( JournalContact )( childEntry ) ) && m_canUsePhone )
				{
					SpawnContactLink( ( ( JournalContact )( childEntry ) ), container, enableInput );
				}
				else if( ( ( ( JournalPhoneMessage )( childEntry ) ) || ( ( JournalPhoneChoiceGroup )( childEntry ) ) ) || ( ( JournalPhoneConversation )( childEntry ) ) )
				{
					SpawnMessageLink( ( ( weak< weak< JournalEntry > > )( childEntry ) ), container, enableInput );
				}
				else if( ( ( JournalOnscreen )( childEntry ) ) )
				{
					SpawnShardLink( ( ( JournalOnscreen )( childEntry ) ), container, enableInput );
				}
			}
		}
	}

	private function SpawnMappinLink( mappinEntry : JournalQuestMapPinBase, jumpTo : Vector3, isTracked : Bool )
	{
		var widget : weak< inkWidget >;
		var controller : QuestMappinLinkController;
		widget = SpawnFromLocal( inkCompoundRef.Get( m_mapLinksContainer ), 'linkMappin' );
		controller = ( ( QuestMappinLinkController )( widget.GetController() ) );
		controller.Setup( mappinEntry, m_journalManager.GetEntryHash( mappinEntry ), jumpTo, isTracked );
	}

	private function SpawnCodexLink( journalEntry : JournalEntry, optional journalEntryReplacer : JournalEntry )
	{
		var widget : weak< inkWidget >;
		var controller : QuestCodexLinkController;
		widget = SpawnFromLocal( inkCompoundRef.Get( m_codexLinksContainer ), 'linkCodex' );
		controller = ( ( QuestCodexLinkController )( widget.GetController() ) );
		controller.Setup( journalEntry, journalEntryReplacer );
	}

	private function SpawnQuestLink( journalEntry : JournalQuest )
	{
		var widget : weak< inkWidget >;
		var controller : QuestMissionLinkController;
		widget = SpawnFromLocal( inkCompoundRef.Get( m_missionLinksContainer ), 'linkQuest' );
		widget.SetHAlign( inkEHorizontalAlign.Right );
		widget.SetVAlign( inkEVerticalAlign.Top );
		controller = ( ( QuestMissionLinkController )( widget.GetController() ) );
		controller.Setup( journalEntry, m_journalManager );
	}

	private function SpawnContactLink( contactEntry : JournalContact, container : inkCompoundRef, inputEnabled : Bool )
	{
		var widget : weak< inkWidget >;
		var controller : QuestContactLinkController;
		widget = SpawnFromLocal( inkCompoundRef.Get( container ), 'linkPhoneContact' );
		widget.SetHAlign( inkEHorizontalAlign.Right );
		widget.SetVAlign( inkEVerticalAlign.Top );
		controller = ( ( QuestContactLinkController )( widget.GetController() ) );
		controller.Setup( contactEntry, m_journalManager, m_phoneSystem, m_uiSystem );
		controller.EnableInputHint( inputEnabled );
	}

	private function SpawnMessageLink( childEntry : weak< JournalEntry >, container : inkCompoundRef, inputEnabled : Bool )
	{
		var widget : weak< inkWidget >;
		var controller : QuestMessageLinkController;
		widget = SpawnFromLocal( inkCompoundRef.Get( container ), 'linkMessageEntry' );
		widget.SetHAlign( inkEHorizontalAlign.Left );
		widget.SetVAlign( inkEVerticalAlign.Top );
		widget.SetMargin( m_objectiveActionOffset, 0.0, 0.0, 0.0 );
		controller = ( ( QuestMessageLinkController )( widget.GetController() ) );
		controller.Setup( childEntry, m_journalManager, m_phoneSystem );
		controller.EnableInputHint( inputEnabled );
	}

	private function SpawnShardLink( journalEntry : JournalOnscreen, container : inkCompoundRef, inputEnabled : Bool )
	{
		var widget : weak< inkWidget >;
		var controller : QuestShardLinkController;
		widget = SpawnFromLocal( inkCompoundRef.Get( container ), 'linkShardEntry' );
		widget.SetHAlign( inkEHorizontalAlign.Left );
		widget.SetVAlign( inkEVerticalAlign.Top );
		widget.SetMargin( m_objectiveActionOffset, 0.0, 0.0, 0.0 );
		controller = ( ( QuestShardLinkController )( widget.GetController() ) );
		controller.Setup( journalEntry, m_journalManager );
		controller.EnableInputHint( inputEnabled );
	}

	private function SpawnFluffShardLink( journalEntry : JournalOnscreen )
	{
		var widget : weak< inkWidget >;
		var controller : QuestShardLinkController;
		widget = SpawnFromLocal( inkCompoundRef.Get( m_fluffLinksContainer ), 'linkFluffShard' );
		controller = ( ( QuestShardLinkController )( widget.GetController() ) );
		controller.Setup( journalEntry, m_journalManager );
	}

}

