// Copyright (c) 2007-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:
//




// INCLUDE FILES
#include <e32svr.h>
#include <s32mem.h>
#include "featmgrclient.h"
#include "featmgrconfiguration.h"
#include "featmgrdebug.h"
#include "featmgrclientserver.h"

// CONSTANTS
const TInt KRetry( 2 );

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

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// RFeatMgrClient::RFeatMgrClient
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
RFeatMgrClient::RFeatMgrClient()
    : RSessionBase(), iFeaturePckg( NULL, 0, 0 )
    {
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::Connect
// Connects to server
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::Connect()
    {
    FUNC_LOG

    // Try this twice
    TInt retry( KRetry );
    TInt err( KErrNone );

    while ( retry > 0 )
        {
        // Try to create a FeatMgr Server session
        err = CreateSession( KServerProcessName, 
                             ServerVersion(), 
                             KDefaultAsyncSlots );

        LOG_IF_ERROR1( err, "RFeatMgrClient::Connect - CreateSession returned: %d", err );
    
        if ( err != KErrNotFound && err != KErrServerTerminated )
            {
            // KErrNone or unrecoverable error
            retry = 0;
            }
        else
            {
            // Return code was KErrNotFound or KErrServerTerminated.
            // Try to start a new FeatMgr Server
            err = StartServer();

            LOG_IF_ERROR1( err, "RFeatMgrClient::Connect - StartServer returned: %d", err );

            if ( err != KErrNone && err != KErrAlreadyExists )
                {
                // Unrecoverable error
                retry = 0;
                }
            }
            
        retry--;
        }
            
    return err;
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::StartServer
// Starts server.
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::StartServer()
    {
    FUNC_LOG
    TIMESTAMP( "StartServer start: " )

    RProcess server;
    const TUidType serverUid( KNullUid, KServerUid2, KNullUid );
    TInt err = server.Create( KServerExeName, // FeatMgrServer.exe
                           KNullDesC, // A descriptor containing data passed as 
                                      // an argument to the thread function of 
                                      // the new process's main thread, when it 
                                      // is first scheduled.
                           serverUid, // FeatMgr server UID
                           EOwnerProcess ); // Ownership of this process handle 

    // Return error code if we couldn't create a process
    if ( err == KErrNone )
        {
        // Rendezvous is used to detect server start
        TRequestStatus stat;
        server.Rendezvous( stat );

        if ( stat != KRequestPending )
            {
            server.Kill( KErrNone ); // Abort startup
            }
        else
            {
            server.Resume();  // Logon OK - start the server
            }

        INFO_LOG( "RFeatMgrClient::StartServer - Waiting server startup" );

        User::WaitForRequest( stat ); // Wait for start or death

        INFO_LOG( "RFeatMgrClient::StartServer - Server startup wait finished" );
        
        // We can't use the 'exit reason' if the server paniced as this
        // is the panic 'reason' and may be '0' which cannot be distinguished
        // from KErrNone
        err = (server.ExitType() == EExitPanic)? KErrGeneral : stat.Int();

        // We can close the handle now
        server.Close();        
        }

    TIMESTAMP( "StartServer end: " )

    return err;
    }


// -----------------------------------------------------------------------------
// RFeatMgrClient::ServerVersion
// Return version of server
// -----------------------------------------------------------------------------
//
TVersion RFeatMgrClient::ServerVersion() const 
    {
    return TVersion( KServerVersionMajor, KServerVersionMinor, KServerVersionBuild );
    }


// -----------------------------------------------------------------------------
// RFeatMgrClient::FeatureSupported()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::FeatureSupported( TFeatureEntry& aFeature ) const
    {  
    TPckg<TFeatureEntry> pckg( aFeature );
    TPckgBuf<TInt> pckgRet;
    
    TInt retval = SendReceive(EFeatMgrFeatureSupported, TIpcArgs( &pckg, &pckgRet ));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::FeatureSupported - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG2( "RFeatMgrClient::FeatureSupported - uid %d, supported %d",
                            aFeature.FeatureUid().iUid, pckgRet() );   
    return pckgRet();
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::FeaturesSupported()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::FeaturesSupported( RFeatureArray& aFeatures )
    {  
    TPckgBuf<TInt> pckg;
    
    TInt retval( KErrNone );
    
    TRAP( retval, SendRcvFeatureArrayL( aFeatures, pckg() ) );

    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::FeaturesSupported - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::FeaturesSupported - return %d", pckg() );
    return pckg();
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::EnableFeature()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::EnableFeature( TUid aFeature ) const
    {  
    TPckgBuf<TInt> pckg;
    
    TInt retval = SendReceive(EFeatMgrEnableFeature, TIpcArgs(aFeature.iUid, &pckg));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::EnableFeature - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::EnableFeature - return %d", pckg() );
    return pckg();
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::DisableFeature()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::DisableFeature( TUid aFeature ) const
    {  
    TPckgBuf<TInt> pckg;
    
    TInt retval = SendReceive(EFeatMgrDisableFeature, TIpcArgs(aFeature.iUid, &pckg));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::DisableFeature - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::DisableFeature - return %d", pckg() );
    return pckg();
    }
    
// -----------------------------------------------------------------------------
// RFeatMgrClient::SetFeature()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::SetFeature( TUid aFeature, TBool aEnable, TInt aData ) const
    {  
    TPckgBuf<TInt> pckg;
    
    TInt retval = SendReceive(EFeatMgrSetFeatureAndData, TIpcArgs(
        aFeature.iUid, aEnable, aData, &pckg));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::SetFeature - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::SetFeature - return %d", pckg() );
    return pckg();
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::SetFeature()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::SetFeature( TUid aFeature, TInt aData ) const
    {  
    TPckgBuf<TInt> pckg;
    
    TInt retval = SendReceive(EFeatMgrSetFeatureData, TIpcArgs(
        aFeature.iUid, aData, &pckg));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::SetFeature - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::SetFeature - return %d", pckg() );
    return pckg();
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::AddFeature()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::AddFeature( TFeatureEntry aFeature ) const
    {  
    TPckg<TFeatureEntry> pckg( aFeature );
    TPckgBuf<TInt> pckgRet;
    
    TInt retval = SendReceive(EFeatMgrAddFeature, TIpcArgs(&pckg, &pckgRet));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::AddFeature - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::AddFeature - return %d", pckgRet() );
    return pckgRet();
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::DeleteFeature()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::DeleteFeature( TUid aFeature ) const
    {  
    TPckgBuf<TInt> pckg;
    
    TInt retval = SendReceive(EFeatMgrDeleteFeature, TIpcArgs(aFeature.iUid, &pckg));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::DeleteFeature - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::DeleteFeature - return %d", pckg() );
    return pckg();
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::ListSupportedFeaturesL()
// -----------------------------------------------------------------------------
//
void RFeatMgrClient::ListSupportedFeaturesL( RFeatureUidArray& aSupportedFeatures )
    {  
    // Reset as array might contain old data.
    aSupportedFeatures.Reset();
    TInt retry( 5 );
    TInt err( KErrNone );
    TInt count;
    TPckg<TInt> sizePckg( count );
    
    while ( retry > 0 )
        {
        User::LeaveIfError( SendReceive( EFeatMgrNumberOfSupportedFeatures, 
            TIpcArgs( &sizePckg ) ) );
        
        HBufC8* buf = HBufC8::NewLC( count * sizeof( TInt ) );
        TPtr8 ptr = buf->Des();
        
        err = SendReceive( EFeatMgrListSupportedFeatures, TIpcArgs( count, &ptr ) );
        LOG_IF_ERROR1( err, "RFeatMgrClient::ListSupportedFeaturesL - SendReceive error %d", err );
        INFO_LOG1( "RFeatMgrClient::ListSupportedFeaturesL - count %d", count );

        if ( err == KErrNone )
            {
            aSupportedFeatures.ReserveL( count );
                
            for ( TInt i = 0; i < count; i++ )
                {
                TPtrC8 featurePtr = ptr.Mid( i * sizeof( TUid ), sizeof( TUid ) );
                TUid featureId = TUid::Uid( 0 );                    
                TPckg<TUid> feature( featureId );
                feature.Copy( featurePtr );
                aSupportedFeatures.AppendL( featureId );
                }

            retry = 0;
            }
        else if ( err == KErrServerBusy )
            {
            retry--;       
            }
        else
            {
            User::Leave( err );
            }
        CleanupStack::PopAndDestroy( buf );
        }   
        
    User::LeaveIfError( err );
    }


// -----------------------------------------------------------------------------
// RFeatMgrClient::ReRequestNotification(TUid&, TRequestStatus&)
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::ReRequestNotification( TUid& aFeatUid, TRequestStatus& aStatus )
    {
    TPckgBuf<TInt> pckg;
    TInt retval( KErrNone );
    
	iFeaturePckg.Set( (TUint8*) &aFeatUid.iUid, sizeof(TUid), sizeof(TUid) );
	TIpcArgs args( &iFeaturePckg );
	SendReceive( EFeatMgrReqNotify, args, aStatus );

    return retval;
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::RequestNotification(RFeatureUidArray&, TUid&, TRequestStatus&)
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::RequestNotification( RFeatureUidArray& aFeatures, 
        TUid& aFeatUid, TRequestStatus& aStatus )
    {
    TPckgBuf<TInt> pckg;
    
    TInt retval( KErrNone );
    
    TRAP( retval, SendUidArrayL( aFeatures, pckg() ) );

    if ( retval == KErrNone )
        {
    	iFeaturePckg.Set( (TUint8*) &aFeatUid.iUid, sizeof(TUid), sizeof(TUid) );
    	TIpcArgs args( &iFeaturePckg );
        SendReceive( EFeatMgrReqNotify, args, aStatus );
        }
    else
        {
        ERROR_LOG1( "RFeatMgrClient::RequestNotification - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::RequestNotification - return %d", pckg() );
    return pckg();
    }
        
// -----------------------------------------------------------------------------
// RFeatMgrClient::RequestNotifyCancel(TUid)
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::RequestNotifyCancel( TUid aFeature ) const
    {
    TPckgBuf<TInt> pckg;
    
    TInt retval = SendReceive(EFeatMgrReqNotifyCancel, TIpcArgs(aFeature.iUid, &pckg));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::RequestNotifyCancel - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::RequestNotifyCancel - return %d", pckg() );
    return pckg();
    }
        
// -----------------------------------------------------------------------------
// RFeatMgrClient::RequestNotifyCancelAll()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::RequestNotifyCancelAll() const
    {
    TPckgBuf<TInt> pckg;
    
    TInt retval = SendReceive(EFeatMgrReqNotifyCancelAll, TIpcArgs(&pckg));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::RequestNotifyCancelAll - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::RequestNotifyCancelAll - return %d", pckg() );
    return pckg();
    }
        
// -----------------------------------------------------------------------------
// RFeatMgrClient::SendUidArrayL()
// -----------------------------------------------------------------------------
//
void RFeatMgrClient::SendUidArrayL( RFeatureUidArray& aFeatures, TInt &retval)
    {
    FUNC_LOG
    
    INFO_LOG1( "RFeatMgrClient::SendUidArrayL - Send %d features", aFeatures.Count() );

    TInt size = aFeatures.Count() * sizeof(TUid);
	CBufBase* buffer = CBufFlat::NewL( size );
	CleanupStack::PushL( buffer );
	buffer->ResizeL( size );

    RBufWriteStream stream( *buffer );
    CleanupClosePushL( stream );
    
    TInt count = aFeatures.Count();
    // Write each field in array to stream
    for(TInt i = 0; i < count; i++)
        {
        stream.WriteUint32L( aFeatures[i].iUid );
        }
    
    stream.CommitL();
    
    // Write transfer buffer to server
	TPtr8 pBuffer(buffer->Ptr(0));
	TPckgBuf<TInt> pckg;
	TIpcArgs args( count, &pBuffer, &pckg );
	TInt sendErr = SendReceive( EFeatMgrReqNotifyUids, args );
	
	retval = pckg();

    CleanupStack::PopAndDestroy( &stream );
    CleanupStack::PopAndDestroy( buffer );
	User::LeaveIfError( sendErr );
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::SendRcvFeatureArrayL()
// -----------------------------------------------------------------------------
//
void RFeatMgrClient::SendRcvFeatureArrayL( RFeatureArray& aFeatures, TInt &retval)
    {
    FUNC_LOG
    
    INFO_LOG1( "RFeatMgrClient::SendRcvFeatureArrayL - Send %d features", aFeatures.Count() );

    TInt size = aFeatures.Count() * sizeof(TFeatureEntry);
	CBufBase* buffer = CBufFlat::NewL( size );
	CleanupStack::PushL( buffer );
	buffer->ResizeL( size );

    RBufWriteStream stream( *buffer );
    CleanupClosePushL( stream );
    
    TInt count = aFeatures.Count();
    // Write each field in array to stream
    for(TInt i = 0; i < count; i++)
        {
        TFeatureEntry entry( aFeatures[i].FeatureUid(), aFeatures[i].FeatureFlags(), 
            aFeatures[i].FeatureData() );
        stream.WriteUint32L( aFeatures[i].FeatureUid().iUid );
        stream.WriteUint32L( aFeatures[i].FeatureFlags().iFlags );
        stream.WriteUint32L( aFeatures[i].FeatureData() );
        stream.WriteUint32L( 0 ); // reserved
        }
    
    stream.CommitL();
    
    // Write transfer buffer to server
	TPtr8 pBuffer(buffer->Ptr(0));
	TPckgBuf<TInt> pckg;
	TIpcArgs args( count, &pBuffer, &pckg );
	TInt sendErr = SendReceive( EFeatMgrFeaturesSupported, args );

    if ( sendErr == KErrNone )
        {
    	TInt responseCount = pckg();
        // Read modified feature entries back to array
        RBufReadStream readStream( *buffer );
        CleanupClosePushL( readStream );
        aFeatures.Reset();
        aFeatures.ReserveL( responseCount );
            
        for ( TInt i = 0; i < responseCount; i++ )
            {
            TUid uid = TUid::Uid( readStream.ReadUint32L() );
            TBitFlags32 flags = readStream.ReadUint32L();
            TUint32 data = readStream.ReadUint32L();
            readStream.ReadUint32L(); // reserved
            TFeatureEntry entry( uid, flags, data );
            aFeatures.AppendL( entry );
            }
            
        CleanupStack::PopAndDestroy( &readStream );
        }

	retval = KErrNone; // Currently no error response exist.

    CleanupStack::PopAndDestroy( &stream );
    CleanupStack::PopAndDestroy( buffer );
	User::LeaveIfError( sendErr );
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::SWIStart()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::SWIStart() const
    {
    TPckgBuf<TInt> pckg;
    
    TInt retval = SendReceive(EFeatMgrSWIStart, TIpcArgs(&pckg));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::SWIStart - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::SWIStart - return %d", pckg() );
    return pckg();
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::SWIEnd()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::SWIEnd() const
    {
    TPckgBuf<TInt> pckg;
    
    TInt retval = SendReceive(EFeatMgrSWIEnd, TIpcArgs(&pckg));
    
    if ( retval != KErrNone )
        {
        ERROR_LOG1( "RFeatMgrClient::SWIEnd - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::SWIEnd - return %d", pckg() ); 
    return pckg();
    }

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



// DEBUG only API functions

#ifdef EXTENDED_FEATURE_MANAGER_TEST
// -----------------------------------------------------------------------------
// RFeatMgrClient::NumberOfNotifyFeatures()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::NumberOfNotifyFeatures( void ) const
    {  
    TInt count;
    TPckg<TInt> sizePckg( count );
    
    TInt retval = SendReceive( EFeatMgrNumberOfNotifyFeatures, TIpcArgs( &sizePckg ) );
    if ( KErrNone != retval )
        {
        ERROR_LOG1( "RFeatMgrClient::NumberOfNotifyFeatures - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::NumberOfNotifyFeatures - return %d", sizePckg() );
    return sizePckg();
    }

// -----------------------------------------------------------------------------
// RFeatMgrClient::CountAllocCells()
// -----------------------------------------------------------------------------
//
TInt RFeatMgrClient::CountAllocCells( void ) const
    {  
    TInt count;
    TPckg<TInt> sizePckg( count );
    
    TInt retval = SendReceive( EFeatMgrCountAllocCells, TIpcArgs( &sizePckg ) );
    if ( KErrNone != retval )
        {
        ERROR_LOG1( "RFeatMgrClient::CountAllocCells - SendReceive error %d", retval );
        return retval;
        }

    INFO_LOG1( "RFeatMgrClient::CountAllocCells - return %d", sizePckg() );
    return sizePckg();
    }

#endif

//  End of File  
