/*
* Copyright (c) 2002-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:  This module contains the implementation of CPELogEvent class
*
*/


//  INCLUDE FILES
#include "cpelogevent.h"
#include "cpeloginfo.h"
#include "cpeloghandling.h"
#include "cpeloghandlingcommand.h"
#include <PbkFields.hrh>
#include <talogger.h>
#include <logcli.h>
#include <LogsApiConsts.h>


// EXTERNAL DATA STRUCTURES
//None

// EXTERNAL FUNCTION PROTOTYPES  
//None

// CONSTANTS
const TInt KPhonebookTypeIdLength = 11;

// Defined in \s60\app\contacts\logsui\EngineIncLogsEngConsts.h as KLogEventALS
const TLogFlags KPELogEventALS = 0x4;

const TInt KOneChar = 1;

// MACROS
//None

// LOCAL CONSTANTS AND MACROS
//None

// MODULE DATA STRUCTURES
//None

// LOCAL FUNCTION PROTOTYPES
//None

// FORWARD DECLARATIONS
//None


// ==================== LOCAL FUNCTIONS =====================================

// -----------------------------------------------------------------------------
// CPELogEvent::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CPELogEvent* CPELogEvent::NewL
        ( 
        CPELogHandling& aOwner,  // Owner of the object
        CPELogHandlingCommand& aLogHandlingCommand
        )
    {
    TEFLOGSTRING(KTAOBJECT, "LOG CPELogEvent::NewL start.");
    CPELogEvent* self = new ( ELeave ) CPELogEvent( aOwner, aLogHandlingCommand );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    TEFLOGSTRING(KTAOBJECT, "LOG CPELogEvent::NewL complete.");
    return self;
    }
  
// Destructor
/*****************************************************
*    Series 60 Customer / LOGENG
*    Series 60  LOGENG API
*****************************************************/
CPELogEvent::~CPELogEvent
        (
        // None
        )
    {
    TEFLOGSTRING( KTAOBJECT, "LOG CPELogEvent::~CPELogEvent()" );
    delete iEvent;
    delete iLogInfo;
    }


// ================= MEMBER FUNCTIONS =======================================
// -----------------------------------------------------------------------------
// CPELogEvent::CPELogEvent
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CPELogEvent::CPELogEvent
        ( 
        CPELogHandling& aOwner,
        CPELogHandlingCommand& aLogHandlingCommand
        ) : iOwner( aOwner ),
            iLogHandlingCommand( aLogHandlingCommand ),
            iCompleted( EFalse ),
            iAdded( EFalse ),
            iSaveLeave( EFalse )
    {
    }
// -----------------------------------------------------------------------------
// CPELogEvent::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
/*****************************************************
*    Series 60 Customer / LOGENG
*    Series 60  LOGENG API
*****************************************************/
void CPELogEvent::ConstructL
        (
        // None
        )
    {
    iEvent = CLogEvent::NewL();
    ResetEvent( );
    iLogInfo = CPELogInfo::NewL();
    }
    
// -----------------------------------------------------------------------------
// CPELogEvent::Save
// Saves the event to the log.
// -----------------------------------------------------------------------------
//
void CPELogEvent::SaveL()
    {
    iSaveLeave = ETrue;
    // iCopleted flag must be set before the function leave as it is used 
    // in log subsytem recovery procedure in case of leave.
    if ( EPEStateIdle == iLogInfo->CallState() || iLogInfo->ForcedCompletion() )
        {
        iCompleted = ETrue;
        }
        
    if ( !iAdded )
        {
        TEFLOGSTRING2( KTAINT, "LOG CPELogEvent::SaveL() > CPELogHandlingCommand::AddEvent(), callId=%d", iLogInfo->CallId() );  
        SetPhoneNumberId();
        SetEventTypeL();
        SetLogEvent();
        SetDuration();
        SetServiceIdL();
        
        if ( &iLogInfo->ContactLink() )
            {
            SetContactLinkL();
            }
        // event under processing will always be of index 0 in the queued array
        User::LeaveIfError( iLogHandlingCommand.AddEvent( *iEvent ) );
        }
    else
        { 
        TEFLOGSTRING2( KTAINT, "LOG CPELogEvent::SaveL() > CPELogHandlingCommand::ChangeEvent(), callId=%d", iLogInfo->CallId() );            
        SetLogEvent();
        SetDuration();
        User::LeaveIfError( iLogHandlingCommand.ChangeEvent( *iEvent ) );
        }
    // indicates no leave happened in Save function
    iSaveLeave = EFalse;
    }

// -----------------------------------------------------------------------------
// CPELogEvent::UpdateLogInfo
// Update log database entry.
// -----------------------------------------------------------------------------
//
void CPELogEvent::UpdateLogInfoL
        ( 
        const CPELogInfo& aLogInfo // Call information
        ) 
    {
    // CPELogHandling generic loginfo must be replicated to this event
    iLogInfo->CopyL( aLogInfo );
    }

// -----------------------------------------------------------------------------
// CPELogEvent::ResetLogInfo
// Reset log info.
// -----------------------------------------------------------------------------
//
void CPELogEvent::ResetLogInfo() 
    {
    TEFLOGSTRING( KTAINT, "LOG CPELogEvent::ResetLogInfo: start" );  
    iLogInfo->Reset();
    TEFLOGSTRING( KTAINT, "LOG CPELogEvent::ResetLogInfo: complete" ); 
    }
    
// -----------------------------------------------------------------------------
// CPELogEvent::ResetEvent
// Reset event on the idle state.
// -----------------------------------------------------------------------------
//
/*****************************************************
*    Series 60 Customer / LOGENG
*    Series 60  LOGENG API
*****************************************************/
void CPELogEvent::ResetEvent()
    {
    iAdded = EFalse;
    iCompleted = EFalse;
    iSaveLeave = EFalse;

    // CLogEvent -variables
    iEvent->SetId( KLogNullId );
    iEvent->SetEventType( KNullUid );
    iEvent->SetRemoteParty( KNullDesC );
    iEvent->SetDirection( KNullDesC );
    iEvent->SetTime( Time::NullTTime() );
    iEvent->SetDurationType( KLogNullDurationType );
    iEvent->SetDuration( KLogNullDuration );
    iEvent->SetStatus( KNullDesC );
    iEvent->SetSubject( KNullDesC );
    iEvent->SetNumber( KNullDesC );
    iEvent->SetContact( KNullContactId );
    iEvent->SetLink( KLogNullLink );
    iEvent->SetDescription( KNullDesC );
    iEvent->ClearFlags( KLogFlagsMask );
    TRAPD( error, iEvent->SetDataL( KNullDesC8 ) );
    if ( error != KErrNone )
        {
        // SetDataL leave should not cause log subsystem to fail. Just log the error.
        TEFLOGSTRING2( KTAERROR, "LOG CPELogEvent::Save()>CPELogHandlingCommand::ResetEvent(), error=%d", error );  
        }
    }

// -----------------------------------------------------------------------------
// CPELogEvent::CallId
// Get call id of the event.
// -----------------------------------------------------------------------------
//
TInt CPELogEvent::CallId
        (
        // None
        )
    {
    return iLogInfo->CallId();
    }

// -----------------------------------------------------------------------------
// CPELogEvent::IsCompleted
// Returns flag if the entry has been completed, ie. no further updates are expected
// -----------------------------------------------------------------------------
//
TBool CPELogEvent::IsCompleted
        (
        // None
        )
    {       
    return iCompleted;
    }

// -----------------------------------------------------------------------------
// CPELogEvent::Added
// iAdded flag is set to ETrue
// -----------------------------------------------------------------------------
//
void CPELogEvent::SetAdded
        (
        // None
        )
    {       
    iAdded = ETrue;
    }

// -----------------------------------------------------------------------------
// CPELogEvent::SaveLeave
// Return value of save leave flag
// -----------------------------------------------------------------------------
//
TBool CPELogEvent::SaveLeave
        (
        // None
        )
    {       
    return iSaveLeave;
    }

// -----------------------------------------------------------------------------
// CPELogEvent::SetPhoneNumberId
// Set event subject.
// -----------------------------------------------------------------------------
//
/*****************************************************
*    Series 60 Customer / LOGENG
*    Series 60  LOGENG API
*****************************************************/
void CPELogEvent::SetPhoneNumberId()
    {
    TBuf<KPhonebookTypeIdLength> subject;
    subject.Zero();

    switch ( iLogInfo->PhoneNumberId() )
        {
        case EPEMobileNumber:
            subject.AppendNum( EPbkFieldIdPhoneNumberMobile );
            break;
        case EPETelephoneNumber:
            subject.AppendNum( EPbkFieldIdPhoneNumberGeneral );
            break;
        case EPEPager:
            subject.AppendNum( EPbkFieldIdPagerNumber );
            break;
        case EPEFaxNumber:
            subject.AppendNum( EPbkFieldIdFaxNumber );
            break; 
        case EPEAssistantNumber:
            subject.AppendNum( EPbkFieldIdAssistantNumber);
            break;
        case EPECarNumber:
            subject.AppendNum( EPbkFieldIdCarNumber);
            break;
        default:
            subject.AppendNum( EPbkFieldIdNone );
            break;
        }

    if ( subject.Length() > 0 )
        {
        iEvent->SetSubject( subject );
        }
    }

// -----------------------------------------------------------------------------
// CPEGsmLogsEntry::SetEventType
// Set event type.
// -----------------------------------------------------------------------------
//
/*****************************************************
*    Series 60 Customer / LOGENG
*    Series 60  LOGENG API
*****************************************************/
void CPELogEvent::SetEventTypeL()
    {
    switch ( iLogInfo->EventType() )
        {
        case CPELogInfo::EPEVoiceEvent:
            
            {
            iEvent->SetEventType( KLogCallEventTypeUid );
            }
            break;
        case CPELogInfo::EPEVideoCallEvent:
            {           
            iEvent->SetEventType( KLogCallEventTypeUid );
            iEvent->SetDataL( KLogsDataFldTag_VT );
            TEFLOGSTRING( KTAINT, "LOG CPELogEvent::SetEventTypeL() video" );                
            }
            break;
        case CPELogInfo::EPEEmergecyEvent:
            {           
            iEvent->SetEventType( KLogCallEventTypeUid );
            iEvent->SetDataL( KLogsDataFldTag_Emergency );
            TEFLOGSTRING( KTAINT, "LOG CPELogEvent::SetEventTypeK() Emergecy" );                
            }
            break;
        case CPELogInfo::EPEVoIPEvent:
            {
            iEvent->SetEventType( KLogCallEventTypeUid );
            iEvent->SetDataL( KLogsDataFldTag_IP );
            TEFLOGSTRING( KTAINT, "LOG CPELogEvent::SetEventTypeL() VoIP" );                
            }
            break;
        case CPELogInfo::EPEUnknownEvent:
        default:
            {
            iEvent->SetEventType( KLogCallEventTypeUid );
            }
            break;
        }
    }

// -----------------------------------------------------------------------------
// CPELogEvent::SetLogEvent
// Set the rest of event information.
// -----------------------------------------------------------------------------
//
/*****************************************************
*    Series 60 Customer / LOGENG
*    Series 60  LOGENG API
*****************************************************/
void CPELogEvent::SetLogEvent()
    {
    if( CCCECallParameters::ECCELineTypeAux == iLogInfo->CurrentLine() )
        {
        iEvent->SetFlags( KPELogEventALS );             
        }
    if ( RMobileCall::EMobileOriginated == iLogInfo->CallDirection() )
        {     
        if ( CCCECallParameters::ECCELineTypeAux == iLogInfo->CurrentLine() )
            {
            iEvent->SetDirection( iOwner.LogStringOutAlt( ) );
            }
        else
            {
            iEvent->SetDirection( iOwner.LogStringOut( ) );    
            }
        }
    else if ( RMobileCall::EMobileTerminated == iLogInfo->CallDirection() )
        {
        if ( iLogInfo->MissedCall() && EPEStateIdle == iLogInfo->CallState() )
            {
            iEvent->SetDirection( iOwner.LogStringMissed( ) );
            }
        else
            //Logging on states Connected and Idle
            {
            if ( CCCECallParameters::ECCELineTypeAux == iLogInfo->CurrentLine() )
                {
                iEvent->SetDirection( iOwner.LogStringInAlt( ) );
                }
            else
                {
                iEvent->SetDirection( iOwner.LogStringIn( ) );
                }
            }
        }

    SetRemoteParty( *iEvent, *iLogInfo );
    iEvent->SetStatus( iOwner.LogStringDelivery( ) );
    
    SetRemoteContact( *iEvent, *iLogInfo );
    
    if ( KNullDesC() != iLogInfo->MyAddress() )
        {
        TRAPD( error, SetDataFieldL( KLogsDataFldTag_MA, iLogInfo->MyAddress() ) );
        if ( error )
            {
            TEFLOGSTRING2( KTAERROR, 
                "LOG CPELogEvent::SetLogEvent()>SetDataFieldL(), error=%d", 
                    error )
            }
        }
    }


// -----------------------------------------------------------------------------
// CPELogEvent::SetDuration
// Set the event duration
// -----------------------------------------------------------------------------
//
/*****************************************************
*    Series 60 Customer / LOGENG
*    Series 60  LOGENG API
*****************************************************/
void CPELogEvent::SetDuration()
    {
    iEvent->SetDurationType( KLogDurationValid );
    iEvent->SetDuration( static_cast <TLogDuration> ( iLogInfo->Duration().Int() ) );

#ifdef _DEBUG
    if ( EPEStateIdle == iLogInfo->CallState() )
        {
        // debug logging of the event start time.
        TBuf<KPEESDWFormattedTimeLength> formattedTime;
        formattedTime.Zero();
        TRAPD( error, iEvent->Time().FormatL( formattedTime, KPEESDWTimeFormat ) );    
        if( error == KErrNone )
            {
            TEFLOGSTRING2( KTAINT, "LOG CPELogEvent::SetDuration() Idle state > formattedTime: %S", &formattedTime );
            }
        else
            {
            TEFLOGSTRING( KTAERROR, "LOG CPELogEvent::SetDuration() Idle state > time conversion failed!");
            }        
        }
#endif // _DEBUG
    }

// -----------------------------------------------------------------------------
// CPELogEvent::SetServiceIdL
// Set callers service id to log event.
// -----------------------------------------------------------------------------
//
void CPELogEvent::SetServiceIdL()
    {
    HBufC8* eventData = NULL; 
    if ( iEvent->Data().Length() )
        {
        // There are existing data logged.
        eventData = HBufC8::NewLC( iEvent->Data().Length() 
                   + KLogsDataFldNameDelimiter().Length() // separator
                   + KLogsDataFldTag_ServiceId().Length()
                   + KLogsDataFldValueDelimiter().Length()
                   + KTUintCharLength );    
                   
        // Copy existing data to temp buffer.
        eventData->Des().Copy( iEvent->Data() );
   
        // Append tag separator.
        eventData->Des().Append( KLogsDataFldNameDelimiter );    
        }
    else
        {
        // No existing data logged. 
        eventData = HBufC8::NewLC( 
            KLogsDataFldTag_ServiceId().Length()
            + KLogsDataFldValueDelimiter().Length()
            + KTUintCharLength ); 
        }
    
    // Append service id
    eventData->Des().Append( KLogsDataFldTag_ServiceId );
    eventData->Des().Append( KLogsDataFldValueDelimiter );
    eventData->Des().AppendNum( (TInt)iLogInfo->ServiceId() );
    
    iEvent->SetDataL( *eventData );
    TEFLOGSTRING( KTAINT, "LOG CPELogEvent::SetServiceIdL() Service id set ok" );  
    CleanupStack::PopAndDestroy( eventData );
    }

// -----------------------------------------------------------------------------
// Sets callers contact link to log event.
// Contact link data might accidentally contain "\t"(KLogsDataFldNameDelimiter),
// because of this, those "accidents" are stuffed with another "\t". They are
// removed in logs handling side when data is read in.
// -----------------------------------------------------------------------------
//
void CPELogEvent::SetContactLinkL()
    {
    HBufC8* eventData = NULL;
    
    TPtrC8 pDelimiter( iLogInfo->ContactLink() );
    TInt delimiterCount = 0;
    // Check how many "delimiters" data contains so that we can
    // reserve space for data duplication
    while ( KErrNotFound != pDelimiter.Find( KLogsDataFldNameDelimiter ) )
        {
        // Skip first \t to see if there exists another one after that 
        pDelimiter.Set( pDelimiter.Mid( pDelimiter.Find( KLogsDataFldNameDelimiter ) + KOneChar ) );
        ++delimiterCount;
        }
    if ( iEvent->Data().Length() )
        {
        // There is previous data logged
        eventData = HBufC8::NewLC( 
            iEvent->Data().Length() 
            + KLogsDataFldNameDelimiter().Length() // separator
            + KLogsDataFldTag_ContactLink().Length() 
            + KLogsDataFldValueDelimiter().Length()
            + iLogInfo->ContactLink().Length() 
            + delimiterCount );
                   
        // Copy previous data to temp buffer
        eventData->Des().Copy( iEvent->Data() );
   
        // Append tag separator
        eventData->Des().Append( KLogsDataFldNameDelimiter );    
        }
    else
        {
        // No previous data logged. 
        eventData = HBufC8::NewLC( 
                KLogsDataFldTag_ContactLink().Length() 
            + KLogsDataFldValueDelimiter().Length()
            + iLogInfo->ContactLink().Length() 
            + delimiterCount ); 
        }
    
    TPtr8 eventDataPtr( eventData->Des() );
    eventDataPtr.Append( KLogsDataFldTag_ContactLink );
    eventDataPtr.Append( KLogsDataFldValueDelimiter );
    
    if ( delimiterCount )
        {
        // Link data contained unintended \t chars
        TPtrC8 linkPtr( iLogInfo->ContactLink() );
        TInt dataLength = 0;
        // Copy link data between \t chars
        for ( TInt i = 0; i < delimiterCount; i++ )
            {
            // Plus one because we need length, not offset
            dataLength = linkPtr.Find( KLogsDataFldNameDelimiter ) + KOneChar;
            // Append from beginning of data, including \t
            eventDataPtr.Append( linkPtr.Left( dataLength ) );
            // Add another \t
            eventDataPtr.Append( KLogsDataFldNameDelimiter );
            linkPtr.Set( linkPtr.Mid( dataLength ) );
            }
        // Copy rest of link data
        eventDataPtr.Append( linkPtr );
        }
    else
        {
        // Link data didn't contain \t, so normal copy is possible
        eventDataPtr.Append( iLogInfo->ContactLink() );
        }
    
    iEvent->SetDataL( *eventData );
    TEFLOGSTRING( KTAINT, "LOG CPELogEvent::ContactLinkL() Contact link set ok" );
    CleanupStack::PopAndDestroy( eventData );
    }

// -----------------------------------------------------------------------------
// CPELogEvent::SetDataFieldL
// -----------------------------------------------------------------------------
//
void CPELogEvent::SetDataFieldL( const TDesC8& aTag, const TDesC& aFieldData )
    {
    __ASSERT_ALWAYS( aTag.Length() != 0 && aFieldData.Length() != 0 ,
        User::Leave( KErrArgument ) );
    
    if ( KErrNotFound == iEvent->Data().Find( aTag ) )
        {
        HBufC8* eventData = NULL;
        const TInt fieldLength = aTag.Length() 
            + KLogsDataFldValueDelimiter().Length()
            + aFieldData.Length();
        const TInt oldDataFieldLength = iEvent->Data().Length();
        
        if ( oldDataFieldLength != 0 )
            {
            const TInt newDataFieldLength = oldDataFieldLength 
                + KLogsDataFldNameDelimiter().Length()
                + fieldLength;
            
            eventData = HBufC8::NewLC( newDataFieldLength );
            
            // Copy previous data
            eventData->Des().Copy( iEvent->Data() );
            eventData->Des().Append( KLogsDataFldNameDelimiter );
            }
        else
            {
            eventData = HBufC8::NewLC( fieldLength );
            }
        
        // Add a new data field.
        eventData->Des().Append( aTag );
        eventData->Des().Append( KLogsDataFldValueDelimiter );
        eventData->Des().Append( aFieldData );     
        iEvent->SetDataL( *eventData );
        
        CleanupStack::PopAndDestroy( eventData );
        }
    }

// -----------------------------------------------------------------------------
// CPELogEvent::SetRemoteParty
// -----------------------------------------------------------------------------
//
void CPELogEvent::SetRemoteParty( CLogEvent& aEvent, 
        const CPELogInfo& aLogInfo )
    {
    if ( KNullDesC() != aLogInfo.Name() )
        {
        // This if clause fixes ou1cimx1#320365 Wrong address shown in received log entry
        if ( aLogInfo.EventType() != CPELogInfo::EPEVoIPEvent ||
             KNullDesC() == aEvent.RemoteParty() )
            {
            aEvent.SetRemoteParty( aLogInfo.Name() );
            }
        }
    }


// -----------------------------------------------------------------------------
// CPELogEvent::SetRemoteContact
// -----------------------------------------------------------------------------
//
void CPELogEvent::SetRemoteContact( CLogEvent& aEvent, 
        const CPELogInfo& aLogInfo )
    {
    if ( KNullDesC() != aLogInfo.PhoneNumber() )      
        {
        if ( aLogInfo.EventType() != CPELogInfo::EPEVoIPEvent ||
             ( KNullDesC() == aEvent.Number() &&
               KErrNotFound == iEvent->Data().Find( KLogsDataFldTag_URL ) ) )
            {
            aEvent.SetNumber( aLogInfo.PhoneNumber() );
            }
        }
    
    else if ( KNullDesC() != aLogInfo.VoipAddress() &&
              KNullDesC() == aEvent.Number())
        {
        TRAPD( error, SetDataFieldL( KLogsDataFldTag_URL, aLogInfo.VoipAddress() ) );
        if ( error )
            {
            TEFLOGSTRING2( KTAERROR, 
                "LOG CPELogEvent::SetRemoteContact()>SetDataFieldL(), error=%d", error )
            }
        }
    }


// ================= OTHER EXPORTED FUNCTIONS ===============================

//  End of File 

