import enum gameMessageSender
{
	NPC,
	Player,
}

import enum gameContactType
{
	Caller,
	Texter,
}

importonly struct JournalRequestStateFilter
{
	import var inactive : Bool;
	import var active : Bool;
	import var succeeded : Bool;
	import var failed : Bool;
}

importonly struct JournalRequestContext
{
	import var stateFilter : JournalRequestStateFilter;

	public import static function CreatePlayerLevelBasedQuestRequestFilter( self : JournalRequestContext, gameInstance : GameInstance, percentMargin : Uint32 );
	public import static function CreateQuestTypeRequestFilter( self : JournalRequestContext, gameInstance : GameInstance, includeMainQuests : Bool, includeSideQuests : Bool, includeStreetStories : Bool, includeCyberPsycho : Bool, includeContracts : Bool );
	public import static function CreateQuestDistanceRequestFilter( self : JournalRequestContext, gameInstance : GameInstance, distance : Float );
}

importonly abstract class JournalEntry extends IScriptable
{
	public import const function GetId() : String;
	public import const function GetEditorName() : String;
	public import const function GetJournalEntryOverrideDataListCount() : Int32;
	public import const function GetJournalEntryOverrideDataList( out journalEntryOverrideDataList : array< JournalEntryOverrideData > );
}

importonly class JournalEntryOverrideData extends IScriptable
{
	import var inputDevice : InputDevice;
	import var inputScheme : InputScheme;

	public import const function GetOverriddenLocalizedText() : String;
}

importonly abstract class JournalContainerEntry extends JournalEntry
{
}

importonly abstract class JournalFileEntry extends JournalContainerEntry
{
}

importonly abstract class JournalQuestGuidanceMarker extends JournalEntry
{
}

importonly abstract class JournalQuestMapPinBase extends JournalContainerEntry
{
	public import const function GetCaption() : String;
}

importonly abstract class JournalQuestMapPin extends JournalQuestMapPinBase
{
}

importonly abstract class JournalQuestMapPinLink extends JournalEntry
{
}

importonly abstract class JournalQuestDescription extends JournalEntry
{
	public import const function GetDescription() : String;
}

importonly abstract class JournalQuestCodexLink extends JournalEntry
{
	public import const function GetLinkPathHash() : Uint32;
}

importonly abstract class JournalImageEntry extends JournalEntry
{
	public import const function GetImageID() : TweakDBID;
	public import const function GetThumbnailImageID() : TweakDBID;
}

importonly abstract class JournalQuestObjectiveBase extends JournalContainerEntry
{
	public import const function GetDescription() : String;
	public import const function HasCounter() : Bool;
	public import const function GetItemID() : TweakDBID;
}

importonly abstract class JournalQuestSubObjective extends JournalQuestObjectiveBase
{
}

importonly abstract class JournalQuestObjective extends JournalQuestObjectiveBase
{
}

importonly abstract class JournalQuestPhase extends JournalContainerEntry
{
}

importonly abstract class JournalPhoneChoiceGroup extends JournalContainerEntry
{
}

importonly abstract class JournalPhoneChoiceEntry extends JournalEntry
{
	public import const function GetText() : String;
	public import const function IsQuestImportant() : Bool;
}

importonly abstract class JournalPhoneMessage extends JournalEntry
{
	public import const function GetText() : String;
	public import const function GetSender() : gameMessageSender;
	public import const function GetAttachmentPathHash() : Uint32;
	public import const function GetImageID() : TweakDBID;
	public import const function IsQuestImportant() : Bool;
}

importonly abstract class JournalPhoneConversation extends JournalContainerEntry
{
	public import const function GetTitle() : String;
}

importonly abstract class JournalContact extends JournalFileEntry
{
	public import const function GetLocalizedName( journalManager : IJournalManager ) : String;
	public import const function IsKnown( journalManager : IJournalManager ) : Bool;
	public import const function GetAvatarID( journalManager : IJournalManager ) : TweakDBID;
	public import const function GetType() : gameContactType;
	public import const function ShouldUseFlatMessageLayout() : Bool;
	public import const function IsCallable( journalManager : IJournalManager ) : Bool;
}

import enum gameJournalQuestType
{
	MainQuest,
	SideQuest,
	MinorQuest,
	StreetStory,
	CyberPsycho,
	Contract,
	VehicleQuest,
	ApartmentQuest,
	CourierQuest,
	CourierSideQuest,
}

importonly abstract class JournalQuest extends JournalFileEntry
{
	public import const function GetTitle( journalManager : IJournalManager ) : String;
	public import const function GetType() : gameJournalQuestType;
	public import const function GetRecommendedLevel() : Int32;
	public import const function GetRecommendedLevelID() : TweakDBID;
}

import enum questJournalSizeEventType
{
	Maximize,
	Minimize,
}

import enum questJournalAlignmentEventType
{
	Left,
	Center,
	Right,
}

importonly abstract class JournalBriefingBaseSection extends JournalEntry
{
	public import const function GetType() : gameJournalBriefingContentType;
}

import enum gameJournalBriefingContentType
{
	MapLocation,
	VideoContent,
	Paperdoll,
}

importonly abstract class JournalBriefingMapSection extends JournalBriefingBaseSection
{
	public import const function GetMapLocation() : Vector4;
}

importonly abstract class JournalBriefingVideoSection extends JournalBriefingBaseSection
{
	public import const function GetVideoPath() : ResRef;
}

importonly abstract class JournalBriefingPaperDollSection extends JournalBriefingBaseSection
{
}

importonly abstract class JournalTarotGroup extends JournalFileEntry
{
}

importonly abstract class JournalTarot extends JournalEntry
{
	public import const function GetIndex() : Int32;
	public import const function GetImagePart() : CName;
	public import const function GetName() : String;
	public import const function GetDescription() : String;
}

importonly abstract class JournalCodexCategory extends JournalFileEntry
{
	public import const function GetCategoryName() : String;
}

importonly abstract class JournalCodexGroup extends JournalContainerEntry
{
	public import const function GetIsSorted() : Bool;
	public import const function GetGroupName() : String;
}

importonly abstract class JournalCodexEntry extends JournalContainerEntry
{
	public import const function GetTitle() : String;
	public import const function GetImageID() : TweakDBID;
	public import const function GetLinkImageID() : TweakDBID;
}

importonly abstract class JournalCodexDescription extends JournalEntry
{
	public import const function GetSubTitle() : String;
	public import const function GetTextContent() : String;
}

importonly abstract class JournalInternetBase extends IScriptable
{
	public import const function GetName() : CName;
	public import const function GetLinkAddress() : String;
	public import const function GetColor() : Color;
	public import const function GetHoverColor() : Color;
}

importonly class JournalInternetText extends JournalInternetBase
{
	public import const function GetText() : String;
}

importonly class JournalInternetRectangle extends JournalInternetBase
{
}

importonly class JournalInternetImage extends JournalInternetBase
{
	public import const function GetAtlasPath() : ResRef;
	public import const function GetTexturePart() : CName;
}

importonly class JournalInternetVideo extends JournalInternetBase
{
	public import const function GetVideoPath() : ResRef;
}

importonly class JournalInternetCanvas extends JournalInternetBase
{
	public import const function IsHidden() : Bool;
}

importonly struct JournalFactNameValue
{
	import var factName : CName;
	import var factValue : Int32;
}

importonly class JournalInternetPage extends JournalEntry
{
	public import const function GetAddress() : String;
	public import const function GetFactsToSet() : array< JournalFactNameValue >;
	public import const function GetWidgetPath() : ResRef;
	public import const function GetScale() : Float;
	public import const function IsAdditionallyFilledFromScripts() : Bool;
	public import const function GetTexts() : array< JournalInternetText >;
	public import const function GetRectangles() : array< JournalInternetRectangle >;
	public import const function GetImages() : array< JournalInternetImage >;
	public import const function GetVideos() : array< JournalInternetVideo >;
	public import const function GetCanvases() : array< JournalInternetCanvas >;
	public import const function ShouldReloadOnZoomIn() : Bool;
}

importonly class JournalInternetSite extends JournalFileEntry
{
	public import const function GetShortName() : String;
	public import const function IsIgnoredAtDesktop() : Bool;
	public import const function GetAtlasPath() : ResRef;
	public import const function GetTexturePart() : CName;
}

importonly class JournalOnscreen extends JournalEntry
{
	public import const function GetTitle() : String;
	public import const function GetDescription() : String;
	public import const function GetIconID() : TweakDBID;
}

importonly class JournalOnscreenGroup extends JournalFileEntry
{
}

importonly class JournalOnscreensStructuredGroup extends IScriptable
{
	public import const function GetTag() : CName;
	public import const function GetEntries() : array< weak< JournalOnscreen > >;
}

importonly class JournalEmail extends JournalEntry
{
	public import const function GetSender() : String;
	public import const function GetAddressee() : String;
	public import const function GetTitle() : String;
	public import const function GetContent() : String;
	public import const function GetVideoResourcePath() : ResRef;
	public import const function GetImageTweak() : TweakDBID;
}

importonly class JournalEmailGroup extends JournalFileEntry
{
}

importonly class JournalFile extends JournalEntry
{
	public import const function GetTitle() : String;
	public import const function GetContent() : String;
	public import const function GetVideoResourcePath() : ResRef;
	public import const function GetImageTweak() : TweakDBID;
}

importonly class JournalFileGroup extends JournalFileEntry
{
}

importonly class JournalMetaQuestObjective extends JournalEntry
{
	public import const function GetDescription() : String;
	public import const function GetProgressPercent() : Uint32;
	public import const function GetIconID() : TweakDBID;
}

importonly class JournalMetaQuest extends JournalFileEntry
{
	public import const function GetTitle() : String;
}

importonly abstract class IJournalManager extends IReplicatedGameSystem
{
}

importonly struct JournalMetaQuestScriptedData
{
	import var hidden : Bool;
	import var percent : Uint32;
	import var text : String;
}

class ContactData
{
	var id : String;
	var localizedName : String;
	var localizedPreview : String;
	var avatarID : TweakDBID;
	var questRelated : Bool;
	var hasQuestImportantReply : Bool;
	var hasMessages : Bool;
	var unreadMessegeCount : Int32;
	var unreadMessages : array< Int32 >;
	var playerCanReply : Bool;
	var playerIsLastSender : Bool;
	var lastMesssagePreview : String;
	var activeDataSync : weak< MessengerContactSyncData >;
	var threadsCount : Int32;
	var timeStamp : GameTime;
	var hash : Int32;
	var conversationHash : Int32;
	var type : MessengerContactType;
	var hasValidTitle : Bool;
	var isCallable : Bool;
	var contactId : String;
	var messagesCount : Int32;
	var repliesCount : Int32;
}

import final class JournalManager extends IJournalManager
{
	public import const function GetQuests( context : JournalRequestContext, out entries : array< weak< JournalEntry > > );
	public import const function GetMetaQuests( context : JournalRequestContext, out entries : array< weak< JournalEntry > > );
	public import const function GetContacts( context : JournalRequestContext, out entries : array< weak< JournalEntry > > );
	public import const function GetFlattenedMessagesAndChoices( contactEntry : weak< JournalEntry >, out messages : array< weak< JournalEntry > >, out choiceEntries : array< weak< JournalEntry > > );
	public import const function GetMessagesAndChoices( conversationEntry : weak< JournalEntry >, out messages : array< weak< JournalEntry > >, out choiceEntries : array< weak< JournalEntry > > );
	public import const function GetConversations( contactEntry : weak< JournalEntry >, out conversations : array< weak< JournalEntry > > );
	public import const function GetTarots( context : JournalRequestContext, out entries : array< weak< JournalEntry > > );
	public import const function GetInternetSites( context : JournalRequestContext, out entries : array< weak< JournalEntry > > );
	public import const function GetInternetPages( context : JournalRequestContext, out entries : array< weak< JournalEntry > > );
	public import const function GetMainInternetPage( siteEntry : weak< JournalInternetSite > ) : weak< JournalInternetPage >;
	public import const function GetCodexCategories( context : JournalRequestContext, out entries : array< weak< JournalEntry > > );
	public import const function GetOnscreens( context : JournalRequestContext, out entries : array< JournalOnscreensStructuredGroup >, optional fallbackGroupName : CName );
	public import const function GetBriefings( context : JournalRequestContext, out entries : array< weak< JournalEntry > > );
	public import const function GetChildren( parentEntry : weak< JournalEntry >, filter : JournalRequestStateFilter, out childEntries : array< weak< JournalEntry > > );
	public import const function GetRandomChildren( parentEntry : weak< JournalEntry >, filter : JournalRequestStateFilter, childCount : Int32, out childEntries : array< weak< JournalEntry > > );
	public import const function GetParentEntry( childEntry : weak< JournalEntry > ) : weak< JournalEntry >;
	public import const function GetEntry( hash : Uint32 ) : weak< JournalEntry >;
	public import const function GetEntryByString( uniquePath : String, className : String ) : weak< JournalEntry >;
	public import const function GetEntryState( entry : weak< JournalEntry > ) : gameJournalEntryState;
	public import const function GetEntryTimestamp( entry : weak< JournalEntry > ) : GameTime;
	public import const function IsEntryVisited( entry : weak< JournalEntry > ) : Bool;
	public import function SetEntryVisited( entry : weak< JournalEntry >, value : Bool );
	public import const function IsEp1Entry( entry : weak< JournalEntry > ) : Bool;
	public import const function GetEntryHash( entry : weak< JournalEntry > ) : Int32;
	public import const function GetTrackedEntry() : weak< JournalEntry >;
	public import const function IsEntryTracked( entry : weak< JournalEntry > ) : Bool;
	public import function TrackEntry( entry : weak< JournalEntry > );
	public import function TrackPrevNextEntry( next : Bool );
	public import function UntrackEntry();
	public import function ChangeEntryState( uniquePath : String, className : String, state : gameJournalEntryState, notifyOption : JournalNotifyOption ) : Bool;
	public import function ChangeEntryStateByHash( hash : Uint32, state : gameJournalEntryState, notifyOption : JournalNotifyOption );
	public import const function HasAnyDelayedStateChanges() : Bool;
	public import const function GetObjectiveCurrentCounter( entry : weak< JournalQuestObjective > ) : Int32;
	public import const function GetObjectiveTotalCounter( entry : weak< JournalQuestObjective > ) : Int32;
	public import const function GetMetaQuestData( metaQuestId : gamedataMetaQuest ) : JournalMetaQuestScriptedData;
	public import const function GetDistrict( entry : weak< JournalEntry > ) : weak< District_Record >;
	public import const function GetRecommendedLevel( entry : weak< JournalEntry > ) : Uint32;
	public import const function GetRecommendedLevelID( entry : weak< JournalEntry > ) : TweakDBID;
	public import const function GetQuestType( entry : weak< JournalEntry > ) : gameJournalQuestType;
	public import const function GetIsObjectiveOptional( entry : weak< JournalQuestObjectiveBase > ) : Bool;
	public import const function TryGetWebsiteData( address : String, context : JournalRequestContext ) : weak< JournalInternetPage >;
	public import const function GetDistanceToNearestMappin( entry : weak< JournalQuestObjective >, optional filter : JournalRequestStateFilter ) : Float;
	public import const function GetPointOfInterestMappinHashFromQuestHash( hash : Uint32 ) : Uint32;
	public import function RegisterScriptCallback( obj : IScriptable, functionName : CName, type : gameJournalListenerType );
	public import function UnregisterScriptCallback( obj : IScriptable, functionName : CName );
	public import function DebugShowAllPoiMappins();

	public constexpr function CreateScriptedQuestFromTemplate( const templateQuestEntryId : ref< String >, const uniqueId : ref< String >, const title : ref< String > ) : Bool
	{
		return false;
	}

	public constexpr function DeleteScriptedQuest( const templateQuestEntryId : ref< String >, const uniqueId : ref< String > ) : Bool
	{
		return false;
	}

	public function SetScriptedQuestEntryState( const templateQuestEntryId : ref< String >, const uniqueId : ref< String >, const templatePhaseAndObjectivePath : ref< String >, state : gameJournalEntryState, notifyOption : JournalNotifyOption, track : Bool ) {}

	public constexpr function SetScriptedQuestObjectiveDescription( const templateQuestEntryId : ref< String >, const uniqueId : ref< String >, const templatePhaseAndObjectivePath : ref< String >, const description : ref< String > ) : Bool
	{
		return false;
	}

	public constexpr function SetScriptedQuestMappinEntityID( const templateQuestEntryId : ref< String >, const uniqueId : ref< String >, const templatePhaseObjectiveAndMappinPath : ref< String >, entityID : EntityID ) : Bool
	{
		return false;
	}

	public constexpr function SetScriptedQuestMappinSlotName( const templateQuestEntryId : ref< String >, const uniqueId : ref< String >, const templatePhaseObjectiveAndMappinPath : ref< String >, recordID : TweakDBID ) : Bool
	{
		return false;
	}

	public constexpr function SetScriptedQuestMappinData( const templateQuestEntryId : ref< String >, const uniqueId : ref< String >, const templatePhaseObjectiveAndMappinPath : ref< String >, const mappinData : ref< MappinData > ) : Bool
	{
		return false;
	}

	protected event OnQuestEntryTracked( entry : weak< JournalEntry > )
	{
		if( entry == NULL )
		{
		}
		else if( ( ( JournalQuest )( entry ) ) )
		{
		}
		else if( ( ( JournalQuestObjective )( entry ) ) )
		{
		}
	}

	protected event OnQuestEntryUntracked( entry : weak< JournalEntry > )
	{
		if( entry == NULL )
		{
		}
		else if( ( ( JournalQuest )( entry ) ) )
		{
		}
		else if( ( ( JournalQuestObjective )( entry ) ) )
		{
		}
	}

	public function GetContactByMessage( msg : JournalPhoneMessage ) : weak< JournalContact >
	{
		var conversationEntry : weak< JournalPhoneConversation >;
		conversationEntry = ( ( JournalPhoneConversation )( GetParentEntry( msg ) ) );
		if( conversationEntry )
		{
			return ( ( JournalContact )( GetParentEntry( conversationEntry ) ) );
		}
		return NULL;
	}

	public function GetContactDataArray( includeUnknown : Bool, includeNonCallable : Bool ) : array< IScriptable >
	{
		var context : JournalRequestContext;
		var entries : array< weak< JournalEntry > >;
		var i, j : Int32;
		var contactEntry : weak< JournalContact >;
		var contactData : ContactData;
		var emptyContactData : ContactData;
		var contactDataArray : array< IScriptable >;
		var messagesReceived : array< weak< JournalEntry > >;
		var playerReplies : array< weak< JournalEntry > >;
		var lastMessegeRecived : weak< JournalPhoneMessage >;
		var lastMessegeSent : weak< JournalPhoneChoiceEntry >;
		var trackedObjective : JournalQuestObjective;
		var trackedChildEntriesList : array< weak< JournalEntry > >;
		var trackedChildEntriesHashList : array< Int32 >;
		var trackedChildEntry : weak< JournalQuestCodexLink >;
		var trackedChildEntriesCount : Int32;
		context.stateFilter.active = true;
		GetContacts( context, entries );
		trackedChildEntriesCount = 0;
		trackedObjective = ( ( JournalQuestObjective )( GetTrackedEntry() ) );
		if( trackedObjective != NULL )
		{
			GetChildren( trackedObjective, context.stateFilter, trackedChildEntriesList );
			trackedChildEntriesCount = trackedChildEntriesList.Size();
			for( j = 0; j < trackedChildEntriesCount; j = j + 1 )
			{
				trackedChildEntry = ( ( JournalQuestCodexLink )( trackedChildEntriesList[ j ] ) );
				if( trackedChildEntry )
				{
					trackedChildEntriesHashList.PushBack( ( ( Int32 )( trackedChildEntry.GetLinkPathHash() ) ) );
				}
			}
		}
		for( i = 0; i < entries.Size(); i += 1 )
		{
			contactEntry = ( ( JournalContact )( entries[ i ] ) );
			if( contactEntry )
			{
				if( !( includeNonCallable || contactEntry.IsCallable( this ) ) )
				{
					continue;
				}
				if( includeUnknown || contactEntry.IsKnown( this ) )
				{
					contactData = new ContactData;
					contactData.id = contactEntry.GetId();
					contactData.hash = GetEntryHash( contactEntry );
					contactData.localizedName = contactEntry.GetLocalizedName( this );
					contactData.avatarID = contactEntry.GetAvatarID( this );
					contactData.questRelated = trackedChildEntriesHashList.Contains( contactData.hash );
					contactData.type = MessengerContactType.Contact;
					contactData.isCallable = contactEntry.IsCallable( this );
					contactData.contactId = contactEntry.GetId();
					messagesReceived.Clear();
					playerReplies.Clear();
					GetFlattenedMessagesAndChoices( contactEntry, messagesReceived, playerReplies );
					contactData.messagesCount = messagesReceived.Size();
					contactData.repliesCount = playerReplies.Size();
					for( j = 0; j < messagesReceived.Size(); j += 1 )
					{
						if( !( this.IsEntryVisited( messagesReceived[ j ] ) ) )
						{
							contactData.unreadMessages.PushBack( this.GetEntryHash( messagesReceived[ j ] ) );
						}
					}
					contactData.playerCanReply = playerReplies.Size() > 0;
					if( messagesReceived.Size() > 0 )
					{
						contactData.hasMessages = true;
						lastMessegeRecived = ( ( JournalPhoneMessage )( messagesReceived.Last() ) );
						if( lastMessegeRecived )
						{
							contactData.lastMesssagePreview = lastMessegeRecived.GetText();
							contactData.playerIsLastSender = false;
						}
						else
						{
							lastMessegeSent = ( ( JournalPhoneChoiceEntry )( messagesReceived.Last() ) );
							contactData.lastMesssagePreview = lastMessegeSent.GetText();
							contactData.playerIsLastSender = true;
						}
					}
					else
					{
						contactData.lastMesssagePreview = "You are now connected.";
					}
					contactDataArray.PushBack( contactData );
				}
			}
			else
			{
				contactDataArray.PushBack( emptyContactData );
			}
		}
		return contactDataArray;
	}

	public function IsAttachedToAnyActiveQuest( hash : Int32 ) : Bool
	{
		var filter : JournalRequestStateFilter;
		var quests : array< weak< JournalEntry > >;
		var childEntries : array< weak< JournalEntry > >;
		var codexLinkEntry : JournalQuestCodexLink;
		var context : JournalRequestContext;
		var i, count : Int32;
		filter.active = true;
		context.stateFilter = filter;
		GetQuests( context, quests );
		count = quests.Size();
		for( i = 0; i < count; i += 1 )
		{
			QuestLogUtils.UnpackRecursiveWithFilter( this, ( ( JournalContainerEntry )( quests[ i ] ) ), filter, childEntries, true );
		}
		count = childEntries.Size();
		for( i = 0; i < count; i += 1 )
		{
			codexLinkEntry = ( ( JournalQuestCodexLink )( childEntries[ i ] ) );
			if( codexLinkEntry && ( ( ( Int32 )( codexLinkEntry.GetLinkPathHash() ) ) == hash ) )
			{
				return true;
			}
		}
		return false;
	}

	public function IsAttachedToTrackedObjective( hash : Int32 ) : Bool
	{
		var filter : JournalRequestStateFilter;
		var objective : JournalQuestObjective;
		var childEntries : array< weak< JournalEntry > >;
		var count, i : Int32;
		var trackedChildEntry : JournalQuestCodexLink;
		filter.active = true;
		objective = ( ( JournalQuestObjective )( GetTrackedEntry() ) );
		if( objective != NULL )
		{
			GetChildren( objective, filter, childEntries );
			count = childEntries.Size();
			for( i = 0; i < count; i = i + 1 )
			{
				trackedChildEntry = ( ( JournalQuestCodexLink )( childEntries[ i ] ) );
				if( trackedChildEntry && ( ( ( Int32 )( trackedChildEntry.GetLinkPathHash() ) ) == hash ) )
				{
					return true;
				}
			}
		}
		return false;
	}

}

