//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=======================================================================================//

#include "shared_replaycontext.h"
#include "replay/shared_defs.h"
#include "replay/replayutils.h"
#include "baserecordingsession.h"
#include "baserecordingsessionblock.h"
#include "baserecordingsessionmanager.h"
#include "baserecordingsessionblockmanager.h"
#include "thinkmanager.h"
#include "filesystem.h"
#include "errorsystem.h"

#undef Yield
#include "vstdlib/jobthread.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

//----------------------------------------------------------------------------------------

CSharedReplayContext::CSharedReplayContext( IReplayContext *pOwnerContext )
:	m_pOwnerContext( pOwnerContext ),
	m_pRecordingSessionManager( NULL ),
	m_pRecordingSessionBlockManager( NULL ),
	m_pErrorSystem( NULL ),
	m_pThreadPool( NULL ),
	m_bInit( false )
{
}

CSharedReplayContext::~CSharedReplayContext()
{
	delete m_pRecordingSessionManager;
	delete m_pRecordingSessionBlockManager;
	delete m_pErrorSystem;
	delete m_pThreadPool;
}

bool CSharedReplayContext::Init( CreateInterfaceFn fnFactory )
{
	m_strRelativeBasePath.Format(
		"%s%c%s%c",
		SUBDIR_REPLAY,
		CORRECT_PATH_SEPARATOR,
		m_strSubDir.Get(),
		CORRECT_PATH_SEPARATOR
	);

	m_strBasePath.Format(
		"%s%c%s",
		g_pEngine->GetGameDir(),
		CORRECT_PATH_SEPARATOR,
		m_strRelativeBasePath.Get()
	);

	// Owning context should have initialized these by now
	// NOTE: Session manager init must come after block manager init since session manager
	// assumes all blocks have been loaded.
	// 
	m_pRecordingSessionBlockManager->Init();
	m_pRecordingSessionManager->Init();

	if ( !InitThreadPool() )
		return false;

	m_bInit = true;

	return true;
}

bool CSharedReplayContext::InitThreadPool()
{
	// Create thread pool
	Log( "Replay: Creating thread pool..." );
	IThreadPool *pThreadPool = CreateThreadPool();
	if ( !pThreadPool )
	{
		Log( "failed!\n" );
		return false;
	}
	Log( "succeeded.\n" );

	// Jon says: The client only really needs a single "ReplayContext" thread, so that the replay editor can write
	//  data asynchronously. The game server does in fact require 4 threads, and can be configured to use more
	//	via the replay_max_publish_threads convar.
	int nMaxThreads = 1;

	if ( g_pEngine->IsDedicated() )
	{
		// Use the convar for max threads on servers
		extern ConVar replay_max_publish_threads;
		nMaxThreads = replay_max_publish_threads.GetInt();
	}

	// Start thread pool
	Log( "Replay: Starting thread pool with %i threads...", nMaxThreads );
	if ( !pThreadPool->Start( ThreadPoolStartParams_t( true, nMaxThreads ), "ReplayContext" ) )
	{
		Log( "failed!\n" );
		return false;
	}
	Log( "succeeded.\n" );

	m_pThreadPool = pThreadPool;

	return true;
}

void CSharedReplayContext::Shutdown()
{
	m_pRecordingSessionBlockManager->Shutdown();
	m_pRecordingSessionManager->Shutdown();
	m_pThreadPool->Stop();
}

void CSharedReplayContext::Think()
{
}

const char *CSharedReplayContext::GetRelativeBaseDir() const
{
	return m_strRelativeBasePath.Get();
}

const char *CSharedReplayContext::GetBaseDir() const
{
	return m_strBasePath.Get();
}

const char *CSharedReplayContext::GetReplaySubDir() const
{
	return m_strSubDir.Get();
}

void CSharedReplayContext::EnsureDirHierarchy()
{
	g_pFullFileSystem->CreateDirHierarchy( m_strBasePath.Get() );
}

//----------------------------------------------------------------------------------------

bool RunJobToCompletion( IThreadPool *pThreadPool, CJob *pJob )
{
	pThreadPool->AddJob( pJob );
	pJob->WaitForFinish();
	return pJob->Executed();
}

//----------------------------------------------------------------------------------------