/*
* Copyright (c) 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 implementation of 
* CTestEngineServer class member functions.
*
*/

// INCLUDE FILES
#include <e32std.h>
#include <e32svr.h>
#include <f32file.h>
#include "TestEngine.h"
#include "TestEngineClient.h"
#include "TestEngineCommon.h"
#include <stifinternal/TestServerClient.h>
#include "TestModuleController.h"
#include "TestCaseController.h"
#include "TestReport.h"
#include "Logging.h"
#include "SettingServerClient.h"
//--PYTHON-- begin
#include "StifPython.h"
#include "StifPythonFunEng.h"
//--PYTHON-- end

// EXTERNAL DATA STRUCTURES
// None

// EXTERNAL FUNCTION PROTOTYPES  
// None

// CONSTANTS
_LIT( KTestModule, "TestModule=" );
_LIT( KTestCaseFile, "TestCaseFile=" );
_LIT( KTestCaseNumber, "TestCaseNumber=" );
_LIT( KTestCaseTitle, "TestCaseTitle=" );
_LIT( KStateCode, "StateCode=" );
_LIT( KStateName, "StateName=" );
    
// MACROS
// None

// LOCAL CONSTANTS AND MACROS
// None

// MODULE DATA STRUCTURES
struct TThreadStartTestEngine
    {   
    RThread    iEngineThread; // The server thread
    RSemaphore iStarted;      // Startup syncronisation semaphore   
    };

// LOCAL FUNCTION PROTOTYPES
// None

// FORWARD DECLARATIONS
// None

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

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

/*
-------------------------------------------------------------------------------

    Class: CTestEngine
   
    Function: ErrorPrint

    Description: ErrorPrint

    Parameters: const TInt aPriority: in: Priority of error
                TPtrC aError: in: Error description

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::ErrorPrint( const TInt aPriority, 
                              TPtrC aError )
    {
    TErrorNotification error;
    TErrorNotificationPckg errorPckg ( error );

    error.iModule = _L("TestEngine");
    error.iPriority = aPriority;
    error.iText = aError;

    ErrorPrint( errorPckg );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestModule

    Method: ErrorPrint

    Description: Sends error notification

    Parameters: TErrorNotificationPckg aError: in: Error

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::ErrorPrint( TErrorNotificationPckg aError )
    {
    // Add new item to end of queue
     if ( iErrorQueue.Append ( aError() ) != KErrNone )
            {
            RDebug::Print (_L("Error message lost"));
            return;
            }

    ProcessErrorQueue();

    }

/*
-------------------------------------------------------------------------------

    Class: CTestModule

    Method: ProcessErrorQueue

    Description: Process error queue

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::ProcessErrorQueue()
    {
    // If message is available, complete first item from queue
    if ( iErrorMessageAvailable )
        {
        
        if ( iErrorQueue.Count() > 0 )
            {
            TErrorNotification err = iErrorQueue[0];
            TErrorNotificationPckg errPckg(err);
            iErrorQueue.Remove(0);
        
        	TInt r( KErrNone );
        
            TRAP( r, iErrorMessage.WriteL( 0, errPckg ) );

            // Do not handle errors

            iErrorMessageAvailable = EFalse;
            iErrorMessage.Complete( KErrNone );
            }
        }

    }

/*
-------------------------------------------------------------------------------
   
    Function: LeaveIfErrorWithNotify

    Description: If error leave with notify

    Parameters: TInt aCode: in: Error code
    
    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::LeaveIfErrorWithNotify( TInt aCode )
      {
      LeaveIfErrorWithNotify ( aCode, _L("Check testengine log") );

      }

/*
-------------------------------------------------------------------------------
   
    Function: LeaveIfErrorWithNotify

    Description: If error leave with notify

    Parameters: TInt aCode: in: Error code
                const TDesC& aText: in: Descriptive text

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::LeaveIfErrorWithNotify( TInt aCode,
                                          const TDesC& aText )
    {
    if ( aCode != KErrNone )
        {
           LeaveWithNotifyL ( aCode, aText );
        }

    }

/*
-------------------------------------------------------------------------------

    Function: LeaveWithNotifyL

    Description: Leave with notify

    Parameters: TInt aCode: in: Error code

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::LeaveWithNotifyL( TInt aCode )
    {
    LeaveWithNotifyL ( aCode, _L("Check testengine log") );

    }

/*
-------------------------------------------------------------------------------

    Function: LeaveWithNotifyL

    Description: Leave with notify

    Parameters: TInt aCode: in: Error code
                const TDesC& aText: in: Descriptive text

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::LeaveWithNotifyL( TInt aCode,
                                   const TDesC& aText )
    {
    ErrorPrint ( 0, aText );
    User::Leave ( aCode );

    }

#define LOGGER iLogger

/*
-------------------------------------------------------------------------------

    Function: ThreadFunction

    Description: The thread function, where Test Engine lives in.

    Parameters: TAny* aStarted: in: Start info

    Return Values: TInt: Returns always KErrNone

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEngineServer::ThreadFunction( TAny* aStarted )
    {
//    __UHEAP_MARK;

    // Create cleanup stack
    CTrapCleanup* cleanup = CTrapCleanup::New();
    __ASSERT_ALWAYS( cleanup, PanicServer( ECreateTrapCleanup ) );

    // Get start-up information
    TThreadStartTestEngine* startInfo = ( TThreadStartTestEngine* ) aStarted;
    __ASSERT_ALWAYS( startInfo, PanicServer( ENoStartupInformation ) );

    // Construct and install active scheduler
    CActiveScheduler* scheduler = new CActiveScheduler;
    __ASSERT_ALWAYS( scheduler, PanicServer( EMainSchedulerError ) );
    CActiveScheduler::Install( scheduler );

    // Construct server, an active object
    CTestEngineServer* server = NULL;
    TRAPD( err, server = CTestEngineServer::NewL() );
    __ASSERT_ALWAYS( !err, PanicServer( ESvrCreateServer ) );

    // Inform that we are up and running
    startInfo->iStarted.Signal();

    // Global mutex(handling according to the name)
    RMutex startupMutex;
    // Try to create global mutex, CREATE
    TInt ret = startupMutex.CreateGlobal( KStifTestServerStartupMutex );
    if( ret != KErrNone )
        {
        // Mutex already create, OPEN
        ret = startupMutex.OpenGlobal( KStifTestServerStartupMutex );
        }
    if( ret != KErrNone )
        {
        // Not able to create or open mutex
        return ret;
        }

    // Start handling requests
    CActiveScheduler::Start();

    startupMutex.Close();

    // Should come here after RTestEngineServer is closed
    delete server;
    delete scheduler;
    delete cleanup;

//    __UHEAP_MARKEND;

    return KErrNone;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: CTestEngineServer

    Description: Default constructor

    C++ default constructor can NOT contain any code, that
    might leave.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEngineServer::CTestEngineServer() :
    CServer2( CTestEngineServer::ETestEngineServerPriority ),
    iSessionCount( 0 )
    {

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if CObjectConIx::NewL leaves
                       Leaves if CStifLogger::NewL leaves
                       Leaves if StartL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngineServer::ConstructL()
    {
    // Create container
    iContainerIndex = CObjectConIx::NewL();

    // Create logger, in Wins use HTML in HW default logger
    TLoggerSettings loggerSettings;

    // Directory must create by hand if test engine log wanted
    loggerSettings.iCreateLogDirectories = EFalse;

    loggerSettings.iOverwrite = ETrue;
    loggerSettings.iTimeStamp = ETrue;
    loggerSettings.iLineBreak = ETrue;
    loggerSettings.iEventRanking = EFalse;
    loggerSettings.iThreadId = EFalse;
    loggerSettings.iHardwareFormat = CStifLogger::ETxt;
#ifndef FORCE_STIF_INTERNAL_LOGGING_TO_RDEBUG
    loggerSettings.iEmulatorFormat = CStifLogger::EHtml;
    loggerSettings.iEmulatorOutput = CStifLogger::EFile;
    loggerSettings.iHardwareOutput = CStifLogger::EFile;
#else
    RDebug::Print( _L( "STIF Test Engine logging forced to RDebug" ) );
    loggerSettings.iEmulatorFormat = CStifLogger::ETxt;
    loggerSettings.iEmulatorOutput = CStifLogger::ERDebug;
    loggerSettings.iHardwareOutput = CStifLogger::ERDebug;
#endif
    loggerSettings.iUnicode = EFalse;
    loggerSettings.iAddTestCaseTitle = EFalse;

    iLogger = CStifLogger::NewL( _L( "C:\\logs\\testframework\\testengine\\"),
                                    _L( "testengine" ),
                                    loggerSettings );
    // Start Server
    StartL( KTestEngineName );

    __TRACE(KVerbose, (_L( "CTestEngineServer::ConstructL: Server Created" ) ) );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: NewL

    Description: Two-phased constructor.

    Parameters: None

    Return Values: CTestEngineServer* : pointer to CTestEngineServer object

    Errors/Exceptions: Leaves if construction of CBufferArray fails

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEngineServer* CTestEngineServer::NewL()
    {
    CTestEngineServer* self = new ( ELeave ) CTestEngineServer();
    CleanupStack::PushL( self );      
    self->ConstructL();
    CleanupStack::Pop();

    return self;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: ~CTestEngineServer

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEngineServer::~CTestEngineServer()
    {
    delete iContainerIndex; 

    __TRACE(KAlways, ( _L( "---------------- Log Ended ----------------" ) ) );
    delete iLogger;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: NewContainerL

    Description: Create new container

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if called CreateL method leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
CObjectCon* CTestEngineServer::NewContainerL()
    {
    CObjectCon* container = iContainerIndex->CreateL();

    iSessionCount++;

    return container;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: DeleteContainer

    Description: Deletes a container

    Parameters: CObjectCon* 

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngineServer::DeleteContainer( CObjectCon* aContainer )
    {
    iContainerIndex->Remove( aContainer );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: SessionClosed

    Description: Inform Server that session is closed.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngineServer::SessionClosed()
    {
    // Decrease session count
    iSessionCount--;

    // Check if last session is closed
    if ( iSessionCount <= 0 )
        {
        // Stop the active scheduler
        // Execution will continue in ThreadFunction()
        CActiveScheduler::Stop();
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: NewSessionL

    Description: Create a new client session for this server.

    Parameters: const TVersion& aVersion: in: Client side version number

    Return Values: CSharableSession* : pointer to CSharableSession object

    Errors/Exceptions: Leaves if given version is incorrect
                       Leaves if CTestEngine::NewL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
CSession2* CTestEngineServer::NewSessionL( const TVersion &aVersion,
                                         const RMessage2& /*aMessage*/ ) const
    {
    // Check that version is ok
    TVersion v( KTestEngineMajorVersionNumber,
                KTestEngineMinorVersionNumber,
                KTestEngineBuildVersionNumber );
    if ( !User::QueryVersionSupported( v, aVersion ) )
        {
        User::Leave( KErrNotSupported );
        }

    return CTestEngine::NewL( ( CTestEngineServer* ) this );
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: PanicServer

    Description: Panic the server

    Parameters: TTestEnginePanic aPanic: in: Panic number

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngineServer::PanicServer( TTestEnginePanic aPanic )
    {
    _LIT( KTestServer, "CTestEngineServer" );
    User::Panic( KTestServer, aPanic );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineServer

    Method: Logger

    Description: Return the pointer to iLogger.

    Parameters: None

    Return Values: CStifLogger*: Pointer to StifLogger

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CStifLogger* CTestEngineServer::Logger()
    {
    return iLogger;

    }

/*
-------------------------------------------------------------------------------

    DESCRIPTION

    This module contains implementation of CTestEngine class member functions.

-------------------------------------------------------------------------------
*/
#undef LOGGER
#define LOGGER Logger()

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

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: CTestEngine

    Description: Default constructor

    C++ default constructor can NOT contain any code, that
    might leave.

    Parameters: RThread& aClient: in: Client's thread

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
    CTestEngine::CTestEngine() :
        CSession2(),
    iReportMode( CTestReport::ETestReportFull ),
    iReportOutput( CTestReport::ETestReportNone ),
    iEnumerateModuleCount( 0 ),
    iIsTestReportGenerated( EFalse ),
    iDisableMeasurement( EEnableAll)
    {

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: CTestEngineServer* aServer: in: Pointer to CTestEngineServer

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::ConstructL( CTestEngineServer* aServer )
    {
    // Second-phase construct base class
    //CSession2::CreateL();

    iTestEngineServer = aServer;

    // Create new object index
    iTestEngineSubSessions = CObjectIx::NewL();

    // Create new object index
    iTestCases = CObjectIx::NewL();
    
    // Initialize the object container from Server
    iContainer = iTestEngineServer->NewContainerL();

    __TRACE( KInit, ( _L( "CTestEngine::ConstructL: Test Engine Created" ) ) );

   
    RFs iFs;
    User::LeaveIfError( iFs.Connect() );
    _LIT(KCSteve,"C:\\Testframework\\");
    iFs.MkDirAll(KCSteve);
      
    iFs.Close();
    
    iRebootDefaultPath.Set( _L( "C:\\TestFramework\\" ) );
    iRebootDefaultFilename.Set( _L( "Reboot.txt" ) );

    TPtrC dllName;
    dllName.Set( _L( "StifHWResetStub.dll" ) );
    iDeviceResetDllName = dllName.AllocL();

    iDefaultTimeout = 0;
    iUITestingSupport = EFalse;
    iSeparateProcesses = EFalse;
    
    iIndexTestModuleControllers = 1;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: NewL

    Description: Two-phased constructor.

    Parameters: RThread& aClient : Client's thread
                CTestEngineServer* aServer : Pointer to CTestEngineServer

    Return Values: CTestEngine* : pointer to CTestEngine object

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEngine* CTestEngine::NewL( CTestEngineServer* aServer )
    {
    CTestEngine* self = new ( ELeave ) CTestEngine();
    CleanupStack::PushL( self );
    self->ConstructL( aServer );
    CleanupStack::Pop();
    return self;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: CloseSession

    Description: Close client server session to Test Engine

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::CloseSession() 
    {
    __TRACE( KInit, ( _L( "CTestEngine::CloseSession" ) ) );

    iErrorQueue.Close();

    // Delete test report
    delete iTestReport;
    iTestReport = NULL;

    // Delete device reset module's DLL name
    delete iDeviceResetDllName;
    iDeviceResetDllName = NULL;

    // Delete state events
    iStateEvents.ResetAndDestroy();
    iStateEvents.Close();

    //Delete Client events
    iClientEvents.ResetAndDestroy();
    iClientEvents.Close();

    // Remove contents of iTestCases
    if ( iTestCases )
        {
        TInt handle;
        CObject* object = NULL;
        TInt count = iTestCases->Count();

        for ( TInt i = 0; i < count; i++ )
            {
            object = iTestCases->operator[](i);
            if ( object )
                {
                handle = iTestCases->At( object );
                iTestCases->Remove( handle );       
                }
            }

        delete iTestCases;
        iTestCases = NULL;
        }
    
    delete iTestEngineSubSessions;
    iTestEngineSubSessions = NULL;

    // Delete the object container
    // This provides unique ids for the objects of this session
    iTestEngineServer->DeleteContainer( iContainer );

    // Inform server that session is closed
    iTestEngineServer->SessionClosed();

    delete iIniFile;
    iIniFile = NULL;

    delete iRebootPath;
    iRebootPath = NULL;

    delete iRebootFilename;
    iRebootFilename = NULL;

    delete iRebootParams;
    iRebootParams = 0;

    __TRACE(KVerbose, ( _L( "CTestEngine::CloseSession finished" ) ) );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: CountResources

    Description: Resource counding

    Parameters: None

    Return Values: TInt Resource count

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEngine::CountResources()
    {
    return iResourceCount;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: NumResources

    Description: Get resources, writes to Message()

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::NumResources( const RMessage2& aMessage )
    {

    TInt ret( 0 );

    TPckgBuf<TInt> countPckg( iResourceCount );

    TRAP( ret, aMessage.WriteL( 0, countPckg ) );

    if ( ret != KErrNone )
        {
        PanicClient( EBadDescriptor, aMessage );
        }


    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: PanicClient

    Description: Panic the client

    Parameters: TTestEnginePanic aPanic: in: Panic number

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::PanicClient( TTestEnginePanic aPanic,
                                const RMessage2& aMessage ) const
    {
    iTestEngineServer->Logger()->Log( CStifLogger::ERed, _L( "CTestEngine::PanicClient [%d]" ), aPanic );

    _LIT( KTestEngine, "CTestEngine" );

    aMessage.Panic( KTestEngine, aPanic );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: ServiceL

    Description: Message handling method that calls trapped DispatchMessageL

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Error from DispatchMessageL is trapped and handled

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::ServiceL( const RMessage2& aMessage )
    {
    TRAPD( ret, DispatchMessageL( aMessage ) );
    if ( ret != KErrNone )
        {
         __TRACE(KError, ( CStifLogger::ERed, _L( "CTestEngine::DispatchMessageL Function=[%d], left with [%d]" ),
                                                aMessage.Function(), ret ) );
        if( ret == KErrNoMemory )
            {
            __TRACE( KError, ( CStifLogger::ERed, _L( "No memory available. Some possibility to do: 1. Reduce test case count. 2. Increase StifTestEngine's heap size." ) ) );
            }
        aMessage.Complete( ret );
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: DispatchMessageL

    Description: Actual message handling

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::DispatchMessageL( const RMessage2& aMessage )
    {
    iComplete = ETrue;
    iReturn = KErrNone;

    switch ( aMessage.Function() )
        {
        case ETestEngineServerCloseSession:
            {
            if ( !iIsTestReportGenerated  && iTestReport )
                {
                iTestReport->GenerateReportL();
                iIsTestReportGenerated = ETrue;
                }               
            CloseSession();
            break;
            }
        case ETestEngineCreateSubSession:
            {
            InitEngineL( aMessage );
            break;
            }
        case ETestEngineCloseSubSession:
            {
            CloseTestEngineL( aMessage.Int3() );
            break;
            }
        case ETestEngineSetAttribute:
            {
            SetAttributeL( aMessage );
            break;
            }

        case ETestEngineAddTestModule:
            {
            AddTestModuleL( aMessage );
            break;
            }
        case ETestEngineRemoveTestModule:
            {
            iReturn = RemoveTestModuleL( aMessage );
            break;
            }
        case ETestEngineAddConfigFile:
            {
            AddConfigFileL( aMessage );
            break;
            }
        case ETestEngineRemoveConfigFile:
            {
            RemoveConfigFileL( aMessage );
            break;
            }
        case ETestEngineEnumerateTestCases:
            {
            EnumerateTestCasesL( aMessage );
            break;
            }
        case ETestEngineGetTestCases:
            {
            GetTestCasesL( aMessage );
            break;
            }
        case ETestEngineCancelAsyncRequest:
            {
            CancelAsyncRequest( aMessage );
            break;
            }
        case ETestEngineEvent:
            {
            EventControlL( aMessage );
            iComplete = EFalse;
            break;
            }
        case ETestEngineErrorNotification:
            {
            HandleErrorNotificationL( aMessage );
            iComplete = EFalse;
            break;
            }
        case ETestEngineLoggerSettings:
            {
            LoggerSettings( aMessage );
            break;
            }
        case ETestEngineCloseLoggerSettings:
            {
            CloseLoggerSettings();
            break;
            }
        case ETestEngineReportTestCase:
            {
            iReturn = AddTestCaseToTestReport(aMessage);
            break;
            }
        // Subsession specific functions
        case ETestCaseCreateSubSession:
            {
            NewTestCaseL( aMessage );
            break;
            }
        case ETestCaseCloseSubSession:
            {
            DeleteTestCase( aMessage.Int3() );
            break;
            }
        case ETestCaseRunTestCase:
            {
            TestCaseByHandle( aMessage.Int3(), aMessage )->RunTestCaseL( aMessage );
            iComplete = EFalse;
            break;
            }
        case ETestCasePause:
            {
            iReturn = TestCaseByHandle( aMessage.Int3(), aMessage )->Pause();
            break;
            }
        case ETestCaseResume:
            {
            iReturn = TestCaseByHandle( aMessage.Int3(), aMessage )->Resume();
            break;
            }
        case ETestCaseNotifyProgress:
            {
            TestCaseByHandle( aMessage.Int3(), aMessage )->NotifyProgressL( aMessage );
            iComplete = EFalse;
            break;
            }
        case ETestCaseNotifyRemoteType:
            {
            TestCaseByHandle( aMessage.Int3(), aMessage )->NotifyRemoteTypeL( aMessage );
            iComplete = EFalse;
            break;
            }
        case ETestCaseNotifyRemoteMsg:
            {
            TestCaseByHandle( aMessage.Int3(), aMessage )->NotifyRemoteMsgL( aMessage );
            iComplete = EFalse;
            break;
            }
        case ETestCaseCancelAsyncRequest:
            {
            TestCaseByHandle( 
                aMessage.Int3(), aMessage )->CancelAsyncRequest( aMessage );
            break;
            }
        default:
            {
            User::Leave( KErrNotSupported );
            break;
            }
        }
    
    if ( iComplete )
        {
        aMessage.Complete( iReturn );
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: InitTestReportAndLoggerVarL

    Description: Initialize Test report and Logger's overwrite parameters

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if memory allocation fails

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::InitTestReportAndLoggerVarL()
    {
    // Test report settings initialization
    iTestEngineServer->iTestReportSettings.iCreateTestReport = ETrue;
    _LIT( path, "C:\\LOGS\\TestFramework\\");
    _LIT( name, "TestReport");
    iTestEngineServer->iTestReportSettings.iPath = path().AllocL();
    iTestEngineServer->iTestReportSettings.iName = name().AllocL();
    iTestEngineServer->iTestReportSettings.iFormat = CStifLogger::ETxt;
    iTestEngineServer->iTestReportSettings.iOutput = CStifLogger::EFile;
    iTestEngineServer->iTestReportSettings.iOverwrite = ETrue;

    // Initializations to indicator is setting in use
    iTestEngineServer->iLoggerSettings.iIsDefined.iCreateLogDir = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iPath = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iHwPath = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iFormat = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iHwFormat = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iOutput = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iHwOutput = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iOverwrite = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iLineBreak = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iTimeStamp = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iEventRanking = EFalse;
    iTestEngineServer->iLoggerSettings.iIsDefined.iThreadId = EFalse;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: InitEngineL

    Description: Init the test engine

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::InitEngineL( const RMessage2& aMessage )
    {
  
    // Parse reboot file 
    ParseRebootParamsL();

    TName iniFileName;

    // Read ini file name from aMessage
    aMessage.ReadL( 0, iniFileName );
    TStifUtil::CorrectFilePathL( iniFileName );

    iIniFile = iniFileName.AllocL();

    // HBufC to TPtrC
    TPtrC iniFile( iIniFile->Des() );

    __TRACE( KInit, ( CStifLogger::EBold, _L( "CTestEngine::InitEngineL\t iIniFile=[%S]" ), iIniFile ) );

    // Connect to the Setting server and open handle(Handle will close when
    // closing TestEngine).
    TInt ret = iSettingServer.Connect();
    if ( ret != KErrNone )
        {
        User::Leave( ret );
        }

    InitTestReportAndLoggerVarL();

    if ( iniFile.Length() > 0 )
        {
        Logger()->WriteDelimiter();
        __TRACE( KInit,( _L( "Starting to parse initialization file" ) ) );

        // Set initialization file information to Setting server's side.
        ret = iSettingServer.SetIniFileInformation( iniFileName );
        if ( ret != KErrNone )
            {
            User::Leave( ret );
            }
        // Struct to Logger settigs.
        TLoggerSettings loggerSettings; 
        // Parse Logger defaults from STIF initialization file.
        ret = iSettingServer.ReadLoggerSettingsFromIniFile( loggerSettings );
        if ( ret != KErrNone )
            {
            User::Leave( ret );
            }

        // Create parser for parsing ini file
        CStifParser* parser = NULL;
        TRAPD( r, parser = CStifParser::NewL( _L(""), iniFile ) );
        if ( r != KErrNone )
            {
            __TRACE( KError,( CStifLogger::ERed, _L( "Can't open ini-file [%S], code %d" ), &iniFile, r ) );
            LeaveWithNotifyL(r);
            }

        CleanupStack::PushL( parser );

        CSTIFTestFrameworkSettings* settings = NULL;
        TRAPD( settings_ret, settings = CSTIFTestFrameworkSettings::NewL() );
        CleanupStack::PushL( settings );
        if ( settings_ret != KErrNone )
            {
            __TRACE( KError,( CStifLogger::ERed, _L( "CSTIFTestFrameworkSettings class object creation fails") ) );
            LeaveWithNotifyL( settings_ret );
            }

        ReadEngineDefaultsL( parser, settings );

        SetLoggerSettings( loggerSettings ) ;

        TRAP(r, ReadTestModulesL( parser ));
        if(r != KErrNone)
            {
            __TRACE(KError, (CStifLogger::ERed, _L("Reading test modules finished with error [%d]"), r));
            User::Leave(r);
            }

        CleanupStack::PopAndDestroy( settings );
        CleanupStack::PopAndDestroy( parser );
        __TRACE( KInit, ( _L( "Configuration file reading finished" ) ) );
        }
    else
        {
        __TRACE( KInit,( CStifLogger::EBold, _L( "Initialisation file not specified." ) ) );
        }

    Logger()->WriteDelimiter();
    
    // Create Test Reporter if allowed
    if ( iTestEngineServer->iTestReportSettings.iCreateTestReport )
        {
        TRAPD(err, iTestReport = 
            CTestReport::NewL( iTestEngineServer->iTestReportSettings, 
                               ( CTestReport::TTestReportMode ) iReportMode ));
        if(err!=KErrNone)
            {
            iTestReport = NULL;
            __TRACE( KInit,( CStifLogger::ERed, _L( "Test report creation failed with error: %d, test report not created." ), err ) );
            __TRACE( KInit,( CStifLogger::ERed, _L( "Check your testreport settings from testframework.ini file (e.g. TestReportFilePath)." ) ) );
            }
        }
    
    // Create test engine subsession object
    CTestEngineSubSession* testEngineSubSession =
    CTestEngineSubSession::NewL( this );
    CleanupStack::PushL( testEngineSubSession );

    // Add object to object container to generate unique id
    iContainer->AddL( testEngineSubSession );

    // Add object to object index
    // This returns a unique handle so we can get it again
    TInt handle = iTestEngineSubSessions->AddL( testEngineSubSession );

    // Write the handle to client
    TPckg<TInt> handlePckg( handle );

    TRAPD( res, aMessage.WriteL( 3, handlePckg ) );
    if ( res != KErrNone )
        {
        iTestEngineSubSessions->Remove( handle );
        PanicClient( EBadDescriptor, aMessage );
        return;
        }

    CleanupStack::Pop( testEngineSubSession );

    // Notch up another resource
    iResourceCount++;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: ReadEngineDefaults

    Description: Parse Test Engine defaults from STIF 
                 initialization file.

    Parameters: CStifParser& parser: in: CStifParser object
                CSTIFTestFrameworkSettings* aSettings: in:
                CSTIFTestFrameworkSettings object

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::ReadEngineDefaultsL( CStifParser* aParser,
                                        CSTIFTestFrameworkSettings* aSettings )
    {
    __TRACE( KInit,( _L( "" ) ) );
    __TRACE( KInit,( _L( "Start parsing engine defaults" ) ) );
    TInt get_ret( KErrNone );

    CStifSectionParser* sectionParser = NULL;

    // Parse Engine's default values
    _LIT( KDefaultsStart, "[Engine_Defaults]" );
    _LIT( KDefaultsEnd, "[End_Defaults]" );
    __TRACE( KInit,( _L( "Starting to search sections" ) ) );
    sectionParser = aParser->SectionL( KDefaultsStart, KDefaultsEnd );
    CleanupStack::PushL( sectionParser );
    if ( sectionParser )
        {
        __TRACE( KInit,( _L( "Found '%S' and '%S' sections" ), &KDefaultsStart, &KDefaultsEnd ) );

        // Get Test Report Mode
        __TRACE( KInit,( _L( "Parsing Test report mode" ) ) );
        TUint reportMode( 0 );
        get_ret = aSettings->GetReportModeL( sectionParser,
                                        _L( "TestReportMode=" ), reportMode );
        if ( get_ret == KErrNone )
            {
            __TRACE( KInit,( _L( "Report mode: %d"), reportMode ) );
            iReportMode = reportMode;
            }
        else
            {
            __TRACE( KInit,( _L( "Report mode not found or not given" ) ) );
            }

        // Indicator to test report creation
        __TRACE( KInit,( _L( "Parsing Test report creation indicator" ) ) );
        TBool createTestReport( 0 );
        get_ret = aSettings->GetBooleanSettingsL( sectionParser,
                                _L( "CreateTestReport=" ), createTestReport );
        if ( get_ret == KErrNone )
            {
            __TRACE( KInit,( _L( "Test report creation indicator: %d"), createTestReport ) );
            iTestEngineServer->iTestReportSettings.iCreateTestReport = createTestReport;
            }
        else
            {
            __TRACE( KInit,( _L( "Creation indicator not found or not given" ) ) );
            }

        // Get Test report path settings
        if ( iTestEngineServer->iTestReportSettings.iCreateTestReport )
            {
            __TRACE( KInit,( _L( "Parsing Test report path" ) ) );
            TPtrC path;
            get_ret = aSettings->GetFileSetting( sectionParser,
                                        _L( "TestReportFilePath=" ), path );
            if ( get_ret == KErrNone )
                {
                __TRACE( KInit,( _L( "Test report path: %S"), &path ) );
                // Delete old one before setting new one
                delete iTestEngineServer->iTestReportSettings.iPath;
				iTestEngineServer->iTestReportSettings.iPath = NULL;
                iTestEngineServer->iTestReportSettings.iPath = path.AllocL();
                }
            else
                {
                __TRACE( KInit,( _L( "Path not found or not given" ) ) );
                }
            }

        // Get Test report name settings
        if ( iTestEngineServer->iTestReportSettings.iCreateTestReport )
            {
            __TRACE( KInit,( _L( "Parsing Test report filename" ) ) );
            TPtrC name;
            get_ret = aSettings->GetFileSetting( sectionParser,
                                        _L( "TestReportFileName=" ), name );
            if ( get_ret == KErrNone )
                {
                __TRACE( KInit,( _L( "Test report filename: %S"), &name ) );
                // Delete old one before setting new one
                delete iTestEngineServer->iTestReportSettings.iName;
				iTestEngineServer->iTestReportSettings.iName = NULL;
                iTestEngineServer->iTestReportSettings.iName = name.AllocL();
                }
            else
                {
                __TRACE( KInit,( _L( "Filename not found or not given" ) ) );
                }
            }

        // Get Test report format settings
        if ( iTestEngineServer->iTestReportSettings.iCreateTestReport )
            {
            __TRACE( KInit,( _L( "Parsing Test report format" ) ) );
            CStifLogger::TLoggerType type;
            TBool xml;
            get_ret = aSettings->GetFormatL( sectionParser,
                                            _L( "TestReportFormat=" ), type, xml );
            if ( get_ret == KErrNone )
                {
                __TRACE( KInit,( _L( "Test report format: %d, xml: %d"), type, xml ) );
                iTestEngineServer->iTestReportSettings.iFormat = type;
                iTestEngineServer->iTestReportSettings.iXML = xml;
                }
            else
                {
                __TRACE( KInit,( _L( "Format not found or not given" ) ) );
                }
            }

        // Get Test report output settings
        if ( iTestEngineServer->iTestReportSettings.iCreateTestReport )
            {
            __TRACE( KInit,( _L( "Parsing Test report output" ) ) );
            CStifLogger::TOutput output;
            get_ret = aSettings->GetOutputL( sectionParser,
                                        _L( "TestReportOutput=" ), output );
            if ( get_ret == KErrNone )
                {
                __TRACE( KInit,( _L( "Test report output: %d"), output ) );
                iTestEngineServer->iTestReportSettings.iOutput = output;
                }
            else
                {
                __TRACE( KInit,( _L( "Output not found or not given" ) ) );
                }
            }

        // Get Test report file creation mode (overwrite settings)
        if ( iTestEngineServer->iTestReportSettings.iCreateTestReport )
            {
            __TRACE( KInit,( _L( "Parsing Test report file writing mode" ) ) );
            TBool overwrite;
            get_ret = aSettings->GetOverwriteL( sectionParser,
                            _L( "TestReportFileCreationMode=" ), overwrite );
            if ( get_ret == KErrNone )
                {
                __TRACE( KInit,( _L( "Test report file creation mode: %d"), overwrite ) );
                iTestEngineServer->iTestReportSettings.iOverwrite = overwrite;
                }
            else
                {
                __TRACE( KInit,( _L( "Writing mode not found or not given" ) ) );
                }
            }
        // Get device reset module's DLL name
        __TRACE( KInit,( _L( "Parsing device reset module's DLL name" ) ) );
        TPtrC deviceResetName;
        get_ret = aSettings->GetFileSetting( sectionParser,
                                        _L( "DeviceResetDllName=" ), deviceResetName );
        if ( get_ret == KErrNone )
            {
            __TRACE( KInit,( _L( "Device reset module's name: %S"), &deviceResetName ) );
            // Delete old one before setting new one
            delete iDeviceResetDllName;
			iDeviceResetDllName = NULL;
            iDeviceResetDllName = deviceResetName.AllocL();
            }
        else
            {
            __TRACE( KInit,( _L( "Device reset module's name not found or not given" ) ) );
            }

        // Get measurement disable option
        CStifItemParser* item = NULL;
        TRAPD( ret, item = sectionParser->GetItemLineL( _L( "DisableMeasurement=" ), ENoTag ) );
        if( ( ret != KErrNone ) || ( item == NULL ) )
            {
             __TRACE( KInit,( _L( "Measurement 'DiableMeasurement=' not found or not given" ) ) );
			delete item; 
            item = NULL;
            }
        else
            {
			CleanupStack::PushL( item );			
            TPtrC string;
            ret = item->GetString( KNullDesC(), string );
            while( ret == KErrNone )
                {
                HBufC* stringHbuf = string.AllocL();
                TPtr modifiableString = stringHbuf->Des();
                modifiableString.LowerCase();

                if( modifiableString == KStifMeasurementDisableNone ||
                    modifiableString == KStifMeasurementDisableAll ||
                    modifiableString == KStifMeasurement01 ||
                    modifiableString == KStifMeasurement02 ||
                    modifiableString == KStifMeasurement03 ||
                    modifiableString == KStifMeasurement04 ||
                    modifiableString == KStifMeasurement05 ||
                    modifiableString == KStifMeasurementBappea )
                    {
                    __TRACE( KInit,( _L( "Measurement disable option: %S"), &modifiableString ) );
                    DisableStifMeasurement( modifiableString );
                    }
                else if( modifiableString == _L( "#" ) )
                    {
					delete stringHbuf;
					stringHbuf = NULL;
                    break;
                    }
                else
                    {
                    __TRACE( KInit,( _L( "Measurement disable option not found or not given" ) ) );
                    delete stringHbuf;                    
					stringHbuf = NULL;
                    break;
                    }
                delete stringHbuf;
                ret = item->GetNextString( string );
                }
			CleanupStack::PopAndDestroy( item );
			item = NULL;
            }

        // Get timeout value option
        __TRACE(KInit, (_L("Parsing default timeout value")));
        iDefaultTimeout = 0;
        item = NULL;
        TRAP(ret, item = sectionParser->GetItemLineL(_L("Timeout=" ), ENoTag));
        if( ( ret != KErrNone ) || ( item == NULL ) )
            {
            __TRACE(KInit, (_L("'Timeout' option not found or not given")));
            delete item;
            item = NULL;
            }
        else
            {
            CleanupStack::PushL( item );
            TPtrC string;
            ret = item->GetString(KNullDesC(), string);
            if(string.Length() > 0)
                {
                TLex lex(string);
                ret = lex.Val(iDefaultTimeout);
                if(ret != KErrNone)
                    {
                    __TRACE(KError, (_L("Could not convert timeout value '%S' to integer. Error %d. Ignoring this setting."), &string, ret));
                    }
                if(iDefaultTimeout < 0)
                    {
                    __TRACE(KError, (_L("'Timeout' value cannot be negative. Resetting to 0.")));
                    iDefaultTimeout = 0;
                    }
                }
            else
                {
                __TRACE(KInit, (_L("'Timeout' value not given")));
                }
            CleanupStack::PopAndDestroy( item );
            item = NULL;
            }
        __TRACE(KInit, (_L("'Timeout' value set to %d"), iDefaultTimeout));
        iDefaultTimeout *= 1000;
        
        // Get UITestingSupport value option
        __TRACE(KInit, (_L("Parsing UITestingSupport value")));
        iUITestingSupport = EFalse;
        item = NULL;
        TRAP(ret, item = sectionParser->GetItemLineL(_L("UITestingSupport=" ), ENoTag));
        if((ret != KErrNone) || (item == NULL))
            {
            __TRACE(KInit, (_L("'UITestingSupport' option not found")));
            delete item;
            item = NULL;
            }
        else
            {
            CleanupStack::PushL(item);
            TPtrC string;
            ret = item->GetString(KNullDesC(), string);
            if(string.Length() > 0)
                {
                iUITestingSupport = (string == _L("YES"));
                }
            else
                {
                __TRACE(KInit, (_L("'UITestingSupport' value not given")));
                }
            CleanupStack::PopAndDestroy(item);
            item = NULL;
            }
        __TRACE(KInit, (_L("'UITestingSupport' value set to %d"), iUITestingSupport));

        // Get SeparateProcesses value option
        __TRACE(KInit, (_L("Parsing SeparateProcesses value")));
        iSeparateProcesses = EFalse;
        item = NULL;
        TRAP(ret, item = sectionParser->GetItemLineL(_L("SeparateProcesses=" ), ENoTag));
        if((ret != KErrNone) || (item == NULL))
            {
            __TRACE(KInit, (_L("'SeparateProcesses' option not found")));
            delete item;
            item = NULL;
            }
        else
            {
            CleanupStack::PushL(item);
            TPtrC string;
            ret = item->GetString(KNullDesC(), string);
            if(string.Length() > 0)
                {
                iSeparateProcesses = (string == _L("YES"));
                }
            else
                {
                __TRACE(KInit, (_L("'SeparateProcesses' value not given")));
                }
            CleanupStack::PopAndDestroy(item);
            item = NULL;
            }
        __TRACE(KInit, (_L("'SeparateProcesses' value set to %d"), iSeparateProcesses));
        }
    else
        {
        __TRACE( KInit,( _L( "Not found '%S' and '%S' sections" ), &KDefaultsStart, &KDefaultsEnd ) );
        }
    __TRACE( KInit,( _L( "End parsing engine defaults" ) ) );
    CleanupStack::PopAndDestroy( sectionParser );
    
    // Store engine settings to SettingServer
    RSettingServer settingServer;
    TInt ret = settingServer.Connect();
    if(ret != KErrNone)
        {
        __TRACE(KError, (_L("Could not connect to SettingServer [%d] and store engine settings"), ret));
        }
    else
        {
        TEngineSettings settings;
        settings.iUITestingSupport = iUITestingSupport;
        settings.iSeparateProcesses = iSeparateProcesses;
        ret = settingServer.StoreEngineSettings(settings);
        if(ret != KErrNone)
            {
            __TRACE(KError, (_L("Could not store engine settings to SettingServer [%d]"), ret));
            }
            else
            {
            __TRACE(KInit, (_L("Engine settings succesfully stored to SettingServer")));
            }
        settingServer.Close();
        }
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: SetLoggerSettings

    Description: Set parsed logger's settings to TestEngine side.

    Parameters: TLoggerSettings& aLoggerSettings: in: Parsed logger settings

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestEngine::SetLoggerSettings( TLoggerSettings& aLoggerSettings )
    {
    iTestEngineServer->iLoggerSettings = aLoggerSettings;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: ParseTestModulesL

    Description: Parse and search for module info and fill list of modules.

    Parameters: CStifParser*     aParser:       in: CStifParser object
                CTestModuleList* aModuleList:   in: list of modules
                TPtrC&           aSectionStart: in: descriptor with start of section string
                TPTrC&           aSectionEnd:   in: descriptor with end of section string

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::ParseTestModulesL(CStifParser* aParser, CTestModuleList* aModuleList, const TDesC& aSectionStart, const TDesC& aSectionEnd)
    {
    //First let's find all modules given in Stif's ini file and store that info in CTestModuleList object
    CStifSectionParser* sectionParser = NULL;
    CStifItemParser* item = NULL;

    sectionParser = aParser->SectionL(aSectionStart, aSectionEnd);

    TBool sectionOK;

    while(sectionParser)
        {
        sectionOK = ETrue;
        __TRACE(KInit, (_L("Found '%S' and '%S' sections"), &aSectionStart, &aSectionEnd));
        CleanupStack::PushL(sectionParser);
        __TRACE(KInit, (_L("Starting to read module information")));

        // Get name of module
        _LIT(KModuleName, "ModuleName=");
        item = sectionParser->GetItemLineL(KModuleName);
        CleanupStack::PushL(item);
        if(!item)
            {
            __TRACE(KError, (CStifLogger::ERed, _L("'%S' not found from Module section. Skipping whole section."), &KModuleName));
            sectionOK = EFalse;
            }
        else
            {
            __TRACE(KInit, (_L("'%S' found"), &KModuleName));
            }

        TName moduleName;
        TInt ret(KErrNone);

        if(sectionOK)
            {
            TPtrC name;
            ret = item->GetString(KModuleName, name);
            if(ret != KErrNone)
                {
                __TRACE(KError, (CStifLogger::ERed, _L("Module name parsing ended with error [%d]. Skipping whole section"), ret));
                sectionOK = EFalse;
                }
            else
                {
                __TRACE(KInit, (_L("Module '%S' found from ini-file"), &name));
                moduleName.Copy(name);
                moduleName.LowerCase();
                ret = aModuleList->AddTestModule(moduleName);
                if(ret != KErrNone && ret != KErrAlreadyExists)
                    {
                    CleanupStack::PopAndDestroy(item);
                    __TRACE(KError, (CStifLogger::ERed, _L("Could not add module to list of modules. Error %d"), ret));
                    LeaveIfErrorWithNotify(ret);
                    }
                }
            }
        CleanupStack::PopAndDestroy(item);

        //Get pointer to added module
        if(sectionOK)
            {
            CTestModuleInfo* moduleInfo = aModuleList->GetModule(moduleName);
            if(!moduleInfo)
                {
                __TRACE(KError, (CStifLogger::ERed, _L("Could not add get module info from list")));
                LeaveIfErrorWithNotify(KErrNotFound);
                }
    
            // Get ini file, if it exists
            __TRACE(KInit, (_L("Start parsing ini file")));
            _LIT(KIniFile, "IniFile=");
            item = sectionParser->GetItemLineL(KIniFile);
            if(item)
                {
                __TRACE(KInit, (_L("'%S' found"), &KIniFile));
                CleanupStack::PushL(item);
                TPtrC iniFile;
                ret = item->GetString(KIniFile, iniFile);
                if(ret == KErrNone)
                    {
                    // Module inifile (might be empty) OK
                    TFileName filename;
                    filename.Copy(iniFile);
                    TStifUtil::CorrectFilePathL( filename );
                    filename.LowerCase();
                    __TRACE(KInit, (CStifLogger::EBold, _L("Initialization file '%S' found, file can be empty"), &iniFile));
                    moduleInfo->SetIniFile(filename);
                    }
                else
                    {
                    __TRACE(KInit, (_L("Initialization file not found")));
                    }
                CleanupStack::PopAndDestroy(item);
                }
            else
                {
                __TRACE(KInit, (_L("'%S' not found"), &KIniFile));
                }
    
            // Get config (testcase) file
            __TRACE(KInit, (_L("Start parsing cfg files")));
            TPtrC cfgTag;
            for(TInt i = 0; i < 2; i++)
                {
                //Set tag for config files
                if(i == 0)
                    {
                    cfgTag.Set(_L("ConfigFile="));
                    }
                    else
                    {
                    cfgTag.Set(_L("TestCaseFile="));
                    }
                //Read data
                item = sectionParser->GetItemLineL(cfgTag);
                while(item)
                    {
                    CleanupStack::PushL(item);
                    __TRACE(KInit, (_L("Item '%S' found"), &cfgTag));
                    TPtrC cfgFile;
                    ret = item->GetString(cfgTag, cfgFile);
                    if(ret == KErrNone)
                        {
                        TFileName ifile;
                        ifile.Copy(cfgFile);
                        TStifUtil::CorrectFilePathL( ifile );
                        ifile.LowerCase();
                        __TRACE(KInit, (_L("Configuration file '%S' found"), &ifile));
                        moduleInfo->AddCfgFile(ifile);
                        }
                    else
                        {
                        __TRACE(KInit, (_L("Configuration file not found")));
                        }
                    CleanupStack::PopAndDestroy(item);
                    item = sectionParser->GetNextItemLineL(cfgTag);
                    }
                }
    
            __TRACE(KInit, (_L("Module '%S' information read correctly"), &moduleName));
            }
        else
            {
            __TRACE(KError, (_L("Module '%S' information skipped"), &moduleName));
            }

        // Get next section...
        CleanupStack::PopAndDestroy(sectionParser);
        sectionParser = aParser->NextSectionL(aSectionStart, aSectionEnd);
        }
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: ReadTestModules

    Description: Parse Test modules and module information from
                 STIF initialization file.

    Parameters: CStifParser& parser: in: CStifParser object

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::ReadTestModulesL(CStifParser* aParser)
    {
    __TRACE( KInit, (_L("")));
    __TRACE( KInit, (CStifLogger::EBold, _L("Start parsing test modules")));

    //Create CTestModuleList object. It will keep information about all found test modules,
    //its initialization files and test case (config) files.
    CTestModuleList* moduleList = CTestModuleList::NewL(Logger());
    CleanupStack::PushL(moduleList);

    // Parse Test Module information
    _LIT(KTestModuleStart, "[New_Module]");
    _LIT(KTestModuleEnd, "[End_Module]");

    __TRACE(KInit, (_L("Starting to search module sections")));
    TRAPD(err, ParseTestModulesL(aParser, moduleList, KTestModuleStart, KTestModuleEnd));
    if(err != KErrNone)
        {
        __TRACE(KError, (CStifLogger::ERed, _L("Parsing test modules returned error [%d]"), err));
        User::Leave(err);
        }
    __TRACE(KInit, (CStifLogger::EBold, _L("End parsing test modules")));
    __TRACE(KInit, (_L("")));

    //Now, find included test modules and also add them to CTestModuleList object.
    _LIT(KIncludeModuleStart, "[New_Include_Module]");
    _LIT(KIncludeModuleEnd, "[End_Include_Module]");

    __TRACE(KInit, (CStifLogger::EBold, _L("Start parsing included modules")));
    CTestCaseFileInfo* finfo = moduleList->GetUncheckedCfgFile();
    while(finfo)
        {
        TFileName fname;
        finfo->GetCfgFileName(fname);

        __TRACE(KInit, (_L("checking file: '%S'"), &fname));
        finfo->SetChecked();

        CStifParser* parser = NULL;

        TRAPD(err, parser = CStifParser::NewL(_L(""), fname));
        if(err == KErrNotFound)
            {
            __TRACE(KError, (CStifLogger::ERed, _L("Could not open file '%S'"), &fname));
            }
        else if(err != KErrNone)
            {
            __TRACE(KError, (CStifLogger::ERed, _L("Could not create parser for file '%S'"), &fname));
            LeaveIfErrorWithNotify(err);
            }
        else
            {
            CleanupStack::PushL(parser);

            ParseTestModulesL(parser, moduleList, KIncludeModuleStart, KIncludeModuleEnd);

            CleanupStack::PopAndDestroy(parser);
            }

        finfo = moduleList->GetUncheckedCfgFile();
        }

    __TRACE(KInit, (CStifLogger::EBold, _L("End parsing included modules")));
    __TRACE(KInit, (_L("")));

    //Now, when all modules have been found, create them
    __TRACE(KInit, (CStifLogger::EBold, _L("Start creating modules")));
    TBool afterReset = EFalse;
    if(iRebootParams)
        {
        afterReset = ETrue;
        }
    CTestModuleInfo* moduleInfo = NULL;
    TInt i;
    TInt modCnt = moduleList->Count();

    for(i = 0; i < modCnt; i++)
        {
        moduleInfo = moduleList->GetModule(i);
        if(!moduleInfo)
            {
            __TRACE(KInit, (CStifLogger::ERed, _L("Could not get module info at index %d"), i));
            TName error;
            error.AppendFormat(_L("Could not get module info at index %d"), i);
            ErrorPrint(1, error);
            continue;
            }

        TName moduleName;
        moduleInfo->GetModuleName(moduleName);

        // Create module controller
        __TRACE(KInit, (_L("Creating module controller for '%S'"), &moduleName));
		CTestModuleController* module = NULL;
		if( moduleName == _L( "testscripter" ) )
			{
			module = CTestModuleController::NewL(this, moduleName, afterReset, ETrue);
			}
		else
			{
			module = CTestModuleController::NewL(this, moduleName, afterReset);
			}
        CleanupStack::PushL(module);
        __TRACE(KInit, (_L("Module controller created")));

        // Get ini file, if exists
        __TRACE(KInit, (_L("Checking ini file")));
        TFileName ini;
        moduleInfo->GetIniFileName(ini);
        if(ini.Length() == 0)
            {
            __TRACE(KInit, (_L("Ini file not found")));
            }

        TRAPD(err, module->InitL(ini, KNullDesC));
        if(err != KErrNone)
            {
            __TRACE(KInit, (CStifLogger::ERed, _L("Module '%S' loading failed: %d"), &moduleName, err));
            TName error;
            error.AppendFormat(_L("Module '%S' loading failed: %d"), &moduleName, err);
            ErrorPrint(1, error);

            CleanupStack::PopAndDestroy(module);
            continue;
            }

        //Add test case files
        __TRACE(KInit, (_L("Checking cfg files")));
        TInt cfgCnt = moduleInfo->CountCfgFiles();
        TInt j;
        TFileName cfgFile;
        for(j = 0; j < cfgCnt; j++)
            {
            moduleInfo->GetCfgFileName(j, cfgFile);
            if(cfgFile.Length() > 0)
                {
                __TRACE(KInit, (_L("Adding config file '%S'"), &cfgFile));
                module->AddConfigFileL(cfgFile);
                }
            else
                {
                __TRACE(KInit, (_L("Got empty config filename")));
                }
            }
        if(cfgCnt == 0)
            {
            __TRACE(KInit, (_L("Cfg file not found")));
            }

        __TRACE(KInit, (_L("Module '%S' created correctly"), &moduleName));

        // Store module for later use
        User::LeaveIfError(iModules.Append(module));
        CleanupStack::Pop(module);
        }

    __TRACE(KInit, (CStifLogger::EBold, _L("End creating test modules")));
    __TRACE(KInit, (_L("")));

    //Check if there are any modules added to Stif
    if (iModules.Count() == 0)
        {
        __TRACE(KInit, (_L("Not found '%S' and '%S' sections"), &KTestModuleStart, &KTestModuleEnd));
        __TRACE(KInit, (CStifLogger::EBold, _L("Test module(s) not defined in initialisation file")));
        // Note is printed from UI, not from here anymore
        // ErrorPrint( 0 , _L("Test modules not found. Check testengine log"));
        }

    //Delete CTestModuleList object. It is not needed any more
    CleanupStack::PopAndDestroy(moduleList);
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: TestModuleConfigFileL

    Description: Add config file to test module

    Parameters: CTestModuleController* aModule: in: CTestModuleController
                                                    object.
                CStifSectionParser* aSectionParser: in: CStifSectionParser
                object.
                TDesC& aTag :in: Founded tag.

    Return Values: None

    Errors/Exceptions: Leaves if GetNextItemLineL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::TestModuleConfigFileL( CTestModuleController* aModule,
                                            CStifSectionParser* aSectionParser,
                                            TDesC& aTag )
    {
    // Add config files to Test Module
    TPtrC configFile;
    CStifItemParser* item = NULL;
    item = aSectionParser->GetItemLineL( aTag );

    TInt cfgFiles = 0;
    TFileName config;

    TInt ret( 0 );

    while ( item )
        {
        __TRACE( KInit,( _L( "Found '%S' section" ), &aTag ) );
        CleanupStack::PushL( item );
        ret = item->GetString( aTag, configFile );
        if ( ret != KErrNone )
            {
            CleanupStack::PopAndDestroy( item );
            __TRACE( KError, ( CStifLogger::ERed, _L( "File parsing left with error [%d]" ), ret ) );
            }
        else
            {
            config = configFile;
            aModule->AddConfigFileL( config );

            // Module configfile (might be empty) OK
            __TRACE( KInit,( _L( "Adding configuration file [%S]" ), &config ) );
            cfgFiles++;
            CleanupStack::PopAndDestroy( item );
            }
        item = aSectionParser->GetNextItemLineL( aTag );
        }

    // Print trace
    if ( cfgFiles == 0)
        {  
        __TRACE( KInit,( _L( "Module does not have '%S' files") , &aTag ) );
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: ModuleControllerByName

    Description: Return the module controller specified by given parameter.

    Parameters: const TName& aModuleName: in: Test module name

    Return Values: CTestModuleController* : pointer to CTestModuleController

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestModuleController* CTestEngine::ModuleControllerByName(
                                                    const TName& aModuleName )
    {
    TInt modules = iModules.Count();

    for ( TInt i = 0; i < modules; i++ )
        {
        if ( iModules[i]->ModuleName( aModuleName ) == aModuleName )
            {
            return iModules[i];
            }
        }
    return NULL;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: GetFreeOrCreateModuleControllerL

    Description: Return free module controller specified by given parameter.
                 If it can't be found, new one will be created.

    Parameters: TTestInfo& aTestInfo: test info structure
                CTestModuleController** aRealModuleController: for test scripter a real module controller will be returned

    Return Values: CTestModuleController* : pointer to CTestModuleController

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestModuleController* CTestEngine::GetFreeOrCreateModuleControllerL(TTestInfo& aTestInfo,
                                                                     CTestModuleController** aRealModuleController)
    {
    TInt i, j;
    *aRealModuleController = NULL;
    
    TInt modules = iModules.Count();

    //Find out which way it should be processed
    //New way means that Stif is going to find free test module controller
    //(free means that it does not run any test case)
    TBool oldWay = ETrue;
    if((iUITestingSupport && aTestInfo.iModuleName.Find(KTestScripterName) == 0) 
        || (aTestInfo.iModuleName == KPythonScripter)
        || (iSeparateProcesses))
        {
        __TRACE(KInit, (_L("Module controllers handling mode: exclusive")));
        //Exclusive mode means that every test case must be run in separate module controller.
        oldWay = EFalse;
        }
    else
        {
        __TRACE(KInit, (_L("Module controllers handling mode: normal")));
        oldWay = ETrue;
        }
        
    //If option is not set and it is not python scripter case
    //(python scripter always should look for free module controller)
    //This is the old way
    if(oldWay) 
        {
        __TRACE(KInit, (_L("Find test module controller for [%S]"), &aTestInfo.iModuleName));
        for(i = 0; i < modules; i++)
            {
            if(iModules[i]->ModuleName(aTestInfo.iModuleName) == aTestInfo.iModuleName)
                {
                __TRACE(KInit, (_L("Found test module controller for [%S]"), &aTestInfo.iModuleName));
                return iModules[i];
                }
            }
        __TRACE(KInit, (_L("Test module controller for [%S] NOT FOUND"), &aTestInfo.iModuleName));
        return NULL;
        }
    
    //This is a new way
    __TRACE(KInit, (_L("Find free test module controller for [%S]"), &aTestInfo.iModuleName));

    TName moduleName(aTestInfo.iModuleName);
    CTestModuleController* parentController = NULL;

    //First find original test module controller (parent)
    for(TInt i = 0; i < modules; i++)
        {
        if(iModules[i]->ModuleName(moduleName) ==  moduleName)
            {
            parentController = iModules[i];
            __TRACE(KInit, (_L("Original (parent) module controller found [%S]"), &moduleName));
            break;
            }
        }

    //Search free module controller among parent's children
    if(parentController)
        {
        //TestScripter is handled in other way
        if(moduleName.Find(KTestScripterName) == 0)
            {
            __TRACE(KInit, (_L("This is testscripter case. Searching real module controller.")));
            *aRealModuleController = parentController->GetFreeOrCreateModuleControllerL(aTestInfo, iUITestingSupport);
            return parentController;                 
            }

        //When UITestingSupport always create new module controller!
        TInt childrenCount = parentController->iChildrenControllers.Count();
        for(TInt i = 0; i < childrenCount; i++)
            {
            if(parentController->iChildrenControllers[i]->iTestCaseCounter == 0)
                {
                if(iUITestingSupport && aTestInfo.iModuleName.Find(KTestScripterName) == 0)
                    {
                    __TRACE(KInit, (_L("Free module controller found but in UITestingSupport mode always new one will be created")));
                    }
                else
                    {
                    __TRACE(KInit, (_L("Free module controller found [%S]"), parentController->iChildrenControllers[i]->iName));
                    return parentController->iChildrenControllers[i];
                    }
                }
            else
                {
                __TRACE(KInit, (_L("Module controller [%S] found but it is not free (it runs %d test cases)"), parentController->iChildrenControllers[i]->iName, parentController->iChildrenControllers[i]->iTestCaseCounter));
                }
            }
        }
    else
        {
        __TRACE(KError, (_L("Parent module controller NOT found [%S]"), &moduleName));
        User::Leave(KErrNotFound);
        }

    //No free module controller has been found. Create new one.
    TBuf<10> ind;
    ind.Format(_L("%d"), GetIndexForNewTestModuleController());
    moduleName.Append(_L("@"));
    moduleName.Append(ind);
    __TRACE(KInit, (_L("Free module controller not found. Creating new one [%S]."), &moduleName));
            
    //Create server and active object (This uses CTestModuleController::InitL())
    CTestModuleController* module = CTestModuleController::NewL(this, moduleName, parentController->iAfterReboot);
    CleanupStack::PushL(module);
    
    TRAPD(err, module->InitL(parentController->iInifile, aTestInfo.iConfig));
    if(err != KErrNone)
        {
        __TRACE(KInit, (_L("InitL fails with error: %d for module [%S]" ), err, &moduleName));
        User::Leave(err);
        }
    __TRACE(KInit, (_L("New module controller created [%S]."), &moduleName));

    // Store module for later use
    User::LeaveIfError(parentController->iChildrenControllers.Append(module));
    CleanupStack::Pop(module);
    __TRACE(KInit, (_L("Child added to [%S] controller. Currently it has %d children:"), parentController->iName, parentController->iChildrenControllers.Count()));
    for(j = 0; j < parentController->iChildrenControllers.Count(); j++)
        {
        __TRACE(KInit, (_L("    %d. [%S]"), j + 1, parentController->iChildrenControllers[j]->iName));
        }

    return module;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: SetAttributeL

    Description: Sets attributes to Test Framework

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Leave if ReadL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::SetAttributeL( const RMessage2& aMessage )
    {
    __TRACE( KVerbose, ( _L( "CTestEngine::SetAttributeL" ) ) );

    TAttribute attribute;
    TName genericTName;

    // Read attribute from aMessage
    attribute = (TAttribute)aMessage.Int0();

    switch( attribute )
        {
        // Path attribute
        case ELogPath:
            {
            // Read path from aMessage. 
            // NOTE!If message length is over TName, ReadL will cut the message
            // to allowed size and won't return any error code or leave code.
            aMessage.ReadL( 1, genericTName );

            // Handle to Setting server.
            RSettingServer settingServer;
            // Connect to the Setting server and create session
            TInt ret = settingServer.Connect();
            if ( ret != KErrNone )
                {
                User::Leave( ret );
                }
            settingServer.SetNewIniFileSetting( genericTName );
            // Close Setting server session
            settingServer.Close();
            break;
            }
        // Reboot directory
        case ERebootPath:
            {
            // Read reboot path from aMessage. 
            // NOTE!If message length is over TName, ReadL will cut the message
            // to allowed size and won't return any error code or leave code.
            aMessage.ReadL( 1, genericTName );
            // Allocated dynamically iRebootPath size and copies aMessage path.
            iRebootPath = genericTName.AllocL();
            break;
            }
        // Reboot path
        case ERebootFilename:
            {
            // Read reboot path from aMessage. 
            // NOTE!If message length is over TName, ReadL will cut the message
            // to allowed size and won't return any error code or leave code.
            aMessage.ReadL( 1, genericTName );
            // Allocated dynamically iRebootFilename size and copies aMessage
            // filename.
            iRebootFilename = genericTName.AllocL();
            break;
            }
        // Measurement configuration info
        case EStifMeasurementOn:
            {
            // Read Measurement configuration info from aMessage. 
            aMessage.ReadL( 1, genericTName );

            // Set info to test engine
            User::LeaveIfError( EnableStifMeasurement( genericTName ) );
            break;
            }
        // Measurement configuration info
        case EStifMeasurementOff:
            {
            // Read Measurement configuration info from aMessage. 
            aMessage.ReadL( 1, genericTName );

            // Set info to test engine
            User::LeaveIfError( DisableStifMeasurement( genericTName ) );
            break;
            }
        default:
            {
            __TRACE( KVerbose, ( _L( "Not valid attribute" ) ) );
            }
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: AddTestModuleL

    Description: Adds new Test Module

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves
                       Leaves if name length is zero

    Status: Approved: Proposal

-------------------------------------------------------------------------------
*/
void CTestEngine::AddTestModuleL( const RMessage2& aMessage )
    {
    __TRACE( KVerbose, ( _L( "CTestEngine::AddTestModuleL" ) ) );
    TName name;
    TFileName iniFile;

    // Read test module name from aMessage
    aMessage.ReadL( 0, name );

    if( name.Length() == 0 )
        {
        LeaveWithNotifyL( KErrArgument );
        }
    // Read ini file name from aMessage
    aMessage.ReadL( 1, iniFile );
    
    name.LowerCase();
    // Remove optional '.DLL' from file name
    TParse parse;
    parse.Set( name, NULL, NULL );
    
    if ( parse.Ext() == _L(".dll") )
        {
        const TInt len = parse.Ext().Length();
        name.Delete ( name.Length()-len, len );
        }

    __TRACE( KInit, ( 
        _L( "CTestEngine::AddTestModuleL, Adding Module:[%S]"), &name ) );

    // Check if test module already exists
    CTestModuleController* testModule = ModuleControllerByName( name );
    if ( testModule == NULL )
        {
        TBool afterReset = EFalse;
        if( iRebootParams && iRebootParams->iTestModule == name )
            {
            afterReset = ETrue;
            }
        
        // Create module controller
		CTestModuleController* module = NULL;
		if( name == _L( "testscripter" ) )
			{
			module = CTestModuleController::NewL( this, name, afterReset, ETrue );
			}
		else
			{
			//CTestModuleController* module = 
			module = CTestModuleController::NewL( this, name, afterReset );
			}
        CleanupStack::PushL( module );

        module->InitL( iniFile, KNullDesC );

        // Store module for later use
        User::LeaveIfError( iModules.Append( module ) );
        CleanupStack::Pop( module );
        // Done
        iReturn = KErrNone;

        __TRACE( KInit, ( 
        _L( "CTestEngine::AddTestModuleL, module added correctly") ) );
        }
    else
        {
        iReturn = KErrAlreadyExists;
        __TRACE( KInit, ( 
        _L( "CTestEngine::AddTestModuleL, module already added, all ok.") ) );
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: RemoveTestModuleL

    Description: Removes Test Module

    Parameters: const RMessage& aMessage: in: Server message
    
    Return Values: TInt KErrNone: No errors occurred
                        KErrNotFound: Test module not found
                        KErrInUse: Test module is in use, cannot be removed

    Errors/Exceptions: Leaves if some of called leaving methods leaves
                       Leaves if moduleName length is zero

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEngine::RemoveTestModuleL( const RMessage2& aMessage )
    {
    __TRACE( KInit, ( _L( "CTestEngine::RemoveTestModuleL" ) ) );
    // Read Module name from message
    TName moduleName;
    aMessage.ReadL( 0, moduleName );
    if( moduleName.Length() == 0 )
        {
        LeaveWithNotifyL( KErrArgument );
        }

    moduleName.LowerCase();
    // Remove optional '.DLL' from file name
    TParse parse;
    parse.Set( moduleName, NULL, NULL );

    if ( parse.Ext() == _L(".dll") )
        {
        const TInt len = parse.Ext().Length();
        moduleName.Delete ( moduleName.Length()-len, len );
        }

    __TRACE(KInit, (_L("Going to remove module controller [%S]"), &moduleName));
    // Check that the module that will be removed exists
    TInt moduleCount = iModules.Count();
    TBool found = EFalse;
    TInt moduleIndex;
    for ( moduleIndex = 0; moduleIndex < moduleCount; moduleIndex++ )
        {
        if ( iModules[moduleIndex]->ModuleName( moduleName ) == moduleName )
            {
            found = ETrue;
            break;
            }
        }

    if ( !found )
        {
        // Test Module does not exists
        __TRACE(KInit, (_L("Module controller [%S] to be removed NOT FOUND"), &moduleName));
        return KErrNotFound;
        }
    // Check module controller and its children
    if(iModules[moduleIndex]->iTestCaseCounter > 0)
        {
        __TRACE(KInit, (_L("Cannot remove module controller [%S], it is running %d test cases"), &moduleName, iModules[moduleIndex]->iTestCaseCounter));
        return KErrInUse;
        }
    TInt j;
    for(j = 0; j < iModules[moduleIndex]->iChildrenControllers.Count(); j++)
        {
        if(iModules[moduleIndex]->iChildrenControllers[j]->iTestCaseCounter > 0)
            {
            __TRACE(KInit, (_L("Cannot remove module controller [%S], its child [%S] is running %d test cases"), &moduleName, iModules[moduleIndex]->iChildrenControllers[j]->iName, iModules[moduleIndex]->iChildrenControllers[j]->iTestCaseCounter));
            return KErrInUse;
            }
        }
    // Test cases not running so we can remove the Test Module
    __TRACE(KInit, (_L("Removing module controller [%S]"), &moduleName));
    CTestModuleController* module = iModules[moduleIndex];
    iModules.Remove(moduleIndex);
    delete module;

    return KErrNone;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: CloseTestEngineL

    Description: Close test engine

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if GenerateReportL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::CloseTestEngineL( TUint aHandle )
    {
    __TRACE( KInit, ( _L( "CTestEngine::CloseTestEngineL" ) ) );
    // Remove all module controllers
    iModules.ResetAndDestroy();
    iModules.Close();

    // If test report is created
    if( iTestReport )
        {
        iTestReport->GenerateReportL();
        iIsTestReportGenerated = ETrue;
        }

    // Close Setting server, no handle available anymore
    iSettingServer.Close();

    // Get test case from container
    CTestEngineSubSession* testEngineSubSession = ( CTestEngineSubSession* )iTestEngineSubSessions->At( aHandle );

    // Do nothing if invalid handle
    if ( testEngineSubSession == NULL )
        {
        // Handle might be already deleted, so do nothing.
        return;
        }

    iTestEngineSubSessions->Remove( aHandle );

    // Decrement resource count
    iResourceCount--;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: AddConfigFileL

    Description: Adds new config file to Test Module

    Parameters: const RMessage& aMessage: in: Server Message

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves
                       Leaves if module length is zero
                       Leaves if configFile length is zero

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::AddConfigFileL( const RMessage2& aMessage )
    {
    TName module;
    TFileName configFile;

    // Read module name from aMessage
    aMessage.ReadL( 0, module );

    if( module.Length() == 0 )
        {
        LeaveWithNotifyL( KErrArgument );
        }
    // Read config file name from aMessage
    aMessage.ReadL( 1, configFile );

    if( configFile.Length() == 0 )
        {
        LeaveWithNotifyL( KErrArgument );
        }

    module.LowerCase();
    // Remove optional '.DLL' from file name
    TParse parse;
    parse.Set( module, NULL, NULL );
    
    if ( parse.Ext() == _L(".dll") )
        {
        const TInt len = parse.Ext().Length();
        module.Delete ( module.Length()-len, len );
        }
        
    __TRACE( KInit, ( _L( "Adding config file [%S] to [%S] module"), &configFile, &module ) );
    
    // Get correct test module controller
    CTestModuleController* testModule = ModuleControllerByName( module );
    if ( testModule == NULL )
        {        
        __TRACE( KError, ( CStifLogger::ERed, _L( "Added configure file has an invalid module:[%S]"), &module ) );
        LeaveWithNotifyL ( KErrNotFound );
        }

    // Add config file to Module
    testModule->AddConfigFileL( configFile );

    }
    
/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: RemoveConfigFileL

    Description: Removes a config file from test module

    Parameters: const RMessage& aMessage: in: Server Message

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves
                       Leaves if module length is zero
                       Leaves if configFile length is zero

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestEngine::RemoveConfigFileL( const RMessage2& aMessage )
    {
    TName module;
    TFileName configFile;

    // Read module name from aMessage
    aMessage.ReadL( 0, module );

    if( module.Length() == 0 )
        {
        LeaveWithNotifyL( KErrArgument );
        }
    // Read config file name from aMessage
    aMessage.ReadL( 1, configFile );

    if( configFile.Length() == 0 )
        {
        LeaveWithNotifyL( KErrArgument );
        }

    module.LowerCase();
    // Remove optional '.DLL' from file name
    TParse parse;
    parse.Set( module, NULL, NULL );
    
    if ( parse.Ext() == _L(".dll") )
        {
        const TInt len = parse.Ext().Length();
        module.Delete ( module.Length()-len, len );
        }
        
    __TRACE( KInit, ( _L( "Removing config file [%S] from [%S] module"), &configFile, &module ) );
    
    // Get correct test module controller
    CTestModuleController* testModule = ModuleControllerByName( module );
    if ( testModule == NULL )
        {        
        __TRACE( KError, ( CStifLogger::ERed, _L( "Added configure file has an invalid module:[%S]"), &module ) );
        LeaveWithNotifyL ( KErrNotFound );
        }

    // Remove config file from Module
    testModule->RemoveConfigFileL( configFile );

    }


/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: EnumerateTestCasesL

    Description: Enumerates test cases

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Panics the client if enumeration is already pending
                       Leaves if called StartEnumerateL method leaves

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestEngine::EnumerateTestCasesL( const RMessage2& aMessage )
    {
    __TRACE( KInit, ( _L( "CTestEngine::EnumerateTestCasesL" ) ) );
    // Check if enumerate is ongoing!!
    __ASSERT_ALWAYS( iEnumerateModuleCount == 0, PanicClient( EReqPending, aMessage ) );

    iCaseCount = 0;
    iEnumError = KErrNone;

    TInt count = iModules.Count();
    if ( count == 0 )
        {

        __TRACE( KInit, ( CStifLogger::EBold, _L( "Test module(s) not loaded - returning 0 test cases" ) ) );
        
        // Note is printed from UI
        // ErrorPrint(0, _L("No test modules, check testengine log"));
        // Write test case count to client
        TCaseCount countPckg( 0 );
        TRAPD( err, aMessage.WriteL( 0, countPckg ) );

        // Request will be completed in DispatchMessageL
        iReturn = err;
        }
    else
        {
        for ( TInt i = 0; i < count; i++ )
            {
            // Send enumerate request to each test module.
            iModules[i]->StartEnumerateL();
            iEnumerateModuleCount++;
            }
    
        // Message is completed later from EnumerationCompleted function
        iComplete = EFalse;

        // Store the message
        iEnumerationMessage = aMessage;
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: EnumerationCompleted

    Description: Return the module controller specified by given parameter.

    Parameters: TInt aCount: in: Count of test cases
                TInt aError: in: Symbian OS Error code: Error from Test Module

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestEngine::EnumerationCompleted( TInt aCount, TInt aError )
    {
    // Increment test case count by aCount
    iCaseCount+= aCount;

    if ( aError != KErrNone )
        {
        iEnumError = aError;
        }

    iEnumerateModuleCount--;
    
    if ( iEnumerateModuleCount == 0 )
        {
       
        TInt attrib = CStifLogger::ENoStyle;
        if ( iCaseCount == 0 )
            {
            attrib = CStifLogger::EBold;
            }
        __TRACE( KInit, ( attrib, _L( "Test case enumeration completed, testcase count %d"), iCaseCount ) );

        // Write test case count to client
        TCaseCount countPckg( iCaseCount );
        TRAPD( err, iEnumerationMessage.WriteL( 0, countPckg ) );

        if ( err != KErrNone )
            {
            iEnumError = err;
            __TRACE( KError, ( CStifLogger::ERed,  _L( "CTestEngine::EnumerationCompleted: Failed %d"), iEnumError ) );
            }
        
        // Complete request
        iEnumerationMessage.Complete( iEnumError );
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: GetTestCasesL

    Description: Get test cases

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Leaves if enumeration is not yet complete

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::GetTestCasesL( const RMessage2& aMessage )
    {
    __TRACE( KVerbose, ( _L( "CTestEngine::GetTestCasesL" ) ) );

    const TInt len = sizeof( TTestInfo );

    // Loop through all test modules
    TInt moduleCount = iModules.Count();
    TInt pos = 0;
    TInt totalCount = 0;
    for ( TInt i = 0; i < moduleCount; i++ )
        {
        CTestModuleController* module = iModules[i];

        // Check that test cases are enumerated first
        if ( !module->EnumerationComplete() )
            {
            __TRACE( KError, ( CStifLogger::ERed, _L( "CTestEngine::GetTestCasesL, Test Cases not yet enumerated!" ) ) );
            LeaveIfErrorWithNotify( KErrNotFound );
            }

        CFixedFlatArray<TTestInfo>* testCases = module->TestCasesL();
        CleanupStack::PushL( testCases );
        
        // Loop through all test cases got from test module
        const TInt caseCount = testCases->Count();
        totalCount+=caseCount;

        for ( TInt j = 0; j < caseCount; j++ )
            {
            if(((*testCases)[j]).iTestCaseInfo.iTimeout == 0 && iDefaultTimeout > 0)
                {
                ((*testCases)[j]).iTestCaseInfo.iTimeout = iDefaultTimeout;
                }

            // Construct package for source data
            TTestInfoPckg tmpPackage( ( *testCases )[j] );

            // Copy test case package to client's memory
            aMessage.WriteL( 0, tmpPackage, pos ) ;

            pos = pos + len;
            }
        CleanupStack::PopAndDestroy( testCases );

        // Free allocated test cases because not needed anymore
        module->FreeTestCases();

        }

    __TRACE( KVerbose, ( _L( "CTestEngine::GetTestCasesL, case count %d" ), totalCount ) );

    // Finished
    iReturn = KErrNone;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: CancelAsyncRequest

    Description: Asynchronous requests are canceled by this function.

    Parameters: const RMessage aMessage

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestEngine::CancelAsyncRequest( const RMessage2& aMessage )
    {
    switch ( aMessage.Int0() )
        {
        case ETestEngineEnumerateTestCases:
            {
            TInt count = iModules.Count();
            for ( TInt i=0; i < count; i++ )
                {
                // Cancel enumerate  
                iModules[i]->Cancel();
                }
            break;
            }

        case ETestEngineErrorNotification:
            {
            if ( iErrorMessageAvailable )
                {
                iErrorMessageAvailable = EFalse;
                iErrorMessage.Complete ( KErrCancel );
                }
            }
            break;
        case ETestEngineEvent:
            // Event command cannot be cancelled
            // Only EWaitEvent can be cancelled with ECancelWait
        default:
            PanicClient( EBadRequest, aMessage );
            break;
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: EventControlL

    Description: Controls event system.

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestEngine::EventControlL( const RMessage2& aMessage )

    {
    __TRACE( KVerbose, ( _L( "CTestEngine::EventControlL" ) ) );
    TInt ret = KErrNone;

    // Read EventIf from aMessage
    TEventIf event;
    TEventIfPckg eventIfPckg( event );
    aMessage.ReadL( 0, eventIfPckg );

    // EWaitEvent, EReqEvent and ERelEvent need processing here
    if( ( event.Type() == TEventIf::EWaitEvent ) ||
        ( event.Type() == TEventIf::EReqEvent ) ||
        ( event.Type() == TEventIf::ERelEvent ) ||
        ( event.Type() == TEventIf::ECancelWait ) )
        {
        TInt ind = 0; 
        TInt count = iClientEvents.Count();
        const TDesC& eventName = event.Name();
        // Search event from client event list
        for( ind=0; ind < count; ind++ )
            {
            if( iClientEvents[ind]->Name() == eventName )
                {
                break;
                }
            }

        switch( event.Type() )
            {
            // Handle event waiting  
            case TEventIf::EWaitEvent:
                {
                // Check that we found event from client events list
                if( ind == count )
                    {
                    ret = KErrNotFound;
                    }
                else
                    {
                    TEventMsg* eventEntry = iClientEvents[ind];
                    
                    __TRACE( KVerbose, ( _L( "CTestEngine::EventControlL: Waiting %S (count %i)"), 
                        &event.Name(), count ) );

                    // Waiting is completed either from here in Wait method 
                    // if event is already pending,
                    // or from Set method in CtlEvent when event is set.
                    eventEntry->Wait( aMessage );
                    return;
                    }
                }
                break;
            case TEventIf::ECancelWait:
                {
                // Check that we found event from client events list
                if( ind == count )
                    {
                    ret = KErrNotFound;
                    }
                else
                    {
                    TEventMsg* eventEntry = iClientEvents[ind];
                    
                    __TRACE( KVerbose, ( _L( "CTestEngine::EventControlL: Cancel waiting %S (count %i)"), 
                        &event.Name(), count ) );

                    eventEntry->CancelWait();
                    }
                }
                break;
            // Handle event request
            case TEventIf::EReqEvent:
                {
                // Check that event is not already requested
                if( ind < count )
                    {
                    // Already exists
                    ret = KErrArgument;
                    }
                else
                    { 
                    // Requested events are added to iClientEvents
                    TEventMsg* eventEntry = new TEventMsg;
                    if( eventEntry == NULL )
                        {
                        ret = KErrNoMemory;
                        }
                    else
                        {
                        CleanupStack::PushL( eventEntry );
                        eventEntry->Copy( event );
                        // Check if state event is set already
                        if( IsStateEventAndSet( event.Name() ) )
                            { 
                            // If it was set already, set the event
                            eventEntry->Set( TEventIf::EState );
                            }
                        ret = iClientEvents.Append( eventEntry ); 
                        if( ret != KErrNone )
                            {
                            CleanupStack::PopAndDestroy( eventEntry );
                            }
                        else
                            {   
                            CleanupStack::Pop( eventEntry );
                               
                            __TRACE( KVerbose, ( _L( "CTestEngine::EventControlL: Req added %S (count %i)"),
                                &event.Name(), iClientEvents.Count() ) );
                            } 
                        }
                    }
                }
                break;
            // Release event 
            case TEventIf::ERelEvent:
                {
                // Released events are deleted from iClientEvents
                // Check that we found entry from client events list
                if( ind == count )
                    {
                    ret = KErrNotFound;
                    }
                else
                    {
                    __TRACE( KVerbose, ( _L( "CTestEngine::EventControlL: Release event %S (count %i)"), 
                        &event.Name(), iClientEvents.Count() ) );

                    TEventMsg* eventEntry = iClientEvents[ind];
                    iClientEvents.Remove( ind );
                    eventEntry->Release();
                    delete eventEntry;
                    }
                }
                break;
            default: // This should never happen!!!
                { 
                _LIT( KEngine, "CTestEngine" );
                User::Panic( KEngine, KErrGeneral );
                }
                break;
            }
        }
    else
        {
        // ESetEvent and EUnsetEvent are only forwarded
        TRequestStatus req;
        CtlEventL( event, req );
        User::WaitForRequest( req );
        }
        
    aMessage.Complete( ret );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: HandleErrorNotificationL

    Description: Handle error notifications.

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::HandleErrorNotificationL( const RMessage2& aMessage )
    {
    iErrorMessage = aMessage;
    iErrorMessageAvailable = ETrue;

    ProcessErrorQueue();

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: LoggerSettings

    Description: Get Logger's overwrite parameters

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Panics if WriteL fails

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::LoggerSettings( const RMessage2& aMessage )
    {
    __TRACE( KInit, ( _L( "CTestEngine::LoggerSettings" ) ) );

    // Copies logger settings to the package
    TPckg<TLoggerSettings> loggerSettingsPckg( iTestEngineServer->iLoggerSettings );

    // Writes a packege that includes the logger overwrite settings to aMessage
    TRAPD( err, aMessage.WriteL( 0, loggerSettingsPckg ) );
    if ( err != KErrNone )
        {
        PanicClient( EBadDescriptor, aMessage );
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: CloseLoggerSettings

    Description: Close logger settings

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::CloseLoggerSettings()
    {
    __TRACE( KInit, ( _L( "CTestEngine::CloseLoggerSettings" ) ) );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: TestCaseByHandle

    Description: Return test case specified by aHandle

    Parameters: TUint aHandle : in : TUint : Handle to TestCase subsession

    Return Values: CTestCase* : pointer to CTestCase object

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestCase* CTestEngine::TestCaseByHandle( TUint aHandle, const RMessage2& aMessage )
    {
    // Try to get test case from test case container
    CTestCase* testCase =
        ( CTestCase* )iTestCases->At( aHandle );
    if ( testCase == NULL )
        {
        PanicClient( EBadSubsessionHandle, aMessage ); 
        }

    return testCase;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: NewTestCaseL

    Description: Create new test execution subsession

    Parameters: const RMessage& aMessage: in: Server Message

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving method leaves

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestEngine::NewTestCaseL( const RMessage2& aMessage )
    {
    __TRACE( KVerbose, ( _L( "CTestEngine::NewTestCaseL start" ) ) );

    // Get data from message
    TTestInfo testInfo;
    TTestInfoPckg testInfoPckg = testInfo;

    TRAPD( res, aMessage.ReadL( 0, testInfoPckg ) );
    if ( res != KErrNone )
        {
        PanicClient( EBadDescriptor, aMessage );
        return;
        }

    testInfo.iModuleName.LowerCase();
    // Remove optional '.DLL' from file name
    TParse parse;
    parse.Set( testInfo.iModuleName, NULL, NULL );

    if ( parse.Ext() == _L(".dll") )
        {
        const TInt len = parse.Ext().Length();
        testInfo.iModuleName.Delete ( testInfo.iModuleName.Length()-len, len );
        }

    // Get correct test module controller
    CTestModuleController* scrModule = NULL;
    CTestModuleController* module = GetFreeOrCreateModuleControllerL(testInfo, &scrModule);
    if ( module == NULL )
        {
        //@spe PanicClient( EInvalidModuleName, aMessage );
        //@spe return;
        __TRACE( KError, ( CStifLogger::ERed, _L( "Invalid module:[%S]"), &testInfo.iModuleName ) );
        LeaveWithNotifyL ( KErrNotFound );
        }

    // Create test case object
    CTestCase* testCase =
        CTestCase::NewL( this, module, iTestReport, testInfo, scrModule);
    CleanupStack::PushL( testCase );

    // Add object to object container to generate unique id
    iContainer->AddL( testCase );

    // Add object to object index
    // This returns a unique handle so we can get it again
    TInt handle = iTestCases->AddL( testCase );

    // Write the handle to client
    TPckg<TInt> handlePckg( handle );

    TRAP( res, aMessage.WriteL( 3, handlePckg ) );
    if ( res != KErrNone )
        {
        iTestCases->Remove( handle );
        PanicClient( EBadDescriptor, aMessage );
        return;
        }

    // Add new test case to testcase array
    User::LeaveIfError( iTestCaseArray.Append( testCase ) );
    CleanupStack::Pop( testCase );

    // Notch up another resource
    iResourceCount++;

    iReturn = KErrNone;

    __TRACE( KVerbose, ( _L( "CTestEngine::NewTestCaseL done" ) ) );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: DeleteTestCase

    Description: Delete test case from container list

    Parameters: TUint aHandle: in: Handle to test case to be removed

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::DeleteTestCase( TUint aHandle ) 
    {
    __TRACE( KVerbose, ( _L( "CTestEngine::DeleteTestCase" ) ) );

    // Get test case from container
    CTestCase* testCase = ( CTestCase* )iTestCases->At( aHandle );

    // Do nothing if invalid handle
    if ( testCase == NULL )
        {
        // Handle might be already deleted, so do nothing.
        return;
        }

    //Get controllers
    CTestModuleController* moduleController;
    CTestModuleController* realModuleController;
    
    moduleController = testCase->GetModuleControllers(&realModuleController);
    
    // Check if module controllers have crashed
    TBool moduleControllerCrashed = EFalse;
    TBool realModuleControllerCrashed = EFalse;

    if(moduleController)
        {
        moduleControllerCrashed = moduleController->iTestModuleCrashDetected;
        }
    if(realModuleController)
        {
        realModuleControllerCrashed = realModuleController->iTestModuleCrashDetected;
        }

    //__TRACE(KInit, (_L("CTestEngine::DeleteTestCase moduleController=[%x] crashed=[%d] realModuleController=[%x] crashed=[%d]"), moduleController, moduleControllerCrashed, realModuleController, realModuleControllerCrashed));
    // For UITestingSupport, SeparateProcesses and PythonSupport, when module is crashed,
    // remove it from module lists, because it will be deleted when closing test case.
    if(moduleController)
        {
        if(moduleControllerCrashed && iUITestingSupport && moduleController->iName->Find(KTestScripterName) == 0
           || moduleControllerCrashed && iSeparateProcesses
           || moduleControllerCrashed &&  moduleController->iName->Find(KPythonScripter) == 0
          )
            {
            __TRACE(KInit, (_L("Removing module controller from module list because of crash")));
            //Look for specific module controller and delete it
            TInt i;
            TInt j, children;
            TInt modules = iModules.Count();
            for(i = 0; i < modules; i++)
                {
                if(iModules[i] == moduleController)
                    {
                    __TRACE(KInit, (_L("Module controller found - removing")));
                    iModules.Remove(i);
                    break;
                    }

                //Check children of the module and if module to be deleted found there, remove it
                children = iModules[i]->iChildrenControllers.Count();
                __TRACE(KInit, (_L("Checking %d children of [%S]"), children, iModules[i]->iName));
                for(j = 0; j < children; j++)
                    {
                    if(iModules[i]->iChildrenControllers[j] == moduleController)
                        {
                        __TRACE(KInit, (_L("Module controller found (child) - removing")));
                        
                        iModules[i]->iChildrenControllers.Remove(j);

                        __TRACE(KInit, (_L("Child removed from [%S] controller. Currently it has %d children:"), iModules[i]->iName, iModules[i]->iChildrenControllers.Count()));
                        for(TInt k = 0; k < iModules[i]->iChildrenControllers.Count(); k++)
                            {
                            __TRACE(KInit, (_L("    %d. [%S]"), k + 1, iModules[i]->iChildrenControllers[k]->iName));
                            }                            
                        break;
                        }
                    }
                }
            }
        }
    if(moduleController && realModuleController)
        {
        if(realModuleControllerCrashed && iUITestingSupport && realModuleController->iName->Find(KTestScripterName) == 0
           || realModuleControllerCrashed && iSeparateProcesses
           || realModuleControllerCrashed &&  realModuleController->iName->Find(KPythonScripter) == 0
          )
            {
            __TRACE(KInit, (_L("Removing real module controller from module list because of crash")));
            //Remove module controller from scripter controller
            moduleController->RemoveModuleController(realModuleController);
            }
        }

    // Close test case and remove it from container
    //testCase->CloseTestCase();
    iTestCases->Remove( aHandle );

    // Decrement resource count
    iResourceCount--;

    // Remove from testcase array
    iTestCaseArray.Remove( iTestCaseArray.Find( testCase ) );

    //If this is UITestingSupport and module is not crashed, delete controller 
    //(in other words, kill process, because we need somehow reset the test server).
    if(moduleController && !moduleControllerCrashed)
        {        
        if(iUITestingSupport && moduleController->iName->Find(KTestScripterName) == 0)
            {
            if(realModuleController)
                {
                if(!realModuleControllerCrashed)
                    {
                    __TRACE(KInit, (_L("Delete module controller (and kill process in which test case was run).")));
                    __TRACE(KInit, (_L("Real module controller provided - processing")));
                    //Remove module controller from scripter controller
                    moduleController->DeleteModuleController(realModuleController);
                    }
                }
            else
                {
                 __TRACE(KInit, (_L("Delete module controller (and kill process in which test case was run).")));
                 __TRACE(KInit, (_L("Real module controller not provided, checking normal controllers")));
                //Look for specific module controller and delete it
                TInt i;
                TInt j, children;
                TInt modules = iModules.Count();
                for(i = 0; i < modules; i++)
                    {
                    if(iModules[i] == moduleController)
                        {
                        __TRACE(KInit, (_L("Module controller found - deleting")));
                        delete iModules[i];
                        iModules.Remove(i);
                        break;
                        }

                    //Check children of the module and if module to be deleted found there, remove it
                    children = iModules[i]->iChildrenControllers.Count();
                    __TRACE(KInit, (_L("Checking %d children of [%S]"), children, iModules[i]->iName));
                    for(j = 0; j < children; j++)
                        {
                        if(iModules[i]->iChildrenControllers[j] == moduleController)
                            {
                            __TRACE(KInit, (_L("Module controller found (child) - deleting")));
                            
                            delete iModules[i]->iChildrenControllers[j];
                            iModules[i]->iChildrenControllers.Remove(j);
    
                            __TRACE(KInit, (_L("Child removed from [%S] controller. Currently it has %d children:"), iModules[i]->iName, iModules[i]->iChildrenControllers.Count()));
                            for(TInt k = 0; k < iModules[i]->iChildrenControllers.Count(); k++)
                                {
                                __TRACE(KInit, (_L("    %d. [%S]"), k + 1, iModules[i]->iChildrenControllers[k]->iName));
                                }                            
                            break;
                            }
                        }
                    }
                }
            }
        }
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: IsStateEventAndSet

    Description: Callback to check state event status.

    Parameters: const TName& aEventName: in: Event name

    Return Values: ETrue: event is set 
                   EFalse: event is not set

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TBool CTestEngine::IsStateEventAndSet( const TName& aEventName )
    {
    TInt count = iStateEvents.Count();
    for( TInt i = 0; i < count; i++ ) 
        {
        TPtrC name = iStateEvents[i]->Des();
        if( name == aEventName )
            {
            // Requested state event set already
            return ETrue;
            }
        }
    return EFalse;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: CtlEventL

    Description: Callback to control events.

    Parameters: const TEventIf& aEvent: in: event information
                TRequestStatus& aStatus: in: Request status

    Return Values: CTestEventController*: CTestEventController object

    Errors/Exceptions: Leaves if CtlEventL leaves
                       Leaves if memory allocation fails
                       Leaves if unset event not found from pending 
                       state event list

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEventController* CTestEngine::CtlEventL( const TEventIf& aEvent, 
                                              TRequestStatus& aStatus )
    {
    __TRACE( KVerbose, ( _L( "CTestEngine::CtlEventL" ) ) );
    
    aStatus = KRequestPending;

    UpdateEventL( aEvent );
    return CTestEventController::NewL( this, aEvent, &aStatus );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: UpdateEventL

    Description: Update event lists.

    Parameters: const TEventIf& aEvent: in: event information

    Return Values: None

    Errors/Exceptions: Leaves if CtlEventL leaves
                       Leaves if memory allocation fails
                       Leaves if unset event not found from pending
                       state event list

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::UpdateEventL( const TEventIf& aEvent )
    {
    // Handle ESetEvent and EUnsetEvent for state events here
    if( aEvent.EventType() == TEventIf::EState )
        {
        // Find event from the list
        TInt count = iStateEvents.Count();
        TInt index = 0;
        const TDesC& eventName = aEvent.Name();
        for( ; index < count; index++ ) 
            {
            TPtrC name = iStateEvents[index]->Des();
            if( name == eventName )
                {
                break;
                }
            }

        if( aEvent.Type() == TEventIf::ESetEvent )
            {
            // Check that event is not already pending
            if( index < count )
                {
                User::Leave( KErrAlreadyExists );
                }

            // Add set event to pending state event list
            HBufC* name = aEvent.Name().AllocLC();
            User::LeaveIfError( iStateEvents.Append( name ) );
            CleanupStack::Pop( name );
            }
        else if( aEvent.Type() == TEventIf::EUnsetEvent )
            {
            if( index == count )
                {
                // Not found from state event list
                User::Leave( KErrNotFound );
                }
            HBufC* tmp = iStateEvents[index];
            iStateEvents.Remove( index );
            delete tmp;
            }
        }
    else if( aEvent.Type() == TEventIf::EUnsetEvent )
        {
        // Can not give Unset for indication event
        User::Leave( KErrNotSupported );
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: Logger

    Description: Return the pointer to Logger.

    Parameters: None

    Return Values: CStifLogger*: Pointer to StifLogger

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CStifLogger* CTestEngine::Logger()
    {
    return iTestEngineServer->Logger();

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: WriteRebootParams

    Description: Write the Reboot's state parameters.

    Parameters: TTestInfo& aTestInfo: in: Test case information.
                TInt& aCode: in: Reboot related integer information.
                TDesC& aName: in: Reboot related string information.

    Return Values: TInt: Symbian OS error

    Errors/Exceptions: Error code returned if Logger creation fails.

    Status: Proposal

-------------------------------------------------------------------------------
*/
TInt CTestEngine::WriteRebootParams( TTestInfo& aTestInfo,
                                        TInt& aCode,
                                        TDesC& aName )
    {
    __TRACE( KVerbose, ( _L( "WriteRebootParams() starts..." ) ) );
    
    // Logger's setting definitions
    TLoggerSettings loggerSettings;

    loggerSettings.iCreateLogDirectories = ETrue;
    loggerSettings.iOverwrite = ETrue;
    loggerSettings.iTimeStamp = EFalse;
    loggerSettings.iLineBreak = EFalse;
    loggerSettings.iEventRanking = EFalse;
    loggerSettings.iThreadId = EFalse;
    // EData format because now we don't have to check file type when
    // parsing this.
    loggerSettings.iHardwareFormat = CStifLogger::EData;
    loggerSettings.iHardwareOutput = CStifLogger::EFile;
    loggerSettings.iEmulatorFormat = CStifLogger::EData;
    loggerSettings.iEmulatorOutput = CStifLogger::EFile;
    loggerSettings.iUnicode = EFalse;
    loggerSettings.iAddTestCaseTitle = EFalse;

    // Use default setting if path or filename are not set by SetAttribute()
    if( iRebootPath == NULL )
        {
        iRebootPath= iRebootDefaultPath.Alloc();
        }
    if( iRebootFilename == NULL )
        {
        iRebootFilename= iRebootDefaultFilename.Alloc();
        }

    CStifLogger* logger = NULL;
    TRAPD( ret, logger = CStifLogger::NewL( *iRebootPath,
                                        *iRebootFilename,
                                        loggerSettings ) );
    if( ret != KErrNone )
        {
        __TRACE( KError, ( _L( "WriteRebootParams() Logger creation fails with error: " ), ret ) );
        delete logger;
        return ret;
        }

    // Write reboot parameters
    // Because logging format is EData we need add line breaks by hand.
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "This is TestFramework's file which includes Reboot related informations" ) );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "Reboot case's related information:" ) );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "%S %S" ), &KTestModule, &aTestInfo.iModuleName );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "%S %S" ), &KTestCaseFile, &aTestInfo.iConfig );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "%S %d" ), &KTestCaseNumber, aTestInfo.iTestCaseInfo.iCaseNumber );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "%S %S" ), &KTestCaseTitle, &aTestInfo.iTestCaseInfo.iTitle );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "%S %d" ), &KStateCode, aCode );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "%S " ), &KStateName );
    logger->Log( aName );
    logger->Log( _L( "\r\n" ) );
    logger->Log( _L( "\r\n" ) );

    delete logger;

    __TRACE( KVerbose, ( _L( "WriteRebootParams() ends" ) ) );

    return KErrNone;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: ReadRebootParams

    Description: Read the Reboot parameters.

    Parameters: TTestInfo& aTestInfo: in: Test case information.

    Return Values: TInt: Symbian OS error

    Errors/Exceptions: Error code returned if Parser creation fails.
                       Error code returned if section creation fails.
                       Error code returned if item creation fails.
                       Error code returned if parsing operation fails.
                       KErrArgument returned if parsed values and test case
                       values are different.

    Status: Proposal

-------------------------------------------------------------------------------
*/
TInt CTestEngine::ReadRebootParams( TTestInfo& aTestInfo, 
                                    TDes& aStateDes, 
                                    TInt& aState )
    {
    __TRACE( KVerbose, ( _L( "ReadRebootParams() starts..." ) ) );

    if( iRebootParams == NULL )
        {
        __TRACE( KVerbose, ( _L( "ReadRebootParams(): Reboot not done" )) );
        return KErrNotFound;
        }
        
    // --.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--
    // Checks parsed values and test case values
    // --.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--
    if( iRebootParams->iTestModule != aTestInfo.iModuleName ||
        iRebootParams->iTestCaseFile != aTestInfo.iConfig ||
        iRebootParams->iCaseNumber != aTestInfo.iTestCaseInfo.iCaseNumber )
        {
        __TRACE( KVerbose, 
            ( _L( "ReadRebootParams(): Reboot not done by %S" ), 
                &aTestInfo.iModuleName) );
        return KErrArgument;
        }
   
    aStateDes.Copy( iRebootParams->iStateName );
    aState = iRebootParams->iStateCode;
   
    // delete reboot params, to ensure that same test case 
    // does not get indication about reboot again
    delete iRebootParams;
    iRebootParams = 0;

    __TRACE( KVerbose, ( _L("ReadRebootParams() ends" ) ) );
    
    return KErrNone;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: ParseRebootParamsL

    Description: Parse the Reboot parameters.

    Parameters: None

    Return Values: TInt: Symbian OS error

    Errors/Exceptions: Error code returned if Parser creation fails.
                       Error code returned if section creation fails.
                       Error code returned if item creation fails.
                       Error code returned if parsing operation fails.
                       KErrArgument returned if parsed values and test case
                       values are different.

    Status: Proposal

-------------------------------------------------------------------------------
*/
TInt CTestEngine::ParseRebootParamsL()
    {
    __TRACE( KVerbose, ( _L( "ParseRebootParamsL() starts..." ) ) );

    TInt ret_parsing( 0 );
    TPtrC tmp;

    // Use default setting if path or filename are not set by SetAttribute()
    if( iRebootPath == NULL )
        {
        iRebootPath= iRebootDefaultPath.Alloc();
        }
    if( iRebootFilename == NULL )
        {
        iRebootFilename= iRebootDefaultFilename.Alloc();
        }

    // Create parser object
    CStifParser* parser = NULL;
    TRAPD( ret, parser = CStifParser::NewL( *iRebootPath,
                                        *iRebootFilename ) );
    if( ret != KErrNone )
        {
        __TRACE( KError, ( _L( "ReadRebootParams(): Reboot file not found" )) );
        return ret;        
        }
    CleanupStack::PushL( parser );
    
    // Create section object
    CStifSectionParser* section = parser->SectionL( KNullDesC, KNullDesC );
    CleanupStack::PushL( section );
    
    // Delete old reboot params
    delete iRebootParams;
    iRebootParams = 0;
    iRebootParams = CRebootParams::NewL();
    
    // ----------------------Test module parsing
    CStifItemParser* item = section->GetItemLineL( KTestModule );
    CleanupStack::PushL( item );

    // Parsing integer
    ret_parsing = item->GetString( KTestModule, tmp );
    if( ret_parsing == KErrNone || ret_parsing == KErrNotFound )
        {
        __TRACE( KVerbose, ( _L("ReadRebootParams(): TestModule: %S" ), &tmp ) );
        }
    else
        {
        __TRACE( KError, 
            ( _L("ReadRebootParams(): TestModule parsing fails with error: " ), 
                ret_parsing ) );
        User::Leave( ret_parsing );        
        }
    iRebootParams->SetTestModuleNameL( tmp );
    CleanupStack::PopAndDestroy( item );

    // ----------------------Testcase parsing
    item = section->GetItemLineL( KTestCaseFile );
    CleanupStack::PushL( item );

    // Parsing string
    ret_parsing = item->GetString( KTestCaseFile, tmp );
    if( ret_parsing == KErrNone ) 
        {
        __TRACE( KVerbose, ( _L("ReadRebootParams(): TestCaseFile: %S" ), &tmp ) );
        iRebootParams->SetTestCaseFileNameL( tmp );
        }
    else if( ret_parsing == KErrNotFound )
        {
        __TRACE( KVerbose, 
            ( _L("ReadRebootParams(): No testcasefile defined for test module" )) );
        }
    else
        {
        __TRACE( KError, 
            ( _L("ReadRebootParams(): TestCaseFile parsing fails with error: %d " ), 
                ret_parsing ) );
        User::Leave( ret_parsing );  
        }
    CleanupStack::PopAndDestroy( item );

    // ----------------------Testcase number parsing
    item = section->GetItemLineL( KTestCaseNumber );
    CleanupStack::PushL( item );    
    
    // Parsing integer
    ret_parsing = item->GetInt( KTestCaseNumber, iRebootParams->iCaseNumber );
    if( ret_parsing == KErrNone || ret_parsing == KErrNotFound )
        {
        __TRACE( KVerbose, ( _L("ReadRebootParams(): TestCaseNumber: %d" ), 
            iRebootParams->iCaseNumber ) );
        }
    else
        {
        __TRACE( KError,
            ( _L("ReadRebootParams(): TestCaseNumber parsing fails with error: %d " ), 
                ret_parsing ) );
         User::Leave( ret_parsing );  
        }
    CleanupStack::PopAndDestroy( item );

    // --.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--
    // --.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--
    // Next state code and name parsing if no error found
    // --.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--.--

    // ----------------------State code parsing
    item = section->GetItemLineL( KStateCode );
    CleanupStack::PushL( item );   

    // Parsing integer
    ret_parsing = item->GetInt( KStateCode, iRebootParams->iStateCode );
    if( ret_parsing == KErrNone || ret_parsing == KErrNotFound )
        {
        __TRACE( KVerbose, ( _L("ReadRebootParams(): StateCode: %d" ), 
            iRebootParams->iStateCode ) );
        }
    else
        {
        __TRACE( KError, 
            ( _L("ReadRebootParams(): StateCode parsing fails with error: %d " ), 
            ret_parsing ) );
        User::Leave( ret_parsing );  
        }
    CleanupStack::PopAndDestroy( item );
    
    // ----------------------State name parsing
    ret_parsing = section->GetLine( KStateName, tmp, ENoTag );
    if( ret_parsing != KErrNone )
        {
        __TRACE( KError, 
            ( _L("ReadRebootParams(): State name parsing fails with error: %d " ), 
            ret_parsing ) );
        User::Leave( ret_parsing );         
        }

    iRebootParams->SetTestCaseStateL( tmp );

    __TRACE( KVerbose, ( _L("ReadRebootParams() ends" ) ) );

    CleanupStack::PopAndDestroy( section );
    CleanupStack::PopAndDestroy( parser );

    // Delete file
    RFs rf;
    TInt retVal = rf.Connect();
	if( retVal != KErrNone )
		{
		User::Leave( retVal ); 
		}
		
    TFileName file( *iRebootPath );
    file.Append( *iRebootFilename );
    rf.Delete( file );
    rf.Close();
    
    return KErrNone;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: PauseAllTestCases

    Description: Pause all test case(s) which are/is running.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
void CTestEngine::PauseAllTestCases()
    {
    __TRACE( KVerbose, ( _L( "CTestEngine::PauseAllTestCases()" ) ) );

    TInt count( 0 );
    count = iTestCaseArray.Count();

    for( TInt a = 0; a < count; a++ )
        {
         // Pause test case
         iTestCaseArray[a]->Pause();
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: FlushAtsLogger

    Description: Flush ATS logger's

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
void CTestEngine::FlushAtsLogger()
    {
    __TRACE( KVerbose, ( _L( "CTestEngine::FlushAtsLogger()" ) ) );

    TInt count( 0 );
    count = iModules.Count();

    for( TInt a = 0; a < count; a++ )
        {
         // Pause test case
         iModules[a]->AtsLogger().SaveForRebootL();
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: GetDeviceResetDllName

    Description: Get device reset module's DLL name.

    Parameters: None

    Return Values: TPtrC

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
TPtrC CTestEngine::GetDeviceResetDllName()
    {
    __TRACE( KVerbose, ( _L( "CTestEngine::GetDeviceResetDllName()" ) ) );

    return iDeviceResetDllName->Des();

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: EnableStifMeasurement

    Description: Set measurements related information, enable measurement.

    Parameters: const TName& aInfoType: in: Enabled measurement type

    Return Values: TInt: Symbian error code

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEngine::EnableStifMeasurement( const TDesC& aInfoType )
    {
    __TRACE( KInit, ( _L( "Measurement [%S] enabled" ), &aInfoType ) );

    if( aInfoType == KStifMeasurement01 )
        {
        iDisableMeasurement &= ~EMeasurement01;
        }
    else if( aInfoType == KStifMeasurement02 )
        {
        iDisableMeasurement &= ~EMeasurement02;
        }
    else if( aInfoType == KStifMeasurement03 )
        {
        iDisableMeasurement &= ~EMeasurement03;
        }
    else if( aInfoType == KStifMeasurement04 )
        {
        iDisableMeasurement &= ~EMeasurement04;
        }
    else if( aInfoType == KStifMeasurement05 )
        {
        iDisableMeasurement &= ~EMeasurement05;
        }
    else if( aInfoType == KStifMeasurementBappea )
        {
        iDisableMeasurement &= ~EBappea;
        }
    else if( aInfoType == KStifMeasurementDisableAll )
        {
        __TRACE( KInit, ( _L( "All measurements are disabled" ) ) );
        iDisableMeasurement &= EDisableAll; // Does change anything !!!
        }
    else if( aInfoType ==  KStifMeasurementEnableAll )
        {
        __TRACE( KInit, ( _L( "All measurements types are enabled" ) ) );
        iDisableMeasurement &= EEnableAll;
        }
    else
        {
        __TRACE( KInit, ( _L( "Measurement [%S] not recognized" ), &aInfoType ) );
        return KErrArgument;
        }

    return KErrNone;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: DisableStifMeasurement

    Description: Set measurements related information, disable measurement.

    Parameters: const TName& aInfoType: in: Disabled measurement type 

    Return Values: TInt: Symbian error code

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEngine::DisableStifMeasurement( const TDesC& aInfoType )
    {
    __TRACE( KInit, ( _L( "Measurement [%S] disabled" ), &aInfoType ) );

    if( aInfoType == KStifMeasurement01 )
        {
        iDisableMeasurement |=  EMeasurement01;
        }
    else if( aInfoType ==  KStifMeasurement02 )
        {
        iDisableMeasurement |=  EMeasurement02;
        }
    else if( aInfoType ==  KStifMeasurement03 )
        {
        iDisableMeasurement |= EMeasurement03;
        }
    else if( aInfoType ==  KStifMeasurement04 )
        {
        iDisableMeasurement |=  EMeasurement04;
        }
    else if( aInfoType ==  KStifMeasurement05 )
        {
        iDisableMeasurement |=  EMeasurement05;
        }
    else if( aInfoType ==  KStifMeasurementBappea )
        {
        iDisableMeasurement |=  EBappea;
        }
    else if( aInfoType ==  KStifMeasurementDisableAll )
        {
        __TRACE( KInit, ( _L( "All measurements are disabled" ) ) );
        iDisableMeasurement |=  EDisableAll;
        }
    else if( aInfoType ==  KStifMeasurementEnableAll )
        {
        __TRACE( KInit, ( _L( "All measurements types are enabled" ) ) );
        iDisableMeasurement |=  EEnableAll; // Does change anything !!!
        }
    // This option can be defined in TestFramework.ini file
    else if( aInfoType ==  KStifMeasurementDisableNone )
        {
        __TRACE( KInit, ( _L( "All measurements types are enabled" ) ) );
        iDisableMeasurement =  EEnableAll; // Sets to 0
        }
    else
        {
        __TRACE( KInit, ( _L( "Measurement [%S] not recognized" ), &aInfoType ) );
        return KErrArgument;
        }

    return KErrNone;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: StifMeasurement

    Description: Get measurements related information. Returns is measurement
                 disable.

    Parameters: None

    Return Values: TInt: Indication what measurement types is/are disabled.

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEngine::StifMeasurement()
    {
    return iDisableMeasurement;

    }
/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: TestModuleCrash

    Description: This method is called only when test module crashed 
                 with KErrServerTerminated (-15). 
                 Clones new TestModuleController:
                 - Find crashed testmodulecontroller
                 - Creates new copy of that testmodulecontroller
                 - Replaces old crashed testmodulecontroller with this new one

    Parameters: CTestModuleController* aTestModuleController: in: TestModuleController
    Return Values: None

    Errors/Exceptions: Leaves if error happens when adding clone to the list

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::TestModuleCrash(CTestModuleController* aTestModuleController)
    {
    TName crashModuleName = aTestModuleController->ModuleName(KNullDesC);
    __TRACE(KInit, (_L("Handling crashed test module [%S]"), &crashModuleName));
    TBool isTestScripter(EFalse);
    
    // Find crashed test module controller
    CTestScripterController* testScripterController = aTestModuleController->iTestScripterController;
    if(testScripterController)
        {
        isTestScripter = ETrue;
        }

    // If UITestingSupport or SeparateProcesses is enabled, there is no need
    // to create clone of Test Module Controller, because it will be created
    // automatically when needed.
    if(iUITestingSupport && crashModuleName.Find(KTestScripterName) == 0 
       || iSeparateProcesses
       || (crashModuleName.Find(KPythonScripter) == 0)
      )
        {
        __TRACE(KInit, (_L("Handling crashed test module with enabled UITestingSupport or SeparateProcesses is not needed")));
        aTestModuleController->iTestModuleCrashDetected = ETrue;
        return;
        }
        
    // Clone crashed module
    TBool afterReset = EFalse;
    if(iRebootParams && iRebootParams->iTestModule == crashModuleName)
        {
        afterReset = ETrue;
        }  
    
    CTestModuleController* clone;    
    clone = aTestModuleController->CloneL(aTestModuleController, afterReset, testScripterController);  
    
    // Replaces crashed testmodulecontroller with this new one    
    // Note: Old Testmodulecontroller is deleted in CTestModuleController::CaseFinished 
    //       that is called from  CTestCase::~CTestCase() 

    TInt index = KErrNotFound;
    if(isTestScripter)
        {
        index = testScripterController->iTestScripter.Find(aTestModuleController);
        __TRACE(KInit, (_L("Crashed module index [%d]"), index));
        if(index != KErrNotFound)
            {
            testScripterController->iTestScripter.Remove(index);
            }
        testScripterController->iTestScripter.Append(clone);            
        }
    else
        {
        index = iModules.Find(aTestModuleController);
        __TRACE(KInit, (_L("Crashed module index [%d]"), index));
        if(index != KErrNotFound)
            {
            iModules.Remove(index);
            }
        iModules.Append(clone);
        }
    __TRACE(KInit, (_L("End of handling crashed test module")));
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: ExecuteCommandL

    Description: Executes command received from test case.
                 The method was created to allow test case to kill itself.

    Parameters: aTestCaseHandle: handler to test case
    Return Values: None

    Errors/Exceptions: Leaves if error happens when adding clone to the list

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngine::ExecuteCommandL(TCommand aCommand, TDesC8& aParamsPckg)
    {
    TInt testCaseHandle = 0;
    // Get params
    switch(aCommand)
        {
        case EStopExecution:
            {
            //Unpack received parameters
            TStopExecutionCommandParams par;
            TStopExecutionCommandParamsPckg parPack(par);
            parPack.Copy(aParamsPckg);

            __TRACE(KInit, (_L("CTestEngine::ExecuteCommandL received command [%d] type [%d] code [%d] test handle [%d]"), TInt(aCommand), TInt(par.iType), TInt(par.iCode), par.iTestCaseHandle));

            //Get test case handle
            testCaseHandle = par.iTestCaseHandle;

            break;
            }
        case ESendTestModuleVersion:
        	{
        	TSendTestModuleVesionCommandParams par;
        	TSendTestModuleVesionCommandParamsPckg parPack(par);
        	parPack.Copy(aParamsPckg);

        	TTestModuleVersionInfo testModuleVersionInfo;
        	testModuleVersionInfo.iMajor = par.iMajor;
        	testModuleVersionInfo.iMinor = par.iMinor;
        	testModuleVersionInfo.iBuild = par.iBuild;
        	testModuleVersionInfo.iTestModuleName = par.iTestModuleName;
        	if(iTestReport)
        	    {
        	    iTestReport->AddTestModuleVersion(testModuleVersionInfo);
        	    }
        	
        	return;
        	}
        default:
            __TRACE(KError, (_L("CTestEngine::ExecuteCommandL Unknown command [%d]"), TInt(aCommand)));
            return;
        }

    // Get test case from container
    CTestCase* testCase = (CTestCase*)iTestCases->At(testCaseHandle);

    // Log some info if invalid handle
    if(testCase == NULL)
        {
        __TRACE(KInit, ( _L( "CTestEngine::ExecuteCommandL - invalid handle. Unable to get test case to execute command [%d]"), TInt(aCommand)));
        return;
        }

    testCase->ExecuteCommandL(aCommand, aParamsPckg);

    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: GetIndexForNewTestModuleController

    Description: Returns new index for test module controller.
                 This number is appended to module controller name.
                 This method is used when option to run every test case in 
                 separate process is set to on.

    Parameters: aTestCaseHandle: handler to test case
    Return Values: None

    Errors/Exceptions: Leaves if error happens when adding clone to the list

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEngine::GetIndexForNewTestModuleController(void)
    {
    return iIndexTestModuleControllers++;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngine

    Method: AddTestCaseToTestReport

    Description: Get parameters from message and add test case to test report.

    Parameters: aMessage: message
    Return Values: error id

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEngine::AddTestCaseToTestReport(const RMessage2& aMessage)
    {
    if(iTestReport)
        {
        // Read test data
        TTestInfo testInfo;
        TTestInfoPckg testInfoPckg(testInfo);
    
        TFullTestResult fullTestResult;
        TFullTestResultPckg fullTestResultPckg(fullTestResult);
        
        TRAPD(err, aMessage.ReadL(0, testInfoPckg));
        if(err)
            {
            __TRACE(KError, (_L("Leave when reading TTestInfo in AddTestCaseToTestReport [%d]"), err));
            return err;
            }
    
        TRAP(err, aMessage.ReadL(1, fullTestResultPckg));
        if(err)
            {
            __TRACE(KError, (_L("Leave when reading TFullTestResult in AddTestCaseToTestReport [%d]"), err));
            return err;
            }
            
        TRAP(err, iTestReport->AddTestCaseResultL(testInfo, fullTestResult, aMessage.Int2()));
        if(err)
            {
            __TRACE(KError, (_L("Leave from test report in AddTestCaseToTestReport [%d]"), err));
            return err;
            }
        }
    else
        {
        __TRACE(KError, (_L("TestReport not initialized in AddTestCaseToTestReport")));
        return KErrNotReady;
        }

    return KErrNone;
    }

/*
-------------------------------------------------------------------------------

    DESCRIPTION

    This module contains implementation of CTestEngineSubSession class member functions.

-------------------------------------------------------------------------------
*/

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

/*
-------------------------------------------------------------------------------

    Class: CTestEngineSubSession

    Method: CTestEngineSubSession

    Description: Default constructor

    C++ default constructor can NOT contain any code, that
    might leave.
    
    Parameters: CTestEngine* aEngine: in: Pointer to Test Engine

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
CTestEngineSubSession::CTestEngineSubSession( CTestEngine* aEngine ) :
    iTestEngine( aEngine )
    {
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineSubSession

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEngineSubSession::ConstructL()
    {
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineSubSession

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to Test Engine

    Return Values: CTestEngineSubSession* : pointer to created CTestEngineSubSession object

    Errors/Exceptions: Leaves if ConstructL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEngineSubSession* CTestEngineSubSession::NewL( CTestEngine* aEngine )    
    {
    CTestEngineSubSession* self = new ( ELeave ) CTestEngineSubSession( aEngine );
    CleanupClosePushL( *self );
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestEngineSubSession

    Method: ~CTestEngineSubSession

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEngineSubSession::~CTestEngineSubSession()
    {
    }


/*
-------------------------------------------------------------------------------

    DESCRIPTION

    This module contains implementation of CTestCase class member functions.

-------------------------------------------------------------------------------
*/

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

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: CTestCase

    Description: Default constructor

    C++ default constructor can NOT contain any code, that
    might leave.
    
    Parameters: CTestEngine* aEngine: in: Pointer to Test Engine
                CTestModuleController* aModuleController: in: Pointer to 
                  Module Controller
                TTestInfo& aTestInfo: in: Test info for this test case
                CTestModuleController* aRealModuleController: in: Pointer to
                  module controller used inside in scripter controller

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
CTestCase::CTestCase( CTestEngine* aEngine,
                     CTestModuleController* aModuleController,
                     TTestInfo& aTestInfo,
                     CTestModuleController* aRealModuleController ) :
    iTestEngine( aEngine ),
    iTestModule( aModuleController ),
    iRealModuleController (aRealModuleController)
    {
    
    // This method must be called to find out how
    // many testcases are currently ongoing by increasing iTestCaseCounter. 
    // This is a part of the implementation for 
    //  supporting test module crashing with -15
    iTestModule->CaseCreated();  

    // Store handle to RTestServer
    //If test scripter is used (it uses internally module controllers)
    //then use it (real module controller). 
    if(iRealModuleController)
        {
        iTestServer = iRealModuleController->Server(aTestInfo); 
        }
    else
        {
        iTestServer = iTestModule->Server( aTestInfo );
        }

    //If real test module controller is provided, increase test case count
    if(iRealModuleController)
        {
        iRealModuleController->CaseCreated();
        }
    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: CTestReport* aTestReport: in: Pointer to Test Report
                TTestInfo& aTestInfo: in: Test Info for this test case

    Return Values: None

    Errors/Exceptions: Leaves if RTestExecution::Open returns error
                       Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::ConstructL( CTestReport* aTestReport,
                           TTestInfo& aTestInfo )
    {
    __TRACE( KVerbose, ( _L( "CTestCase::ConstructL" ) ) );

    // Open handle to RTestExecution
    User::LeaveIfError( iTestExecution.Open( iTestServer,
        aTestInfo.iTestCaseInfo.iCaseNumber, aTestInfo.iConfig ) );

    // Make new test case runner
    iTestCaseController = CTestCaseController::NewL( iTestEngine,
        aTestReport, iTestModule->AtsLogger(), iTestExecution, aTestInfo );

    // Make new test case printer
    iTestCasePrint = CTestProgressNotifier::NewL( iTestEngine,
                                                  iTestExecution );

    iTestCaseEvent = CTestEventNotifier::NewL( iTestEngine, iTestExecution );

    iTestCaseRemoteCmd = CTestRemoteCmdNotifier::NewL( iTestEngine,
                                                    iTestExecution,
                                                    iTestCaseController,
                                                    iTestModule->AtsLogger() );

    iTestCaseCommand = CTestCommandNotifier::NewL(iTestEngine, iTestExecution);
    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to Test Engine
                CTestModuleController* aModuleController: in: Pointer to
                 Module Controller
                CTestReport* aTestReport: in: Pointer to Test Report
                TTestInfo& aTestInfo: in: Test Info for this test case

    Return Values: CTestCase* : pointer to created CTestCase object

    Errors/Exceptions: Leaves if ConstructL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestCase* CTestCase::NewL( CTestEngine* aEngine,
            CTestModuleController* aModuleController,
            CTestReport* aTestReport,
            TTestInfo& aTestInfo,
            CTestModuleController* aRealModuleController )    
    {
    CTestCase* self = new ( ELeave ) CTestCase( aEngine, aModuleController, aTestInfo, aRealModuleController );
    CleanupClosePushL( *self );
    self->ConstructL( aTestReport, aTestInfo );
    CleanupStack::Pop();
    return self;

    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: ~CTestCase

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestCase::~CTestCase()
    {
    CloseTestCase();
    
    // This added method call is a part of the implementation for 
    // supporting test module crashing with -15.
    // It checks that can old Testmodulecontroller be deletd or not 
	if( iTestModule != NULL )
		{
		iTestModule->CaseFinished();    
		}
	
    //If real test module controller is provided, decrease test case count
    if( iRealModuleController != NULL )
        {
        iRealModuleController->CaseFinished();
        }
    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: CloseTestCase

    Description: Close session

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::CloseTestCase()
    {
    __TRACE( KVerbose, ( _L( "CTestCase::CloseTestCase" ) ) );

    // Free allocated resources
    delete iTestCaseController;
    iTestCaseController = NULL;
    delete iTestCasePrint;
    iTestCasePrint = NULL;
    delete iTestCaseRemoteCmd;
    iTestCaseRemoteCmd = NULL;

    delete iTestCaseEvent;
    iTestCaseEvent = NULL;

    delete iTestCaseCommand;
    iTestCaseCommand = NULL;

    iTestExecution.Close();

    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: RunTestCaseL

    Description: Enumerates test cases

    Parameters: const RMessage& aMessage: in: Server Message

    Return Values: None

    Errors/Exceptions: Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::RunTestCaseL( const RMessage2& aMessage )
    {
    __TRACE( KVerbose, ( _L( "CTestCase::RunTestCaseL" ) ) );
    // Start active objects for running test case
    iTestCaseController->StartL( aMessage );
    iTestCaseEvent->Start();
    iTestCaseCommand->Start();
    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: Pause

    Description: Suspend the test case execution

    Parameters: None

    Return Values: TInt: Return value from RTestExecution::Pause

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestCase::Pause()
    {
    __TRACE( KVerbose, ( _L( "CTestCase::Pause" ) ) );

    return iTestExecution.Pause();

    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: Resume

    Description: Resume the suspended test case execution

    Parameters: None

    Return Values: TInt: Return value from RTestExecution::Resume

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestCase::Resume()
    {
    __TRACE( KVerbose, ( _L( "CTestCase::Resume" ) ) );

    return iTestExecution.Resume();

    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: NotifyProgressL

    Description: Notifies progresses from Test Module

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Leaves if called StartL method leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::NotifyProgressL( const RMessage2& aMessage )
    {
    __TRACE( KVerbose, ( _L( "CTestCase::NotifyProgressL" ) ) );
    iTestCasePrint->StartL( aMessage );

    }
    
/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: NotifyRemoteTypeL

    Description: Notifies remote commands from Test Module

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Leaves if called StartL method leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::NotifyRemoteTypeL( const RMessage2& aMessage )
    {
    
    __TRACE( KVerbose, ( _L( "CTestCase::NotifyRemoteTypeL" ) ) );
    iTestCaseRemoteCmd->EnableReceive( aMessage );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: NotifyRemoteMsgL

    Description: Notifies remote commands from Test Module

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: Leaves if called StartL method leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::NotifyRemoteMsgL( const RMessage2& aMessage )
    {
    
    __TRACE( KVerbose, ( _L( "CTestCase::NotifyRemoteMsgL" ) ) );
    switch( aMessage.Int1() )
        {
        case EStifCmdSend:
            {
            iTestCaseRemoteCmd->GetReceivedMsg( aMessage );
            }
            break;
        case EStifCmdReceive:
            {
            TInt len = aMessage.Int2();
            if( len <= 0 )
                {
                User::Leave( KErrGeneral );
                }
            HBufC8* buf = HBufC8::NewLC( len );

            TPtr8 tmp = buf->Des();
            aMessage.ReadL( 0, tmp );

            TInt ret = iTestExecution.ReadRemoteCmdInfo( tmp, EStifCmdReceive );

            CleanupStack::PopAndDestroy( buf );
            
            aMessage.Complete( ret );
            }
            break;
        case EStifCmdRebootProceed:
            {
            TInt value = 0;
            TPckg<TInt> tmp( value );
            aMessage.ReadL( 0, tmp );

            TInt ret = iTestExecution.ReadRemoteCmdInfo( tmp, 
                                                         EStifCmdRebootProceed,
                                                         value );        
            aMessage.Complete( ret );
            }
            break;
        default:
            {
            User::Leave( KErrGeneral );
            }  
        }            
    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: CancelAsyncRequest

    Description: Asynchronous requests are canceled by this function.

    Parameters: const RMessage aMessage

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::CancelAsyncRequest( const RMessage2& aMessage )
    {
    switch ( aMessage.Int0() )
        {
        case ETestCaseRunTestCase:
            {
            iTestCaseController->Cancel();
            iTestCaseEvent->Cancel();
            break;
            }
        case ETestCaseNotifyProgress:
            {
            iTestCasePrint->Cancel();
            break;
            }
        case ETestCaseNotifyRemoteType:
            {
            iTestCaseRemoteCmd->CancelReq();
            break;
            }
        case ETestCaseNotifyCommand:
            {
            iTestCaseCommand->Cancel();
            break;
            }
        default:
            iTestEngine->PanicClient( EBadRequest, aMessage );
            break;
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: ModuleName

    Description: Return the name of Test Module.

    Parameters: None

    Return Values: const TFileName& : Test Module owning this test case

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
const TDesC& CTestCase::ModuleName()
    {
    return iTestModule->ModuleName( KNullDesC );

    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: CtlEvent

    Description: Control events

    Parameters: const TEventIf& aEvent: in: Event
                TRequestStatus& aStatus: in: Request status

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::CtlEvent( const TEventIf& aEvent, TRequestStatus& aStatus )
    {
    __ASSERT_ALWAYS( iTestCaseEvent, User::Panic( _L( "TestEngine event panic" ), KErrArgument ) );
        
    iTestCaseEvent->CtlEvent( aEvent, aStatus );
    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: CheckCtlEvent

    Description: Check if CtlEvent should be called

    Parameters: const TEventIf& aEvent: in: Event

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TBool CTestCase::CheckCtlEvent( const TEventIf& aEvent )
    {
    return iTestCaseEvent->CheckCtlEvent( aEvent );
    }


/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: Logger

    Description: Return the pointer to Logger.

    Parameters: None

    Return Values: CStifLogger*: Pointer to StifLogger

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CStifLogger* CTestCase::Logger()
    {
    return iTestEngine->Logger();

    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: ExecuteCommaandL

    Description: Executes command received from test case.

    Parameters: aStifCommand command to be executed
                aParam1      parameter to command

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::ExecuteCommandL(TCommand aCommand, TDesC8& aParamsPckg)
    {
    switch(aCommand)
        {
        case EStopExecution:
            {
            //Unpack received parameters
            TStopExecutionCommandParams par;
            TStopExecutionCommandParamsPckg parPack(par);
            parPack.Copy(aParamsPckg);

            __TRACE(KVerbose, (_L("CTestCase::ExecuteCommandL command [%d] type [%d] code [%d]"), TInt(aCommand), TInt(par.iType), par.iCode));

            iTestCaseController->Suicide(par.iType, par.iCode);
            break;
            }
        default:
            __TRACE(KVerbose, (_L("CTestCase::ExecuteCommandL unknown command [%d]"), TInt(aCommand)));
            return;
        }

    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: GetModuleControllers

    Description: Return module controller and real module controller

    Parameters: aRealModuleController: out: real module controller

    Return Values: module controller

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestModuleController* CTestCase::GetModuleControllers(CTestModuleController** aRealModuleController)
    {
    *aRealModuleController = iRealModuleController;
    return iTestModule;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: ResetModuleController

    Description: Set new module controller for test case (only in case when 
                 original controller crashed)

    Parameters: aModuleController: in: new module controller

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::ResetModuleController(CTestModuleController* aModuleController)
    {
    iTestModule = aModuleController;
    }

/*
-------------------------------------------------------------------------------

    Class: CTestCase

    Method: ResetRealModuleController

    Description: Set new real module controller for test case (only in case 
                 when original controller crashed).

    Parameters: aRealModuleController: in: new real module controller

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCase::ResetRealModuleController(CTestModuleController* aRealModuleController)
    {
    iRealModuleController = aRealModuleController;
    }

/*
-------------------------------------------------------------------------------

    DESCRIPTION

    This module contains implementation of CRebootParams class member functions.

-------------------------------------------------------------------------------
*/

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

/*
-------------------------------------------------------------------------------

    Class: CRebootParams

    Method: CRebootParams

    Description: Default constructor
    
    Parameters: None
    
    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
CRebootParams::CRebootParams()
    {
    }

/*
-------------------------------------------------------------------------------

    Class: CRebootParams

    Method: ConstructL

    Description: Symbian OS second phase constructor


    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if RTestExecution::Open returns error
                       Leaves if some of called leaving methods leaves

    Status: Draft

-------------------------------------------------------------------------------
*/
void CRebootParams::ConstructL()
    {
    }

/*
-------------------------------------------------------------------------------

    Class: CRebootParams

    Method: NewL

    Description: Two-phased constructor.

    Parameters: none
    
    Return Values: CRebootParams* : pointer to created CRebootParams object

    Errors/Exceptions: Leaves if ConstructL leaves

    Status: Draft

-------------------------------------------------------------------------------
*/
CRebootParams* CRebootParams::NewL()    
    {
    
    CRebootParams* self = new ( ELeave ) CRebootParams();
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
    return self;

    }

/*
-------------------------------------------------------------------------------

    Class: CRebootParams

    Method: ~CRebootParams

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
CRebootParams::~CRebootParams()
    {
    
    delete iTestModuleBuf;
    iTestModuleBuf = 0;
    delete iTestCaseFileBuf;
    iTestCaseFileBuf = 0;
    delete iTestCaseTitleBuf;
    iTestCaseTitleBuf = 0;
    delete iStateNameBuf;
    iStateNameBuf = 0;
    
    }


/*
-------------------------------------------------------------------------------

    Class: CRebootParams

    Method: SetTestModuleNameL

    Description: Setter

    Parameters: const TDesC& aName: in: name to set

    Return Values: None

    Errors/Exceptions: Leaves if memory allocation fails
    
    Status: Draft

-------------------------------------------------------------------------------
*/        
void CRebootParams::SetTestModuleNameL( const TDesC& aName )
    {
    
    delete iTestModuleBuf;
    iTestModuleBuf = 0;
    iTestModuleBuf = aName.AllocLC();
    iTestModule.Set( iTestModuleBuf->Des() );
    CleanupStack::Pop( iTestModuleBuf );
    
    }

/*
-------------------------------------------------------------------------------

    Class: CRebootParams

    Method: SetTestModuleNameL

    Description: Setter

    Parameters: const TDesC& aName: in: name to set

    Return Values: None

    Errors/Exceptions:  Leaves if memory allocation fails

    Status: Draft

-------------------------------------------------------------------------------
*/        
void CRebootParams::SetTestCaseFileNameL( const TDesC& aName )
    {
    
    delete iTestCaseFileBuf;
    iTestCaseFileBuf = 0;
    iTestCaseFileBuf = aName.AllocLC();
    iTestCaseFile.Set( iTestCaseFileBuf->Des() );
    CleanupStack::Pop( iTestCaseFileBuf );
    
    }
    
/*
-------------------------------------------------------------------------------

    Class: CRebootParams

    Method: SetTestModuleNameL

    Description: Setter

    Parameters: const TDesC& aName: in: name to set

    Return Values: None

    Errors/Exceptions:  Leaves if memory allocation fails

    Status: Draft

-------------------------------------------------------------------------------
*/        
void CRebootParams::SetTestCaseTitleL( const TDesC& aName )
    {
    
    delete iTestCaseTitleBuf;
    iTestCaseTitleBuf = 0;
    iTestCaseTitleBuf = aName.AllocLC();
    iTestCaseTitle.Set( iTestCaseTitleBuf->Des() );
    CleanupStack::Pop( iTestCaseTitleBuf );
    
    }
    
/*
-------------------------------------------------------------------------------

    Class: CRebootParams

    Method: SetTestModuleNameL

    Description: Setter

    Parameters: const TDesC& aName: in: name to set

    Return Values: None

    Errors/Exceptions: Leaves if memory allocation fails

    Status: Draft

-------------------------------------------------------------------------------
*/        
void CRebootParams::SetTestCaseStateL( const TDesC& aName )
    {
    
    delete iStateNameBuf;
    iStateNameBuf = 0;
    iStateNameBuf = aName.AllocLC();
    iStateName.Set( iStateNameBuf->Des() );
    CleanupStack::Pop( iStateNameBuf );
    
    }

    
/*
-------------------------------------------------------------------------------

    DESCRIPTION

    This module contains implementation of TEventMsg class member functions.

-------------------------------------------------------------------------------
*/

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

/*
-------------------------------------------------------------------------------

    Class: TEventMsg

    Method: TEventMsg

    Description: Default constructor
    
    Parameters: None
    
    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/    
TEventMsg::TEventMsg():
    TEventIf(),
    iWaitPending(EFalse), 
    iStateEventPending(EFalse),
    iStatus( NULL )
    {
    }

/*
-------------------------------------------------------------------------------

    Class: TEventMsg

    Method: ~TEventMsg

    Description: Destructor
    
    Parameters: None
    
    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/    
TEventMsg::~TEventMsg()
    {
    if( iWaitPending )
        {
        iWaitMsg.Complete( KErrCancel );
        iWaitPending = EFalse;
        }
        
    if( iStatus )
        {
        User::RequestComplete( iStatus, KErrCancel );
        }

    }

/*
-------------------------------------------------------------------------------

    Class: TEventMsg

    Method: Set

    Description: Set event.
    
    Parameters: TEventType aEventType: in: Event type
    
    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/    
void TEventMsg::Set( TEventType aEventType )
    {
    iEventType = aEventType;
    if( aEventType == EState )
        {
        iStateEventPending = ETrue;
        }
    if( iWaitPending )
        {
        TEventIf event;
        event.Copy( *this );
        TEventIfPckg eventIfPckg( event );
        iWaitMsg.WriteL( 0, eventIfPckg );

        iWaitMsg.Complete( KErrNone );
        iWaitPending = EFalse;
        }
    } 

/*
-------------------------------------------------------------------------------

    Class: TEventMsg

    Method: Wait

    Description: Wait event.
    
    Parameters: const RMessage& aMessage: in: Message
    
    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void TEventMsg::Wait( const RMessage2& aMessage )
    { 
    if( iStateEventPending )
        {
        TEventIf event;
        event.Copy( *this );
        TEventIfPckg eventIfPckg( event );
        aMessage.WriteL( 0, eventIfPckg );
        aMessage.Complete( KErrNone );
        }
    else
        {
        iWaitMsg = aMessage;
        iWaitPending = ETrue;
        }
    }

/*
-------------------------------------------------------------------------------

    Class: TEventMsg

    Method: CancelWait

    Description: Cancel pending Wait
    
    Parameters: None
    
    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/    
void TEventMsg::CancelWait()
    {
    if( iWaitPending )
        {
        iWaitMsg.Complete( KErrCancel );
        iWaitPending = EFalse;
        } 
    } 
             
/*
-------------------------------------------------------------------------------

    Class: TEventMsg

    Method: Release

    Description: Release event. Unset released.
    
    Parameters: None
    
    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/    
void TEventMsg::Release()
    { 
    
    if( iStatus )
        {
        User::RequestComplete( iStatus, KErrNone );
        }
        
    } 
/*
-------------------------------------------------------------------------------

    Class: TEventMsg

    Method: Unset

    Description: Unset event. Blocks until Release is called.
    
    Parameters: TRequestStatus& aStatus: in: Status 
    
    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/    
void TEventMsg::Unset( TRequestStatus& aStatus )
    { 
    
    iStatus = &aStatus;
    
    } 

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

/*
-------------------------------------------------------------------------------

    Function: StartEngine

    Description: This is called from the client.

    Parameters: None

    Return Values: TInt KErrNone: No errors occured
                        KErrNoMemory: Memory is too low to create Test Engine
                        Other error code: Error got from iEngineThread.Create()

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
EXPORT_C TInt StartEngine()
    {
    __UHEAP_MARK;

    // check server not already started
    TFindServer findTestEngineServer( KTestEngineName );
    TFullName name;
    if ( findTestEngineServer.Next( name ) == KErrNone )
        {   
        // Server already started, nothing to do    
        __UHEAP_MARKEND;
        return KErrNone;
        }

    // Construct start-up information object
    TThreadStartTestEngine* startInfo = new TThreadStartTestEngine();
    if ( startInfo == NULL )
        {
        __UHEAP_MARKEND;
        return KErrNoMemory;
        }

    startInfo->iStarted.CreateLocal( 0 );     // Create start-up semaphore

    // Create thread    
    TInt ret = startInfo->iEngineThread.Create(
        KTestEngineName ,                               // name of thread
        CTestEngineServer::ThreadFunction,              // thread function
        KDefaultStackSize*4,                            // stack
        KTestEngineMinHeapSize,KTestEngineMaxHeapSize*4,// Heap
        startInfo                                       // parameter to thread
                                                        // function
        );

    if ( ret != KErrNone )
        {
        startInfo->iStarted.Close();
        delete startInfo;
        __UHEAP_MARKEND;
        return ret;
        }

    // Now start thread
    startInfo->iEngineThread.SetPriority( EPriorityMuchMore );  // set its
                                                                // priority
    startInfo->iEngineThread.Resume();                          // kick it
                                                                // into life

    // Wait until the thread is started
    startInfo->iStarted.Wait(); 

    // Clean-up 
    startInfo->iEngineThread.Close();
    startInfo->iStarted.Close(); 


    delete startInfo;

    __UHEAP_MARKEND;

    return KErrNone;

    }


//  End of File
