class GamplayQuestData extends IScriptable
{
	var m_questUniqueID : String;
	var m_objectives : array< GemplayObjectiveData >;

	public const function GetFreeObjectivePath() : String
	{
		return ( GetPhaseEntryID() + "/" ) + GetFreeObjectiveEntryID();
	}

	public const function GetbjectivePath( objectiveData : GemplayObjectiveData ) : String
	{
		return ( GetPhaseEntryID() + "/" ) + objectiveData.GetObjectiveEntryID();
	}

	public const function GetFreeObjectiveEntryID() : String
	{
		var sufix : String;
		if( m_objectives.Size() > 0 )
		{
			sufix = ( ( String )( m_objectives.Size() ) );
		}
		return GetBaseObjectiveEntryID() + sufix;
	}

	public function AddObjective( objectiveData : GemplayObjectiveData, journal : JournalManager )
	{
		if( HasObjective( objectiveData ) )
		{
			return;
		}
		if( CreateObjective( objectiveData, journal ) )
		{
			m_objectives.PushBack( objectiveData );
			SetObjectiveState( objectiveData, journal, gameJournalEntryState.Active );
		}
	}

	public const function HasObjective( objectiveData : GemplayObjectiveData ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_objectives.Size(); i += 1 )
		{
			if( ( m_objectives[ i ].GetOwnerID() == objectiveData.GetOwnerID() ) && m_objectives[ i ].GetClassName() == objectiveData.GetClassName() )
			{
				return true;
			}
		}
		return false;
	}

	public const function GetObjective( objectiveData : GemplayObjectiveData ) : GemplayObjectiveData
	{
		var i : Int32;
		for( i = 0; i < m_objectives.Size(); i += 1 )
		{
			if( ( m_objectives[ i ].GetOwnerID() == objectiveData.GetOwnerID() ) && m_objectives[ i ].GetClassName() == objectiveData.GetClassName() )
			{
				return m_objectives[ i ];
			}
		}
		return NULL;
	}

	private function CreateObjective( objectiveData : GemplayObjectiveData, journal : JournalManager ) : Bool
	{
		var isValid : Bool;
		var mappinData : MappinData;
		var objectivePath : String;
		var mappinPath : String;
		objectivePath = GetFreeObjectivePath();
		isValid = journal.SetScriptedQuestObjectiveDescription( GetQuestEntryID(), objectiveData.GetUniqueID(), objectivePath, objectiveData.GetObjectiveDescription() );
		if( !( isValid ) )
		{
			return false;
		}
		mappinPath = GetFreeQuestMappinPath();
		isValid = journal.SetScriptedQuestMappinEntityID( GetQuestEntryID(), objectiveData.GetUniqueID(), mappinPath, objectiveData.GetOwnerID() );
		if( !( isValid ) )
		{
			return false;
		}
		mappinData.mappinType = T"Mappins.QuestStaticMappinDefinition";
		mappinData.variant = gamedataMappinVariant.DefaultQuestVariant;
		objectiveData.SetObjectiveEntryID( GetFreeObjectiveEntryID() );
		journal.SetScriptedQuestMappinSlotName( GetQuestEntryID(), objectiveData.GetUniqueID(), mappinPath, T"AttachmentSlots.QuestDeviceMappin" );
		journal.SetScriptedQuestMappinData( GetQuestEntryID(), objectiveData.GetUniqueID(), GetFreeQuestMappinPath(), mappinData );
		return true;
	}

	public function SetObjectiveState( objectiveData : GemplayObjectiveData, journal : JournalManager, state : gameJournalEntryState )
	{
		var objective : GemplayObjectiveData;
		var track : Bool;
		objective = GetObjective( objectiveData );
		if( objective == NULL )
		{
			return;
		}
		if( state == gameJournalEntryState.Active )
		{
			track = true;
		}
		journal.SetScriptedQuestEntryState( GetQuestEntryID(), objectiveData.GetUniqueID(), GetbjectivePath( objectiveData ), state, JournalNotifyOption.Notify, track );
		objective.SetObjectiveState( state );
	}

	public const function IsCompleted() : Bool
	{
		var i : Int32;
		for( i = 0; i < m_objectives.Size(); i += 1 )
		{
			if( m_objectives[ i ].GetObjectiveState() != gameJournalEntryState.Inactive )
			{
				return false;
			}
		}
		return true;
	}

	public constexpr const function GetQuestEntryID() : String
	{
		return "generic_gameplay_quest";
	}

	public constexpr const function GetPhaseEntryID() : String
	{
		return "generic_gameplay_phase";
	}

	public constexpr const function GetBaseObjectiveEntryID() : String
	{
		return "generic_gameplay_objective";
	}

	public constexpr const function GetMappinEntryID() : String
	{
		return "generic_gameplay_mappin";
	}

	public const function GetFreeQuestMappinPath() : String
	{
		return ( ( ( GetPhaseEntryID() + "/" ) + GetFreeObjectiveEntryID() ) + "/" ) + GetMappinEntryID();
	}

}

class RegisterGameplayObjectiveRequest extends ScriptableSystemRequest
{
	var objectiveData : GemplayObjectiveData;
}

class SetGameplayObjectiveStateRequest extends ScriptableSystemRequest
{
	var objectiveData : GemplayObjectiveData;
	var objectiveState : gameJournalEntryState;
}

class GameplayQuestSystem extends ScriptableSystem
{
	private var m_quests : array< GamplayQuestData >;

	private function OnRegisterObjective( request : RegisterGameplayObjectiveRequest )
	{
		AddObjective( request.objectiveData );
	}

	private function OnSetObjectiveState( request : SetGameplayObjectiveStateRequest )
	{
		SetObjectiveState( request.objectiveData, request.objectiveState );
	}

	private function AddObjective( objectiveData : GemplayObjectiveData )
	{
		var questData : GamplayQuestData;
		questData = GetQuestData( objectiveData );
		questData.AddObjective( objectiveData, GetJournal() );
	}

	private function SetObjectiveState( objectiveData : GemplayObjectiveData, objectiveState : gameJournalEntryState )
	{
		var questData : GamplayQuestData;
		questData = GetQuestData( objectiveData );
		questData.SetObjectiveState( objectiveData, GetJournal(), objectiveState );
		EvaluateQuest( questData );
	}

	private function HasQuest( const questUniqueId : ref< String > ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_quests.Size(); i += 1 )
		{
			if( m_quests[ i ].m_questUniqueID == questUniqueId )
			{
				return true;
			}
		}
		return false;
	}

	private function GetQuestData( objectiveData : GemplayObjectiveData ) : GamplayQuestData
	{
		var i : Int32;
		var questData : GamplayQuestData;
		for( i = 0; i < m_quests.Size(); i += 1 )
		{
			if( m_quests[ i ].m_questUniqueID == objectiveData.GetUniqueID() )
			{
				questData = m_quests[ i ];
			}
		}
		if( questData == NULL )
		{
			questData = CreateQuest( objectiveData );
		}
		return questData;
	}

	private function CreateQuest( objectiveData : GemplayObjectiveData ) : GamplayQuestData
	{
		var questData : GamplayQuestData;
		var isValid : Bool;
		questData = new GamplayQuestData;
		isValid = GetJournal().CreateScriptedQuestFromTemplate( questData.GetQuestEntryID(), objectiveData.GetUniqueID(), objectiveData.GetQuestTitle() );
		if( isValid )
		{
			questData.m_questUniqueID = objectiveData.GetUniqueID();
			m_quests.PushBack( questData );
			return questData;
		}
		else
		{
			return NULL;
		}
	}

	private function EvaluateQuest( questData : GamplayQuestData )
	{
		if( questData.IsCompleted() )
		{
			if( RemoveQuest( questData ) )
			{
				m_quests.Remove( questData );
				questData = NULL;
			}
		}
	}

	private function RemoveQuest( questData : GamplayQuestData ) : Bool
	{
		return GetJournal().DeleteScriptedQuest( questData.GetQuestEntryID(), questData.m_questUniqueID );
	}

	private const function GetJournal() : JournalManager
	{
		return GameInstance.GetJournalManager( GetGameInstance() );
	}

}

