/*
* Copyright (c) 2002-2005 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:          
*
*/










#include "senlogger.h"
//#include <flogger.h>
#include <f32file.h>
#include <s32file.h> 
#include <versit.h>

namespace
    {
    const TInt KColumnWidth = 100; // used in WriteAll() methods.
     _LIT(KPath,"C:\\SenLogConfig.txt");
     _LIT(  KClientIdFmt,  "- Client[%d] %S");
     
     _LIT(  KClientIdFmtNextLine,  "Client(%d):");
     
     _LIT8( KClientIdFmt8, "- Client[%d] %S");
     _LIT8( KClientIdFmtNextLine8, "Client(%d):");
    }

EXPORT_C TInt CSenLogger::CreateL(TInt aChannel, TInt aLevel, const TDesC& aLogDir, const TDesC& aLogFileName)
     {
	 return CreateL( aChannel, aLevel, aLogDir, aLogFileName, EFileLoggingModeOverwrite );
     }
EXPORT_C TInt CSenLogger::CreateL(TInt aChannel, TInt aLevel, const TDesC& aLogDir, const TDesC& aLogFileName, TFileLoggingMode aMode)
    {
    TInt index(KErrNotFound);
    //	  CSenLogger* pSenLogger = (CSenLogger*)Dll::Tls();
    CSenLogger* pSenLogger = NULL;
    TWsTls* tls = (TWsTls*)Dll::Tls();
    if( !tls )
        {
        tls = new (ELeave) TWsTls();
        tls->iLogger = NULL;
        tls->iProxy = NULL;
        Dll::SetTls( tls );
        }
    pSenLogger = tls->iLogger;    
	if ( !pSenLogger )
  		{
  		pSenLogger = new (ELeave) CSenLogger();
        if ( pSenLogger )
            {
            //      		  Dll::SetTls(pSenLogger);
            tls->iLogger = pSenLogger;
      		pSenLogger->iCount = 0;
      		//reading the configuration file for the logging levels!!!
      		
      		/*the file has the  following format
      		* ==============================================================================
      		  * LogChannel LogLevel
      		    1000 0
      		    2000 1
      		      .
      		      .
      		      .
      		      .
      		      .
      		      ....
      		    18000 2
      		   this means first you need to write the channel followed by the corresponding logging level after a space
      		 
      		 the file has to be located under C:\Config.txt
      		 * ==============================================================================*/
      		 
      
      		TInt res;
      	    RFs fs;
      	    res=fs.Connect();
      	      if(res==KErrNone)
				{
      	     
                RFileReadStream readStream;
      	        res=readStream.Open(fs,KPath,EFileRead|EFileStreamText);
      	   		if(res==KErrNone)
      	     		{
      	      		TInt error;
      	      		TBool result;
      	      		TInt retVal;
      	      		
      	      		CLineReader *readLine = CLineReader::NewL(readStream);
                    CleanupStack::PushL(readLine);
      	    		
                	do
      	    		    {
      	      		    result=readLine->ReadLineL(0,error);
      	      		    
      	       	        if(result==CLineReader::ELineHasContent)
      	       			    {
      	       			    
              	      		TInt *key = new (ELeave) TInt;
              	      	
          	      		
      	       			    TLex8 lexBuf(readLine->iBufPtr);
      	     			    retVal = lexBuf.Val(*key);
      	     			    
      	     			    if(retVal!=0)
      	     			        {
      	     			        delete key;
                             
      	     			        continue;
      	     			        }
      	     			    else
      	     			        {
                  	      		TInt *value = new (ELeave) TInt;
                  	      
      	      		
  	     			            lexBuf.SkipSpace();
  	     			            retVal=lexBuf.Val(*value);
  	     			            if(retVal==0)
	  	     			            {
  	     			    	        retVal = pSenLogger->iMap.Append(key,value);
  	     			    	        if(retVal != KErrNone)
  	     			    	            {
  	     			    	            delete key;
  	     			    	            delete value;
      	    		                   
  	     			    	            }
  	     			    	   
  		     			            }
  		     			         else
  		     			            {
  		     			              delete key;
  	     			    	          delete value;
  		     			                
  		     			            }
      	     			    	
      	     			        }
      	       			    }
      	       			 
      	    		    }while(error!=KErrEof);
      	    		 
      	    		 CleanupStack::PopAndDestroy(readLine);
      	      	     readStream.Close();
      	     		}
      	     
      	      	fs.Close();
      	      	}
            }
        else
            {
            return KErrGeneral;
            }
  		}
  	else
  	    {
  	    index = pSenLogger->ChannelIndex(aChannel);
  	    }	
  	
  	if (index == KErrNotFound)
  	    {
  	    TInt channelIndex;
        TLog* pTLog = new (ELeave) TLog;
        CleanupStack::PushL(pTLog);
        pTLog->iChannel=aChannel;
        channelIndex=pSenLogger->iMap.Find(aChannel);
        if(channelIndex==KErrNotFound)
        {
        pTLog->iLevel=aLevel;
        }
        else
        {
        pTLog->iLevel=*(pSenLogger->iMap.ValueAt(channelIndex));
        }
        pTLog->iCount=1;
        pTLog->iLog.Connect();
        pTLog->iLog.CreateLog(aLogDir, aLogFileName, aMode);
        pTLog->iLog.Write(_L("SenTLSLogger - Log file opened"));
#ifdef EKA
        pSenLogger->iLogs.AppendL(pTLog);
#else
        User::LeaveIfError(pSenLogger->iLogs.Append(pTLog));
	  
#endif
        CleanupStack::Pop(pTLog);
  	    }
  	else
  	    {
  	    pSenLogger->iLogs[index]->iCount++;
  	    }
  	pSenLogger->iCount++;
    
    return KErrNone;
    }

EXPORT_C void CSenLogger::Destroy(TInt aChannel)
    {
    //	CSenLogger* pSenLogger = (CSenLogger*)Dll::Tls();
    CSenLogger* pSenLogger = NULL;
    TWsTls* tls = (TWsTls*)Dll::Tls();
    if( tls )
        {
        pSenLogger = tls->iLogger;
        }
	if ( pSenLogger )
	    {
	    
	    TInt index = pSenLogger->ChannelIndex(aChannel);
	    if (index != KErrNotFound)
	        {
	        pSenLogger->iLogs[index]->iCount--;
	        if (pSenLogger->iLogs[index]->iCount <= 0)
	            {
                pSenLogger->iLogs[index]->iLog.Write(_L("SenTLSLogger - Log file closed."));
                pSenLogger->iLogs[index]->iLog.CloseLog();
                pSenLogger->iLogs[index]->iLog.Close();
                delete pSenLogger->iLogs[index];
                pSenLogger->iLogs.Remove(index);
	            }
            }
	        pSenLogger->iCount--;
	        if (pSenLogger->iCount <= 0)
	            {
	            pSenLogger->iLogs.Close();
	            delete pSenLogger;
            tls->iLogger = NULL;
            if( !tls->iLogger && !tls->iProxy )
                {
	            delete tls;
                Dll::FreeTls();	            
	            }
	        }
	    }
    }

// 16-bit variants    
    
EXPORT_C void CSenLogger::Write(TInt aChannel, TInt aLevel, const TDesC16& aText)
    {
    RFileLogger* pLogger = Logger(aChannel, aLevel);
    if ( pLogger )
        {
        pLogger->Write(aText);
        }
    }

EXPORT_C void CSenLogger::WriteAll(TInt aChannel, TInt aLevel, const TDesC16& aText)
    {
    RFileLogger* pLogger = Logger(aChannel, aLevel);
    if ( pLogger )
        {
        TInt i = 0;
        TInt lineAmount(KColumnWidth);
        TInt length = aText.Length();
        while(i<aText.Length())
            {
            if ( length - i < KColumnWidth )
                {
                lineAmount = length - i;    
                }
            pLogger->Write(aText.Mid(i, lineAmount));
            i += KColumnWidth;
            }
        }
    }

EXPORT_C void CSenLogger::WriteFormat(TInt aChannel, TInt aLevel, TRefByValue<const TDesC16> aFmt,...)
    {
    RFileLogger* pLogger = Logger(aChannel, aLevel);
    if (pLogger)
        {
        VA_LIST list;
        VA_START(list,aFmt);
        pLogger->WriteFormat(aFmt, list);
        }    
    }
    
EXPORT_C void CSenLogger::WriteFormat(TInt aChannel, TInt aLevel, TRefByValue<const TDesC16> aFmt, VA_LIST& aList)
    {
    RFileLogger* pLogger = Logger(aChannel, aLevel);
    if (pLogger)
        {
        pLogger->WriteFormat(aFmt, aList);
        }    
    }


// Client ID spesific logging methods    
EXPORT_C void CSenLogger::WriteWithClientId(TInt aClientId, TInt aChannel, TInt aLevel, const TDesC16& aText)
    {
    WriteFormat( aChannel, aLevel, KClientIdFmt, aClientId, &aText );
    }

EXPORT_C void CSenLogger::WriteAllWithClientId(TInt aClientId, TInt aChannel, TInt aLevel, const TDesC16& aText)
    {
    // Write client id on separate line, for clarity & simplicity
    WriteFormat( aChannel, aLevel, KClientIdFmtNextLine, aClientId);
    WriteAll( aChannel, aLevel, aText );
    }

EXPORT_C void CSenLogger::WriteFormatWithClientId(TInt aClientId, TInt aChannel, TInt aLevel, TRefByValue<const TDesC16> aFmt, ...)
    {
    // Write client id on separate line, for clarity & simplicity
    WriteFormat( aChannel, aLevel, KClientIdFmtNextLine, aClientId);
    VA_LIST list;
    VA_START(list,aFmt);
    WriteFormat( aChannel, aLevel, aFmt, list);
    }
    
EXPORT_C void CSenLogger::WriteFormatWithClientId(TInt aClientId, TInt aChannel, TInt aLevel, TRefByValue<const TDesC16> aFmt, VA_LIST& aList)
    {
    WriteFormat( aChannel, aLevel, KClientIdFmtNextLine, aClientId);
    WriteFormat( aChannel, aLevel, aFmt, aList);
    }

EXPORT_C void CSenLogger::WriteFormatWithClientIdToMainLogs(TInt aClientId, TInt aLevel, TRefByValue<const TDesC16> aFmt,...)
    {
    VA_LIST list;
    VA_START(list,aFmt);
    WriteFormatWithClientId( aClientId, KSenClientSessionLogChannelBase+aClientId, aLevel, aFmt, list );
    WriteFormatWithClientId( aClientId, KSenCoreServiceManagerLogChannelBase, aLevel, aFmt, list );
    }

EXPORT_C void CSenLogger::WriteFormatWithClientIdToMainLogs(TInt aClientId, TInt aLevel, TRefByValue<const TDesC16> aFmt, VA_LIST& aList)
    {
    WriteFormatWithClientId( aClientId, KSenClientSessionLogChannelBase+aClientId, aLevel, aFmt, aList );
    WriteFormatWithClientId( aClientId, KSenCoreServiceManagerLogChannelBase, aLevel, aFmt, aList );
    }
    
// 8-bit variants    

EXPORT_C void CSenLogger::Write(TInt aChannel, TInt aLevel, const TDesC8& aText)
    {
    RFileLogger* pLogger = Logger(aChannel, aLevel);
    if (pLogger)
        {
        pLogger->Write(aText);
        }
    }

EXPORT_C void CSenLogger::WriteAll(TInt aChannel, TInt aLevel, const TDesC8& aText)
    {
    RFileLogger* pLogger = Logger(aChannel, aLevel);
    if ( pLogger )
        {
        TInt i = 0;
        TInt lineAmount(KColumnWidth);
        TInt length = aText.Length();
        while(i<aText.Length())
            {
            if ( length - i < KColumnWidth )
                {
                lineAmount = length - i;    
                }
            pLogger->Write(aText.Mid(i, lineAmount));
            i += KColumnWidth;
            }
        }
    }


EXPORT_C void CSenLogger::WriteFormat(TInt aChannel, TInt aLevel, TRefByValue<const TDesC8> aFmt,...)
    {
    RFileLogger* pLogger = Logger(aChannel, aLevel);
    if (pLogger)
        {
        VA_LIST list;
        VA_START(list,aFmt);
        pLogger->WriteFormat(aFmt, list);
        }    
    }

EXPORT_C void CSenLogger::WriteFormat(TInt aChannel, TInt aLevel, TRefByValue<const TDesC8> aFmt, VA_LIST& aList)
    {
    RFileLogger* pLogger = Logger(aChannel, aLevel);
    if (pLogger)
        {
        pLogger->WriteFormat(aFmt, aList);
        }    
    }

EXPORT_C void CSenLogger::WriteWithClientId(TInt aClientId, TInt aChannel, TInt aLevel, const TDesC8& aText)
    {
    WriteFormat( aChannel, aLevel, KClientIdFmt8, aClientId, &aText );    	
    }

EXPORT_C void CSenLogger::WriteAllWithClientId(TInt aClientId, TInt aChannel, TInt aLevel, const TDesC8& aText)
    {
    // Write client id on separate line, for clarity & simplicity
    WriteFormat( aChannel, aLevel, KClientIdFmtNextLine8, aClientId);
    WriteAll( aChannel, aLevel, aText );
    }

EXPORT_C void CSenLogger::WriteFormatWithClientId(TInt aClientId, TInt aChannel, TInt aLevel, TRefByValue<const TDesC8> aFmt,...)
    {
    // Write client id on separate line, for clarity & simplicity
    WriteFormat( aChannel, aLevel, KClientIdFmtNextLine8, aClientId);
    VA_LIST list;
    VA_START(list,aFmt);
    WriteFormat( aChannel, aLevel, aFmt, list);
    }
    
EXPORT_C void CSenLogger::WriteFormatWithClientId(TInt aClientId, TInt aChannel, TInt aLevel, TRefByValue<const TDesC8> aFmt, VA_LIST& aList)
    {
    WriteFormat( aChannel, aLevel, KClientIdFmtNextLine8, aClientId);
    WriteFormat( aChannel, aLevel, aFmt, aList);
    }

EXPORT_C void CSenLogger::WriteFormatWithClientIdToMainLogs(TInt aClientId, TInt aLevel, TRefByValue<const TDesC8> aFmt, ...)
    {
    VA_LIST list;
    VA_START(list,aFmt);
    WriteFormatWithClientId( aClientId, KSenClientSessionLogChannelBase+aClientId, aLevel, aFmt, list );
    WriteFormatWithClientId( aClientId, KSenCoreServiceManagerLogChannelBase, aLevel, aFmt, list );
    }

EXPORT_C void CSenLogger::WriteFormatWithClientIdToMainLogs(TInt aClientId, TInt aLevel, TRefByValue<const TDesC8> aFmt, VA_LIST& aList)
    {
    WriteFormatWithClientId( aClientId, KSenClientSessionLogChannelBase+aClientId, aLevel, aFmt, aList );
    WriteFormatWithClientId( aClientId, KSenCoreServiceManagerLogChannelBase, aLevel, aFmt, aList );
    }


RFileLogger* CSenLogger::Logger(TInt aChannel, TInt aLevel)
    {
//    CSenLogger* pSenLogger = (CSenLogger*)Dll::Tls();
    CSenLogger* pSenLogger = NULL;
    TWsTls* tls = (TWsTls*)Dll::Tls();
    if( tls )
        {
        pSenLogger = tls->iLogger;
        }
	if ( pSenLogger )
	    {
        TInt index = pSenLogger->ChannelIndex(aChannel);
        if (index != KErrNotFound)
            {
            if (pSenLogger->iLogs[index]->iLevel >= aLevel)
                {
                return &pSenLogger->iLogs[index]->iLog;
                }
            }
	    }
	return NULL;
    }

TInt CSenLogger::ChannelIndex(TInt aChannel) const
    {
    TInt index(KErrNotFound);
    TInt count=iLogs.Count();
    for (TInt i=0; i<count; i++)      	    
        {
        if (iLogs[i]->iChannel == aChannel)
            {
            index = i;
            break;
            }
        }
    return index;    
    }

EXPORT_C CSenLogger::CSenLogger()
    : iCount(0),iMap(1,1)
    {
    }

CSenLogger::~CSenLogger()
    {
   
    iMap.Reset();
    }

// END OF FILE

