// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

/**
 @file
*/

#include "FLOGSVR.H"
#include "FLOGMAN.H"
#include "FLOGSTD.H"

/**
@internalComponent
*/
const TInt KOpenLogFilesGranularity=5;

/**
panics for log client

@internalComponent
*/
enum TLogClientPanic 
    {
	ELogDirectoryNameDoesNotExist =1,   ///<  panic if no log directory name 
	ELogFileNameDoesNotExist	        ///< panic if file name doesnot exist 
	};

/**
CFileLoggerServer class definition
*/

CFileLoggerServer* CFileLoggerServer::NewL()
/**
Creates new CFileLoggerServer object

@return Pointer to CFileLoggerServer object
*/
	{

	CFileLoggerServer* r=new(ELeave) CFileLoggerServer();
	CleanupStack::PushL(r);
	r->ConstructL();
	r->StartL(KFLoggerServerName);
	CleanupStack::Pop();
	return r;
	}

CFileLoggerServer::CFileLoggerServer()
 	: CServer2(EPriority)
 	{}

void CFileLoggerServer::ConstructL()
	{

	iLoggerManager=CFileLoggerManager::NewL();
	iSessionCounter=CFileLogSessionCounter::NewL();
	}

CFileLoggerServer::~CFileLoggerServer()
/**
Destructor
*/
	{

	delete iSessionCounter;
	delete iLoggerManager;
	}

CFileLogSessionCounter* CFileLoggerServer::SessionCounter() const
	{

	return iSessionCounter;
	}

void CFileLoggerServer::Error(TInt aError)
	{

	Message().Complete(aError);
	ReStart();
	}

CSession2* CFileLoggerServer::NewSessionL(const TVersion &aVersion, const RMessage2& /* aMessage */) const
/**
Create a new server session. Check we're the right version and make a new session

@param aVersion version of new session
*/
	{

	TVersion v(KFLogSrvMajorVersionNumber,KFLogSrvMinorVersionNumber,KFLogSrvBuildVersionNumber);
	if (!User::QueryVersionSupported(v,aVersion))
		User::Leave(KErrNotSupported);
	
	iSessionCounter->CancelTimer();
	return CFileLogSession::NewL(CONST_CAST(CFileLoggerServer*,this),iLoggerManager);
	}
/**
CFileLogSessionCounter class definition 
*/

CFileLogSessionCounter* CFileLogSessionCounter::NewL()
/**
Creates new CFileLogSessionCounter object

@return Pointer to CFileLogSessionCounter object
*/
	{
	
	CFileLogSessionCounter* r=new(ELeave) CFileLogSessionCounter();
	CleanupStack::PushL(r);
	r->ConstructL();
	CleanupStack::Pop();
	return r;
	}

CFileLogSessionCounter::~CFileLogSessionCounter()
/**
Destructor
*/
	{

	delete iShutdownTimer;
	}

CFileLogSessionCounter::CFileLogSessionCounter()
	: iSessionCount(0)
/**
Default Constructor
*/
	{}

void CFileLogSessionCounter::ConstructL()
	{

	iShutdownTimer=CShutdownTimer::NewL();
	}
	
void CFileLogSessionCounter::IncrementSessionCount()
/**
Increments the Session count 
*/
	{

	iSessionCount++;
	}

void CFileLogSessionCounter::DecrementSessionCount()
/**
Decrements the Session count
*/
	{

	iSessionCount--;
	if (iSessionCount<=0)
		iShutdownTimer->After(KShutdownPause);
	}

void CFileLogSessionCounter::CancelTimer()
/**
Cancels the timer 
*/
	{

	iShutdownTimer->Cancel();
	}	

/**
CShutdownTimer class definitions
*/

CShutdownTimer* CShutdownTimer::NewL()
/**
Creates new CShutdownTimer object
@return Pointer to CShutdownTimer object
*/
	{

	CShutdownTimer* r=new(ELeave) CShutdownTimer();
	CleanupStack::PushL(r);
	r->ConstructL();
	CleanupStack::Pop();
	return r;
	}

CShutdownTimer::~CShutdownTimer()
/**
Destructor
*/
	{}

CShutdownTimer::CShutdownTimer()
	: CTimer(EPriorityIdle)
/**
Default Constructor
*/
	{
	CActiveScheduler::Add(this);
	}

void CShutdownTimer::RunL()
/**
*/
	{

	CActiveScheduler::Stop();
	}

/**
CFileLogSession class definition
*/

CFileLogSession* CFileLogSession::NewL(CFileLoggerServer* aServer, CFileLoggerManager* aManager)
 	{
   
 	CFileLogSession* r=new(ELeave) CFileLogSession(aServer,aManager);
 	CleanupStack::PushL(r);
 	r->ConstructL();
 	CleanupStack::Pop();
 	return r;
 	}

CFileLogSession::CFileLogSession( CFileLoggerServer* aServer, CFileLoggerManager* aManager)
 	: CSession2(), iLoggerServer(aServer), iLoggerManager(aManager)
 	{}

void CFileLogSession::ConstructL()
	{

	iLoggerServer->SessionCounter()->IncrementSessionCount();		// should be done first because it will be decremented in the destructor
	iOpenLogFiles=new(ELeave) CArrayFixFlat<TLogFile>(KOpenLogFilesGranularity);
 	}

CFileLogSession::~CFileLogSession()
/**
Destructor
*/
	{
	if  (iOpenLogFiles)
		{
	TInt count=iOpenLogFiles->Count();
	TInt i;
	for (i=0; i<count; i++)
		{
		iLoggerManager->CloseLog(iOpenLogFiles->At(i));
		}
	iOpenLogFiles->Delete(0,count);
	delete iOpenLogFiles;
		}
	iLoggerServer->SessionCounter()->DecrementSessionCount();		// starts the timer if this is the last session
	}

void CFileLogSession::ServiceL(const RMessage2& aMessage)
/**
@internalTechnology
*/
	{
  
 	TRAPD(ret,DispatchMessageL(aMessage));
 	aMessage.Complete(ret);
 	}

void CFileLogSession::DispatchMessageL(const RMessage2& aMessage)
 	{
 
 	TInt func=aMessage.Function();
 	if (func!=ECreateLog && func!=EWriteLog && func!=ECloseLog && func!=ECreateWriteAndCloseLog)
 		User::Leave(KErrNotSupported);
 
 	TLogFile log;
 	TPckg<TLogFile> logPckg(log);
 	aMessage.ReadL(0,logPckg);
 	__ASSERT_ALWAYS(log.Directory().Length()!=0,aMessage.Panic(KFLoggerServerName,ELogDirectoryNameDoesNotExist));
 	__ASSERT_ALWAYS(log.Name().Length()!=0,aMessage.Panic(KFLoggerServerName,ELogFileNameDoesNotExist));	
 
 //	TBuf8<KLogBufferSize> buf;
 	TBuf8<1600> buf;
 	if (func==EWriteLog || func==ECreateWriteAndCloseLog)
 		aMessage.ReadL(1,buf);
 
 	switch (func)
 		{
 	case ECreateLog:
 		OpenLogL(log);
 		aMessage.WriteL(0,logPckg);
 		break;
 
 	case EWriteLog:
 		iLoggerManager->WriteToLogL(log,buf);
 		break;
 
 	case ECloseLog:
 		CloseLog(log);
 		break;
 
 	case ECreateWriteAndCloseLog:
  		{
  		OpenLogL(log); // Ok to leave here; assume that log not left open
 		TInt rc = aMessage.Write(0,logPckg);
  		if (rc == KErrNone && log.Valid())
  			TRAP(rc,iLoggerManager->WriteToLogL(log,buf));
    		CloseLog(log);
  		User::LeaveIfError(rc);
    		break;
  		}
 
 	default:
 		User::Leave(KErrNotSupported);
 		break;
 		}
 	}
 

void CFileLogSession::OpenLogL(TLogFile& aLogFile)
/**
Opens log file

@param aLogFile Log file name
*/
	{

	iOpenLogFiles->AppendL(aLogFile);
	iLoggerManager->FindOrCreateLogL(aLogFile);
	}

void CFileLogSession::CloseLog(TLogFile& aLogFile)
/**
Closes the log file

@param aLogFile Log file name
*/
	{

	iLoggerManager->CloseLog(aLogFile);
	TInt count=iOpenLogFiles->Count();
	TInt i=0;
	for (i=0; i<count; i++)
		{
		if (iOpenLogFiles->At(i)==aLogFile)
			{
			iOpenLogFiles->Delete(i,1);
			break;
			}
		}	

	__ASSERT_DEBUG(i<=count, User::Invariant());
	}
			
