class JournalWrapper extends ABaseWrapper
{
	private var m_journalManager : weak< JournalManager >;
	private var m_journalContext : JournalRequestContext;
	private var m_journalSubQuestContext : JournalRequestContext;
	private var m_listOfJournalEntries : array< weak< JournalEntry > >;
	private var m_gameInstance : GameInstance;

	public function Init( gameInstance : GameInstance )
	{
		m_gameInstance = gameInstance;
		m_journalManager = GameInstance.GetJournalManager( gameInstance );
		m_journalContext.stateFilter.active = true;
		m_journalContext.stateFilter.succeeded = true;
		m_journalContext.stateFilter.failed = true;
		m_journalSubQuestContext.stateFilter.inactive = true;
		m_journalSubQuestContext.stateFilter.active = true;
		m_journalSubQuestContext.stateFilter.succeeded = true;
		m_journalSubQuestContext.stateFilter.failed = true;
	}

	public function GetJournalManager() : weak< JournalManager >
	{
		return m_journalManager;
	}

	public function GetQuests( out entries : array< weak< JournalEntry > > )
	{
		m_journalManager.GetQuests( m_journalContext, entries );
	}

	private function BuildQuestData_Recursive( currEntity : weak< JournalEntry >, out description : String, out questObjectives : array< QuestObjectiveWrapper >, out links : array< weak< JournalEntry > >, foundTracked : Bool )
	{
		var i : Int32;
		var linkPathHash : Uint32;
		var listEntries : array< weak< JournalEntry > >;
		var currEntry : weak< JournalEntry >;
		var descriptionEntry : weak< JournalQuestDescription >;
		var linkEntry : weak< JournalQuestCodexLink >;
		var questObjective : weak< JournalQuestObjective >;
		var questSubObjective : weak< JournalQuestSubObjective >;
		var currQuestObjectiveWrapper : QuestObjectiveWrapper;
		var isTrackedEntry : Bool;
		questObjective = ( ( JournalQuestObjective )( currEntity ) );
		questSubObjective = ( ( JournalQuestSubObjective )( currEntity ) );
		if( questObjective )
		{
			m_journalManager.GetChildren( currEntity, m_journalSubQuestContext.stateFilter, listEntries );
		}
		else if( questSubObjective )
		{
			m_journalManager.GetChildren( currEntity, m_journalSubQuestContext.stateFilter, listEntries );
		}
		else
		{
			m_journalManager.GetChildren( currEntity, m_journalContext.stateFilter, listEntries );
		}
		for( i = 0; i < listEntries.Size(); i += 1 )
		{
			currEntry = listEntries[ i ];
			if( !( currEntry ) )
			{
				continue;
			}
			if( !( foundTracked ) )
			{
				isTrackedEntry = GetTrackingStatus( currEntry );
			}
			else
			{
				isTrackedEntry = false;
			}
			descriptionEntry = ( ( JournalQuestDescription )( currEntry ) );
			linkEntry = ( ( JournalQuestCodexLink )( currEntry ) );
			questObjective = ( ( JournalQuestObjective )( currEntry ) );
			questSubObjective = ( ( JournalQuestSubObjective )( currEntry ) );
			if( descriptionEntry )
			{
				description += ( descriptionEntry.GetDescription() + "\n" );
			}
			if( linkEntry )
			{
				linkPathHash = linkEntry.GetLinkPathHash();
				links.PushBack( m_journalManager.GetEntry( linkPathHash ) );
			}
			else if( questObjective )
			{
				currQuestObjectiveWrapper = new QuestObjectiveWrapper;
				currQuestObjectiveWrapper.Init( questObjective, m_journalManager.GetEntryState( questObjective ), isTrackedEntry, m_journalManager.GetEntryHash( questObjective ), m_journalManager.GetObjectiveCurrentCounter( questObjective ), m_journalManager.GetObjectiveTotalCounter( questObjective ) );
				questObjectives.PushBack( currQuestObjectiveWrapper );
			}
			else if( questSubObjective )
			{
				currQuestObjectiveWrapper = questObjectives.Last();
				currQuestObjectiveWrapper.AddSubObjective( questSubObjective, m_journalManager.GetEntryState( questSubObjective ), isTrackedEntry, m_journalManager.GetEntryHash( questSubObjective ) );
			}
			BuildQuestData_Recursive( currEntry, description, questObjectives, links, isTrackedEntry || foundTracked );
		}
	}

	public function BuildQuestData( currQuest : weak< JournalQuest > ) : QuestDataWrapper
	{
		var questData : QuestDataWrapper;
		var title : String;
		var descriptionString : String;
		var questObjectives : array< QuestObjectiveWrapper >;
		var foundTracked : Bool;
		var links : array< weak< JournalEntry > >;
		var recommendedLevel : Int32;
		descriptionString = "";
		if( currQuest )
		{
			foundTracked = GetTrackingStatus( ( ( JournalEntry )( currQuest ) ) );
			BuildQuestData_Recursive( currQuest, descriptionString, questObjectives, links, foundTracked );
		}
		title = currQuest.GetTitle( m_journalManager );
		questData = new QuestDataWrapper;
		recommendedLevel = GameInstance.GetLevelAssignmentSystem( m_gameInstance ).GetLevelAssignment( currQuest.GetRecommendedLevelID() );
		questData.Init( m_journalManager, currQuest, title, descriptionString, links, questObjectives, m_journalManager.GetEntryState( currQuest ), foundTracked, m_journalManager.GetEntryHash( currQuest ), recommendedLevel, !( IsVisited( ( ( JournalEntry )( currQuest ) ) ) ), m_journalManager.GetDistrict( currQuest ) );
		return questData;
	}

	public function GetTrackedEntry() : weak< JournalEntry >
	{
		return m_journalManager.GetTrackedEntry();
	}

	public function GetTrackingStatus( entry : weak< JournalEntry > ) : Bool
	{
		var trackedEntry : weak< JournalEntry >;
		trackedEntry = GetTrackedEntry();
		return trackedEntry && ( m_journalManager.GetEntryHash( trackedEntry ) == m_journalManager.GetEntryHash( entry ) );
	}

	public function SetTracking( entry : weak< JournalEntry > )
	{
		if( entry && m_journalManager.GetEntryState( entry ) == gameJournalEntryState.Active )
		{
			m_journalManager.TrackEntry( entry );
		}
	}

	public function SetVisited( entry : weak< JournalEntry > )
	{
		if( entry && !( m_journalManager.IsEntryVisited( entry ) ) )
		{
			m_journalManager.SetEntryVisited( entry, true );
		}
	}

	public function IsVisited( entry : weak< JournalEntry > ) : Bool
	{
		if( entry )
		{
			return m_journalManager.IsEntryVisited( entry );
		}
		return true;
	}

	public function UpdateQuestData( toUpdate : QuestDataWrapper ) : QuestDataWrapper
	{
		var i, limit : Int32;
		var questEntries : array< weak< JournalEntry > >;
		var questEntry : weak< JournalQuest >;
		GetQuests( questEntries );
		for( i = 0, limit = questEntries.Size(); i < limit; i += 1 )
		{
			questEntry = ( ( JournalQuest )( questEntries[ i ] ) );
			if( questEntry && toUpdate.Equals( m_journalManager.GetEntryHash( questEntry ) ) )
			{
				return BuildQuestData( questEntry );
			}
		}
		return NULL;
	}

	public function GetDescriptionForCodexEntry( entry : weak< JournalCodexEntry >, out result : array< weak< JournalEntry > > )
	{
		m_journalManager.GetChildren( entry, m_journalContext.stateFilter, result );
	}

	public function GetEntryHash( entry : weak< JournalEntry > ) : Int32
	{
		return m_journalManager.GetEntryHash( entry );
	}

}

class QuestDataWrapper extends AJournalEntryWrapper
{
	private var m_isNew : Bool;
	private var m_quest : weak< JournalQuest >;
	private var m_title : String;
	private var m_description : String;
	private var m_questObjectives : array< QuestObjectiveWrapper >;
	private var m_links : array< weak< JournalEntry > >;
	private var m_questStatus : gameJournalEntryState;
	private var m_isTracked : Bool;
	private var m_isChildTracked : Bool;
	private var m_recommendedLevel : Int32;
	private var m_district : District_Record;
	private var m_journalManager : weak< JournalManager >;

	public function Init( journalManager : weak< JournalManager >, currQuest : weak< JournalQuest >, const title : ref< String >, const description : ref< String >, const links : ref< array< weak< JournalEntry > > >, const questObjectives : ref< array< QuestObjectiveWrapper > >, questStatus : gameJournalEntryState, isTracked : Bool, uniqueId : Int32, recommendedLevel : Int32, isNew : Bool, district : District_Record )
	{
		SetUniqueId( uniqueId );
		m_quest = currQuest;
		m_title = title;
		m_description = description;
		m_links = links;
		m_questObjectives = questObjectives;
		m_questStatus = questStatus;
		m_isTracked = isTracked;
		m_recommendedLevel = recommendedLevel;
		m_isNew = isNew;
		m_district = district;
		m_journalManager = journalManager;
	}

	public function GetDistrict() : gamedataDistrict
	{
		return m_district.Type();
	}

	public function GetType() : gameJournalQuestType
	{
		return m_quest.GetType();
	}

	public function GetId() : String
	{
		return m_quest.GetId();
	}

	public function GetQuest() : weak< JournalQuest >
	{
		return m_quest;
	}

	public function GetStatus() : gameJournalEntryState
	{
		return m_questStatus;
	}

	public function GetDescription() : String
	{
		return m_description;
	}

	public function GetLinks() : array< weak< JournalEntry > >
	{
		return m_links;
	}

	public function GetObjectives() : array< QuestObjectiveWrapper >
	{
		return m_questObjectives;
	}

	public function GetTitle() : String
	{
		return m_title;
	}

	public function GetLevel() : Int32
	{
		return m_recommendedLevel;
	}

	public constexpr function HasBriefing() : Bool
	{
		return false;
	}

	public override function ToString() : String
	{
		return "[QuestDataWrapper] Id: " + GetId();
	}

	public function Equals( questData : QuestDataWrapper ) : Bool
	{
		return Equals( questData.GetUniqueId() );
	}

	public function Equals( questUniqueId : Int32 ) : Bool
	{
		return GetUniqueId() == questUniqueId;
	}

	public function IsTracked() : Bool
	{
		return m_isTracked;
	}

	public function IsTrackedInHierarchy() : Bool
	{
		var i, limit : Int32;
		var currObjective : QuestObjectiveWrapper;
		for( i = 0, limit = m_questObjectives.Size(); i < limit; i += 1 )
		{
			currObjective = m_questObjectives[ i ];
			if( currObjective.IsTracked() || currObjective.IsTrackedInHierarchy() )
			{
				return true;
			}
		}
		return false;
	}

	public function IsOptional() : Bool
	{
		var i, limit : Int32;
		var currObjective : QuestObjectiveWrapper;
		for( i = 0, limit = m_questObjectives.Size(); i < limit; i += 1 )
		{
			currObjective = m_questObjectives[ i ];
			if( m_journalManager.GetIsObjectiveOptional( currObjective.GetQuestObjective() ) )
			{
				return true;
			}
		}
		return false;
	}

	public function IsNew() : Bool
	{
		return m_isNew;
	}

	public function UpdateIsNew( value : Bool )
	{
		m_isNew = value;
	}

}

abstract class ABaseQuestObjectiveWrapper extends AJournalEntryWrapper
{
	protected var m_questObjective : weak< JournalQuestObjectiveBase >;
	protected var m_objectiveStatus : gameJournalEntryState;
	protected var m_isTracked : Bool;
	protected var m_currentCounter : Int32;
	protected var m_totalCounter : Int32;

	public function Init( questObjective : weak< JournalQuestObjectiveBase >, objectiveStatus : gameJournalEntryState, isTracked : Bool, uniqueId : Int32, currentCounter : Int32, totalCounter : Int32 )
	{
		SetUniqueId( uniqueId );
		m_questObjective = questObjective;
		m_objectiveStatus = objectiveStatus;
		m_isTracked = isTracked;
		m_currentCounter = currentCounter;
		m_totalCounter = totalCounter;
	}

	public function GetDescription() : String
	{
		return m_questObjective.GetDescription();
	}

	public function GetStatus() : gameJournalEntryState
	{
		return m_objectiveStatus;
	}

	public function IsActive() : Bool
	{
		return GetStatus() == gameJournalEntryState.Active;
	}

	public function GetQuestObjective() : weak< JournalQuestObjectiveBase >
	{
		return m_questObjective;
	}

	public function IsTracked() : Bool
	{
		return m_isTracked;
	}

	public virtual function IsTrackedInHierarchy() : Bool
	{
		return false;
	}

	public function GetCounterText() : String
	{
		var counterText : String;
		if( m_totalCounter > 0 )
		{
			counterText = ( ( ( " [" + ( ( String )( m_currentCounter ) ) ) + "/" ) + ( ( String )( m_totalCounter ) ) ) + "]";
		}
		return counterText;
	}

}

class QuestObjectiveWrapper extends ABaseQuestObjectiveWrapper
{
	private var m_questSubObjectives : array< QuestSubObjectiveWrapper >;

	public function AddSubObjective( questSubObjective : weak< JournalQuestSubObjective >, subObjectiveStatus : gameJournalEntryState, isTracked : Bool, uniqueId : Int32 )
	{
		var currQuestSubObjectiveWrapper : QuestSubObjectiveWrapper;
		currQuestSubObjectiveWrapper = new QuestSubObjectiveWrapper;
		currQuestSubObjectiveWrapper.Init( questSubObjective, subObjectiveStatus, isTracked, uniqueId, 0, 0 );
		m_questSubObjectives.PushBack( currQuestSubObjectiveWrapper );
	}

	public function GetSubObjectives() : array< QuestSubObjectiveWrapper >
	{
		return m_questSubObjectives;
	}

	public override function IsTrackedInHierarchy() : Bool
	{
		var i, limit : Int32;
		for( i = 0, limit = m_questSubObjectives.Size(); i < limit; i += 1 )
		{
			if( m_questSubObjectives[ i ].IsTracked() )
			{
				return true;
			}
		}
		return false;
	}

}

class QuestSubObjectiveWrapper extends ABaseQuestObjectiveWrapper
{

	public override function ToString() : String
	{
		return "[QuestSubObjectiveWrapper] Description: " + GetDescription();
	}

}

abstract class AJournalEntryWrapper extends ABaseWrapper
{
	private var m_UniqueId : Int32;

	public function SetUniqueId( uniqueId : Int32 )
	{
		m_UniqueId = uniqueId;
	}

	public function GetUniqueId() : Int32
	{
		return m_UniqueId;
	}

}

abstract class ABaseWrapper extends IScriptable
{

	public virtual function ToString() : String
	{
		return "";
	}

}

