/*
* 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 
* CTestModuleController class member functions.
*
*/

// INCLUDE FILES
#include <e32svr.h>
#include <stifinternal/TestServerClient.h>
#include <StifLogger.h>
#include "TestEngine.h"
#include "TestModuleController.h"
#include "Logging.h"

// EXTERNAL DATA STRUCTURES
// None

// EXTERNAL FUNCTION PROTOTYPES
// None

// CONSTANTS
// None

// MACROS
// None

// LOCAL CONSTANTS AND MACROS
// None

// MODULE DATA STRUCTURES
// None

// LOCAL FUNCTION PROTOTYPES
// None

// FORWARD DECLARATIONS
// None

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

#define LOGGER iEngine->Logger()

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

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

    Class: CTestModuleController

    Method: CTestModuleController

    Description: Default constructor

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

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestModuleController::CTestModuleController( CTestEngine* aEngine ) :
    CActive( CActive::EPriorityStandard ),
    iEngine( aEngine ),
    iState( ETestModuleIdle )
    {
    CActiveScheduler::Add( this );
    iTestScripterController = NULL;

    }

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

    Class: CTestModuleController

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

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

    Return Values: None

    Errors/Exceptions: Leaves if memory allocation for iConfigFiles fails
                       Leaves if memory allocation for iTestCaseArray fails

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestModuleController::ConstructL( 
                            const TName& aName,
                            TBool aAfterReboot,
                            CTestScripterController* aTestScripterController )
    {
    iTestScripterController = aTestScripterController;
    iTestScripterIndicator = 0;
    
    iAfterReboot = aAfterReboot;

    __TRACE ( KInit, ( _L( "Creating CTestModuleController [%S]" ), &aName ) );

    iTestCaseArray = RPointerArray<TTestCaseArray>();

    // Check aName length
    if( aName.Length() <= 0 )
        {
        iEngine->LeaveWithNotifyL( KErrArgument );
        }

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

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

    iName = name.AllocL();

    // HBufC to TPtrC
    TPtrC atsName;

    TFileName newNameBuffer;
    TInt check = GenerateModuleName( iName->Des(), newNameBuffer );
    if( check == KErrNone )
        {
        // Load the module(TestScripter)
        atsName.Set( newNameBuffer );
        }
    else
        {
        // Load the module(Others)
        atsName.Set( iName->Des() );
        }

    // Moved the implementation to a new function, ConstructASTLoggerL, due to
    // CW 3.0 compiler error with multiple TRAPDs
    TRAPD(err, ConstructASTLoggerL( atsName, aAfterReboot));

    if( err != KErrNone )
        {
         __TRACE ( KError, ( _L( "CTestModuleController[%S]::ConstructL: Creation of ATS logger failed" ), iName ) );
        iEngine->LeaveWithNotifyL( err, _L("Creation of ATS logger failed") );
        }

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

    Class: CTestModuleController

    Method: ConstructASTLoggerL

    Description: Construct ATS logger

    Parameters: TDesC& atsName, TBool& aAfterReboot

    Return Values: TInt

    Errors/Exceptions: Leaves if error got from ATS logger NewL

    Status: Proposal

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

TInt CTestModuleController::ConstructASTLoggerL( TDesC& atsName, TBool& aAfterReboot )
    {
    TRAPD( err, iAtsLogger = CAtsLogger::NewL( atsName, aAfterReboot ); );
    if( err == KErrNotFound && aAfterReboot )
        {
        // If file does not exist, create new 
        aAfterReboot = EFalse;
        iAtsLogger = CAtsLogger::NewL( atsName, aAfterReboot );
        }
    User::LeaveIfError( err );
    iAtsLogger->SetFullReporting( ETrue );
    if( aAfterReboot )
        {
        iAtsLogger->ContinueAfterRebootL();
        }
    else
        {
        // Begin reporting
        iAtsLogger->BeginTestReportL();
          
        // Begin test set
        iAtsLogger->BeginTestSetL();
        }
    return KErrNone;
    }
/*
-------------------------------------------------------------------------------

    Class: CTestModuleController

    Method: InitL

    Description: Initialize test module.

    Parameters: TFileName& aIniFile: in: Initialization file of Test Module
                const TDesC& aConfigFile: in: Test case(config) file name(Used 
                in TestScripter case).

    Return Values: None

    Errors/Exceptions: Leaves if error got from Test Server

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestModuleController::InitL( TFileName& aIniFile, 
                                    const TDesC& aConfigFile )
    {
    __TRACE( KInit, (_L( "Initialising test module [%S] with initialization file [%S]" ),
        iName, &aIniFile ) );

    // HBufC to TPtrC
    TPtrC name( iName->Des() );

    // Connect to server
    TInt r = iServer.Connect( name, aConfigFile );

    if ( r != KErrNone )
        {
        __TRACE( KError, ( CStifLogger::ERed, _L( "Can't connect to test module [%S], IniFile [%S]" ), &name, &aIniFile ) );
        LeaveWithNotifyL( r,  _L( "Can't connect to test module" ) );
        }

    // Open session 
    r = iModule.Open( iServer, aIniFile );
    if ( r != KErrNone )
        {
        __TRACE( KError, ( CStifLogger::ERed, _L( "Can't open session to test module [%S], IniFile=[%S]" ), &name, &aIniFile ) );
        LeaveWithNotifyL( r, _L( "Can't open session to test module" ) );
        }

    iErrorPrinter = CErrorPrinter::NewL( iEngine );
    iErrorPrinter->StartL( iModule );

    iServerStateHandler = CServerStateHandler::NewL( iEngine, this );
    iServerStateHandler->StartL( iServer );
    __TRACE( KInit, (_L( "Initialising test module [%S] with initialization file [%S] done" ),
        iName, &aIniFile ) );

    }

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

    Class: CTestModuleController

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: CTestEngine object.
                const TName& aName: in: module name.
                TBool aAfterReboot: in: reboot indicator.
                TBool aCreateTestScripterCont: in: Indications to
                TestModule or TestScripter creation
                CTestScripterController* aTestScripterController: in:
                CTestEngine object.


    Return Values: CTestModuleController* : pointer to created object

    Errors/Exceptions: Leaves if called ConstructL method leaves

    Status: Proposal

-------------------------------------------------------------------------------
*/
CTestModuleController* CTestModuleController::NewL( 
                            CTestEngine* aEngine,
                            const TName& aName,
                            TBool aAfterReboot,
                            TBool aCreateTestScripterCont,
                            CTestScripterController* aTestScripterController )
    {
    // Create CTestScripterController
    if( aCreateTestScripterCont )
        {
        CTestScripterController* testScripterController = NULL;
        testScripterController = CTestScripterController::NewL(
            aEngine, aName, aAfterReboot );
        return testScripterController;  
        }


    CTestModuleController* self =
        new ( ELeave ) CTestModuleController( aEngine );
    CleanupStack::PushL( self );
    self->ConstructL( aName, aAfterReboot, aTestScripterController );
    CleanupStack::Pop( self );
    return self;

    }

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

    Class: CTestModuleController

    Method: ~CTestModuleController

    Description: Destructor

    Deallocate all allocated resources

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
CTestModuleController::~CTestModuleController()
    {

    // If CTestScripterController is created there is deleted base class(
    // CTestModuleController) also and this has no iName.
    if( iName )
        {
        __TRACE(KVerbose, (_L( "Deleting CTestModuleController [%S]" ), iName ) );
        }

    Cancel();

    // If CTestScripterController is created there is deleted base class(
    // CTestModuleController) also and this has no iAtsLogger.
    if( iAtsLogger )
        {
        // End test set
        TRAPD( err, iAtsLogger->EndTestSetL() );
        // End AtsLogger reporting, has to be trapped in destructor
        TRAPD( err2, iAtsLogger->EndTestReportL() );
        if( ( err != KErrNone ) || ( err2 != KErrNone ) )
            {
            // Print error if error got from trap
            __TRACE( KError, ( 
                _L( "Destructor of CTestModuleController [%S]: XML log closing failed" ),
                iName ) );
            }
        }

    // Delete Atslogger
    delete iAtsLogger;

    // Stop error printer
    delete iErrorPrinter;
    iErrorPrinter = NULL;
    // Delete server state handler
    delete iServerStateHandler;
    iServerStateHandler = NULL;

    // Close RTestModule session
    iModule.Close();
    // Close RTestServer session
    iServer.Close();

    // Release the test case array
    iTestCaseArray.Close();

    // Release the config file array
    iConfigFiles.Close();

    // Release the config file array
    iFailedEnumerateConfig.Reset();
    iFailedEnumerateConfig.Close();
    
    // Release the children array
    iChildrenControllers.ResetAndDestroy();
    iChildrenControllers.Close();

    delete iName;

    }

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

    Class: CTestModuleController

    Method: AddConfigFileL

    Description: Add config file

    Parameters: TFileName& aConfigFile: in: Config file for Test Module

    Return Values: None

    Errors/Exceptions: Leaves if AppendL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestModuleController::AddConfigFileL( TFileName& aConfigFile )
    {
    __TRACE( KInit,
        ( _L( "CTestModuleController::AddConfigFileL [%S] aConfigFile=[%S]" ),
        iName, &aConfigFile ) );
    // Check that this config file does not already exists
    for ( TInt i = 0; i < iConfigFiles.Count(); i++ )
        {
        // HBufC to TPtrC
        TPtrC name( iConfigFiles[i]->Des() );
        if ( KErrNone == aConfigFile.CompareF( name ) )
            {
            LeaveWithNotifyL( KErrAlreadyExists,  
                _L( "Adding config file failed: Config file already exists" ) );
            }
        }
    HBufC* configFile = aConfigFile.AllocLC();

    User::LeaveIfError( iConfigFiles.Append( configFile ) );
    CleanupStack::Pop( configFile );

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

    Class: CTestModuleController

    Method: RemoveConfigFileL

    Description: Remove config file

    Parameters: TFileName& aConfigFile: in: Config file name

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestModuleController::RemoveConfigFileL( TFileName& aConfigFile )
    {
    __TRACE( KInit, ( 
        _L( "CTestModuleController::RemoveConfigFileL [%S] aConfigFile=[%S]" ),
        iName, &aConfigFile ) );
    // Find config file
    for ( TInt i = 0; i < iConfigFiles.Count(); i++ )
        {
        // HBufC to TPtrC
        TPtrC name( iConfigFiles[i]->Des() );
        if ( KErrNone == aConfigFile.CompareF( name ) )
            {
            HBufC* configFile = iConfigFiles[i];
            iConfigFiles.Remove(i);
            delete configFile;
            // Cancel enumerate and free test cases
            Cancel();
            FreeTestCases();
            return;
            }
        }
        
    LeaveWithNotifyL( KErrNotFound, 
        _L( "Removing config file failed: Config file not found" ) );
            
    }

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

    Class: CTestModuleController

    Method: StartEnumerateL

    Description: Start test case enumeration

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestModuleController::StartEnumerateL()
    {
    __TRACE( KVerbose, ( 
        _L( "CTestModuleController::StartEnumerateL [%S]" ), iName ) ); 
    iTestCaseCount = 0;
    iEnumerateCount = 0;
    iFailedEnumerateCount = 0;
    iFailedEnumerateConfig.Reset();
    iEnumerateComplete = EFalse;

    iState = ETestModuleEnumerateCases;

    if ( iConfigFiles.Count() > 0 )
        {
        // HBufC to TPtrC
        iEnumConfigFile.Set( iConfigFiles[0]->Des() );
        }

    __TRACE( KInit, ( 
        _L( "Getting testcases from module [%S], test case file [%S]" ),
        iName, &iEnumConfigFile ) );

    SetActive();
    iModule.EnumerateTestCases( iEnumConfigFile, iEnumResultPackage, iStatus );

    }

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

    Class: CTestModuleController

    Method: RunL

    Description: RunL handles completed requests.

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if iStatus is not KErrNone
                       Leaves if some of called leaving methods leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestModuleController::RunL()
    {

    // If CTestScripterController is used then move execution to the
    // CTestScripterController size
    if( iTestScripterController )
        {
        iTestScripterController->RunLEmulator( this );
        return;
        }

    __TRACE( KVerbose, ( _L( "CTestModuleController::RunL [%S] [iStatus = %d]"),
        iName, iStatus.Int() ) );

    // Note:
    // If test case not found there may be existing cases from previous
    // enumerations, so those cases are valid. e.g. case: "add test case file",
    // "add test case file that not exist" and "get test cases".

    TInt ret( KErrNone );
    // Check that request was successful
    if( iStatus.Int() == KErrNone )
        {
        // Get enumerated test cases and append them to array
        CFixedFlatArray<TTestCaseInfo>* testCases = 
            CFixedFlatArray<TTestCaseInfo>::NewL( iEnumResultPackage() );
        CleanupStack::PushL( testCases );
        ret = iModule.GetTestCases( *testCases );
        __TRACE( KInit, ( _L( "RunL()'s GetTestCases method returns: %d" ), ret ) );

        iTestCaseCount += testCases->Count();

        if ( testCases->Count() == 0 )
            {

            if (iConfigFiles.Count() > 0)
                {
                __TRACE( KInit, ( CStifLogger::EBold, 
                    _L( "Module [%S], test case file [%S] returned 0 cases" ),
                    iName,  iConfigFiles[iEnumerateCount] ) );
                }
            else
                {
                __TRACE( KInit, ( CStifLogger::EBold, 
                    _L( "Module [%S] without test case file, returned 0 cases" ),
                    iName ) );
                }
            iEngine->ErrorPrint( 1, _L("Someone returned 0 test cases. Check testengine log"));
            iAtsLogger->CommentL( _L("Test module returned 0 test cases") );   
            }

        // Store test cases for later use
        User::LeaveIfError( iTestCaseArray.Append( testCases ) );
        CleanupStack::Pop( testCases );
        
        }
    else
        {
        // Calculate failed enumeration count
        iFailedEnumerateCount++;
        // Add failed config(test case) file to array for later removing
        if( iConfigFiles.Count() != NULL )
            {
            __TRACE( KError, (
                CStifLogger::ERed, 
                _L( "Test case[%S] enumeration fails with error: %d" ),
                iConfigFiles[iEnumerateCount], iStatus.Int() ) );
            // Append
            iFailedEnumerateConfig.Append( iConfigFiles[iEnumerateCount] );
            }
        }

    iEnumerateCount++;

    if ( iEnumerateCount < iConfigFiles.Count() )
        {
        // Continue enumeration
        __TRACE( KInit, ( 
            _L( "Getting testcases from module [%S], test case file [%S]" ),
            iName, iConfigFiles[iEnumerateCount] ) );
        SetActive();
        iModule.EnumerateTestCases( *iConfigFiles[iEnumerateCount],
                                    iEnumResultPackage, iStatus );
        }
    else if( iTestCaseCount == 0 )
        {
        // Total count of succesfully enumerations
        iEnumerateCount -= iFailedEnumerateCount;
        User::Leave( KErrNotFound );
        }
    else
        {
        // Total count of succesfully enumerations
        iEnumerateCount -= iFailedEnumerateCount;
        // Remove faulty config (test case) file(s)
        for( TInt a= 0; a < iFailedEnumerateConfig.Count(); a++ )
            {
            TInt index( 0 );
            // Find removed config(test case) file
            index = iConfigFiles.Find( iFailedEnumerateConfig[a] );
            if( index != KErrNotFound )
                {
                __TRACE( KInit, ( _L( "Removing test case file[%S]" ),
                    iConfigFiles[index] ) );
                // Remove
                iConfigFiles.Remove( index );
                }
            }

        // All test cases enumerated
        iState = ETestModuleEnumerateCasesCompleted;
        iEnumerateComplete = ETrue;

        iEngine->EnumerationCompleted( iTestCaseCount );
        }

    }

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

    Class: CTestModuleController

    Method: TestCasesL

    Description: Return Test Cases

    Parameters: None

    Return Values: CFixedFlatArray<TTestInfo>* :Pointer to created array

    Errors/Exceptions: Leaves if NewL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
CFixedFlatArray<TTestInfo>* CTestModuleController::TestCasesL()
    {
    CFixedFlatArray<TTestInfo>* testCases = 
        CFixedFlatArray<TTestInfo>::NewL( iTestCaseCount );

    CleanupStack::PushL( testCases );

    // Loop through all test cases from all config files
    TInt totalCount = 0;
    // HBufC to TPtrC
    TPtrC name( iName->Des() );
    for ( TInt i = 0; i < iEnumerateCount; i++ )
        {
        TTestInfo tmpInfo;
        tmpInfo.iModuleName = name;
        if ( iConfigFiles.Count() > 0 )
            {
            tmpInfo.iConfig = *iConfigFiles[i];
            }

        // Get test cases from iTestCaseArray at [i]
        //if( (iTestCaseArray)[i] )
		if ( iTestCaseArray.Count() > 0) 
            {
            CFixedFlatArray<TTestCaseInfo>* tempTestCases = (iTestCaseArray)[i];
            for ( TInt j = 0; j < tempTestCases->Count(); j++ )
                {
                tmpInfo.iTestCaseInfo = (*tempTestCases)[j];
                // Set TestCaseInfo to testCases array
                testCases->Set( totalCount, tmpInfo );
                totalCount++;
                }
            }
        }

    CleanupStack::Pop( testCases );

    return testCases;

    }

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

    Class: CTestModuleController

    Method: FreeTestCases

    Description: Free memory used for test cases

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestModuleController::FreeTestCases()
    {
    // Reset and destroy test cases
    iTestCaseArray.ResetAndDestroy();
    iTestCaseArray.Close();

    iTestCaseCount = 0;
    iEnumerateComplete = EFalse;

    }

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

    Class: CTestModuleController

    Method: DoCancel

    Description: Cancel active request

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestModuleController::DoCancel()
    {

    // If CTestScripterController is used then move execution to the
    // CTestScripterController size
    if( iTestScripterController )
        {
        iTestScripterController->DoCancelEmulator( this );
        return;
        }

    __TRACE( KVerbose, ( _L( "CTestModuleController::DoCancel [%S]" ), iName ) );

    switch ( iState )
        {
        case ETestModuleEnumerateCases:
            iModule.CancelAsyncRequest( ETestModuleEnumerateTestCases );
            iEnumerateComplete = ETrue;
            // Enumeration canceled, complete with KErrCancel
            iEngine->EnumerationCompleted( 0, KErrCancel );

            // Free allocated test cases because EnumerateTestCases was
            // canceled
            FreeTestCases();
            break;
        case ETestModuleIdle:
        case ETestModuleEnumerateCasesCompleted:
        default:
            // DoCancel called in wrong state => Panic
            _LIT( KTestModuleController, "CTestModuleController" );
            User::Panic( KTestModuleController, EDoCancelDisorder );
            break;
        }

    iAtsLogger->ErrorL( _L("Test case enumeration cancelled") );   

    iState = ETestModuleIdle;

    }

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

    Class: CTestModuleController

    Method: RunError

    Description: Handle errors.

    Parameters: TInt aError: in: Symbian OS error: Error code

    Return Values: TInt KErrNone: Always returned KErrNone

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
TInt CTestModuleController::RunError( TInt aError )
    {

    // If CTestScripterController is used then move execution to the
    // CTestScripterController size
    if( iTestScripterController )
        {
        return iTestScripterController->RunErrorEmulator( aError, this );
        }

    __TRACE( KError, ( CStifLogger::ERed, 
        _L( "CTestModuleController::RunError [%S] aError=[%d]" ),
        iName, aError ) );
    if( aError == KErrNoMemory )
        {
        __TRACE( KError, ( CStifLogger::ERed, 
            _L( "No memory available. Test case file's size might be too big." ) ) );
        }

    iEnumerateComplete = ETrue;

    iAtsLogger->ErrorL( _L("Test module did not return any test cases") );
    
    _LIT( KErrorText, " did not return any test cases [error: ");
    if( KErrorText().Length() + iName->Length() + 1 < KMaxName )
        {
        // Enumeration failed, print warning and complete with KErrNone
        TName error( iName->Des() );
        error.Append( KErrorText );  
        error.AppendNum( aError );  
        error.Append( _L("]") );  
        iEngine->ErrorPrint ( 0, error );
    
        iEngine->EnumerationCompleted( 0, KErrNone );
        }
    else 
        {
        // Cannot only print warning, complete with error
        iEngine->EnumerationCompleted( 0, aError );
        }        

    // Free allocated test cases because EnumerateTestCases failed
    FreeTestCases();
    iEnumerateComplete = ETrue;

    return KErrNone;
    }

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

    Class: CTestModuleController

    Method: Server

    Description: Return handle to Test Server

    Parameters: TTestInfo& aTestInfo: in: Test info for this test case

    Return Values: RTestServer& : Reference to RTestServer

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
RTestServer& CTestModuleController::Server( TTestInfo& /*aTestInfo*/ )
    {
    return iServer;

    }

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

    Class: CTestModuleController

    Method: GetFreeOrCreateModuleControllerL

    Description: Return pointer to module controller.
                 Find module controller which does not run test case
                 and if this is not possible then create new one.
                 (Only for test scripter).

    Parameters: TTestInfo& aTestInfo: in: Test info for this test case
                TBool aUITestingSupport: in: Is UI testing mode enabled

    Return Values: CTestModuleController* : pointer to module controller

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestModuleController* CTestModuleController::GetFreeOrCreateModuleControllerL(TTestInfo& /*aTestInfo*/, TBool /*aUItestingSupport*/)
    {
    return NULL;
    }

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

    Class: CTestModuleController

    Method: ModuleName

    Description: Return the name of Test Module

    Parameters: const TDesC& aModuleName: in Modulename

    Return Values: const TDesC : Name of Test Module

    Errors/Exceptions: None

    Status: proposal

-------------------------------------------------------------------------------
*/
const TDesC& CTestModuleController::ModuleName( const TDesC& /*aModuleName*/ )
    {
    return *iName;

    }

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

    Class: CTestModuleController

    Method: EnumerationComplete

    Description: Is enumeration of test cases complete.

    Parameters: None
    
    Return Values: TBool ETrue: Enumeration of test cases is complete
                         EFalse: Enumeration is not complete

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TBool CTestModuleController::EnumerationComplete()
    {
    return iEnumerateComplete;

    }

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

    Class: CTestModuleController

    Method: LeaveWithNotifyL

    Description: Print out info and leave.

    Parameters: TInt aCode: in: Error code 
                const TDesC& aText: in: Test info
    
    Return Values: None
    
    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestModuleController::LeaveWithNotifyL( TInt aCode, const TDesC& aText )
    {

    __TRACE( KError, ( CStifLogger::ERed, aText ) );
    if( iAtsLogger )
        {
        iAtsLogger->ErrorL( aText );
        }
    iEngine->LeaveWithNotifyL( aCode );

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

    Class: CTestModuleController

    Method: CaseCreated

    Description: Increases the value of iTestCaseCounter

    Parameters: None
    
    Return Values: None
    
    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/  
void CTestModuleController::CaseCreated()
    {
    // Number of ongoing testcases
    iTestCaseCounter++;
    }

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

    Class: CTestModuleController

    Method: CaseFinished

    Description: Decreases the value of iTestCaseCounter and deletes this pointer
                 only in test module crash situations (KErrServerTerminated -15)

    Parameters: None:
    
    Return Values: None
    
    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/  
void CTestModuleController::CaseFinished()
    {
    // Number of ongoing testcases
    iTestCaseCounter--;
    
    // iTestModuleCrashDetected tells is TestModuleController cloned or not
    // TestModuleController is cloned only when testmodule is crashed with KErrServerTerminated -15
    if (iTestCaseCounter == 0 && iTestModuleCrashDetected)
       {
       // Delete this in case where it has been replaced with it clone
       // and no one have pointer to this. This happens only when test module
       // crashes    
  	   delete this;
  	   // Mem::Fill(this, sizeof(CTestModuleController), 0xa1a1a1a1);
       }
       
    }
    
/*
-------------------------------------------------------------------------------

    Class: CTestModuleController

    Method: CloneL

    Description: 

    Parameters: 
    
    Return Values: 
    
    Errors/Exceptions: 

    Status: 

-------------------------------------------------------------------------------
*/    
CTestModuleController* CTestModuleController::CloneL( 
                            CTestModuleController* aTestModuleController,
                            TBool aAfterReset,
                            CTestScripterController* aTestScripterController )
    {
    __TRACE( KInit, ( _L( "Cloning CTestModuleController" ) ) );
   
    
    TName crashModuleName;
    crashModuleName = aTestModuleController->ModuleName( crashModuleName );
    
    CTestModuleController* clone = CTestModuleController::NewL( iEngine, crashModuleName, aAfterReset, EFalse, aTestScripterController );
    
    clone->InitL( aTestModuleController->iInifile, KNullDesC );

	// Give ATS logger to clone
	clone->iAtsLogger = iAtsLogger;
	iAtsLogger = NULL; 
	
    for ( TInt i = 0; i < aTestModuleController->iConfigFiles.Count(); i++ )
	    {
		TPtrC configFile = aTestModuleController->iConfigFiles[i]->Des();
		TFileName config = configFile;
   	    clone->AddConfigFileL( config );
   	    }   
	
	iTestModuleCrashDetected = ETrue;       
	
    __TRACE( KVerbose, ( _L( "Cloning of CTestModuleController finished " ) ) );
    return clone; 
    }    

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

    Class: CTestModuleController

    Method: DeleteModuleController

    Description: In that class this method does nothing. It is implemented
                 in CTestScripterController.

    Parameters: CTestModuleController* aRealModuleController: not used
    
    Return Values: None
    
    Errors/Exceptions: None

    Status: 

-------------------------------------------------------------------------------
*/    
void CTestModuleController::DeleteModuleController(CTestModuleController* /*aRealModuleController*/)
    {
    } 

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

    Class: CTestModuleController

    Method: RemoveModuleController

    Description: In that class this method does nothing. It is implemented
                 in CTestScripterController.

    Parameters: CTestModuleController* aRealModuleController: not used
    
    Return Values: None
    
    Errors/Exceptions: None

    Status: 

-------------------------------------------------------------------------------
*/    
void CTestModuleController::RemoveModuleController(CTestModuleController* /*aRealModuleController*/)
    {
    } 

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

    Class: CTestModuleController

    Method: EnumerateSynchronously

    Description: Enumerates test module controller. Used only when new
                 test module controller is created during test case
                 execution.

    Parameters: None
    
    Return Values: None
    
    Errors/Exceptions: None

    Status: 

-------------------------------------------------------------------------------
*/    
void CTestModuleController::EnumerateSynchronously(void)
    {
    TInt i;
    TInt cfgfiles = iConfigFiles.Count();
    __TRACE(KInit, (_L("Module controller will enumerate synchronously [%d] config files"), cfgfiles));
    
    for(i = 0; i < cfgfiles; i++)
        {
        TRequestStatus status; 
        iModule.EnumerateTestCases(*iConfigFiles[i],
                                   iEnumResultPackage, 
                                   status);
        User::WaitForRequest(status);
        }
    }

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

    DESCRIPTION

    This module contains implementation of CTestScripterController class member
    functions.

-------------------------------------------------------------------------------
*/
#define LOGGER iEngine->Logger()

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

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

    Class: CTestScripterController

    Method: CTestScripterController

    Description: Default constructor

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

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestScripterController::CTestScripterController( CTestEngine* aEngine ) :
    CTestModuleController( aEngine )
    {
    // None

    }

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

    Class: CTestScripterController

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: const TName& aName: in: Test module name
                TBool aAfterReboot: in: Reboot indication

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::ConstructL( const TName& aName,
                                          TBool aAfterReboot )
    {
    __TRACE( KInit, ( 
        _L( "NOTE: Test module is TestScripter and each test case(config) file(s) will have own server(s)" ) ) );

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

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

    iName = name.AllocL();

    iAfterReboot = aAfterReboot;

    }

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

    Class: CTestScripterController

    Method: InitL

    Description: Initialize test module.

    Parameters: TFileName& aIniFile: in: Initialization file of Test Module
                const TDesC& aConfigFile: in: Test case(config) file name(Used 
                in TestScripter case).

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::InitL( TFileName& aIniFile, 
                                     const TDesC& /*aConfigFile*/ )
    {
    // Take initialization file of Test Module
    iInifile = aIniFile;

    // Just empty, don't create TestServer operations. TestServer
    // creation will be do in AddTestCaseFile()-method.

    }

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

    Class: CTestScripterController

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: CTestEngine object
                const TName& aName: in: Test module name
                TBool aAfterReboot: in: Reboot indication

    Return Values: CTestScripterController* : pointer to created object

    Errors/Exceptions: Leaves if called ConstructL method leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestScripterController* CTestScripterController::NewL( CTestEngine* aEngine,
                                                        const TName& aName,
                                                        TBool aAfterReboot )
    {
    CTestScripterController* self =
        new ( ELeave ) CTestScripterController( aEngine );
    CleanupStack::PushL( self );
    self->ConstructL( aName, aAfterReboot );
    CleanupStack::Pop( self );
    return self;

    }

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

    Class: CTestScripterController

    Method: ~CTestScripterController

    Description: Destructor

    Deallocate all allocated resources. Delete CTestScripterController's
    CTestModuleController(s). After this is deleted base class also, see:
    CTestModuleController::~CTestModuleController(). 

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestScripterController::~CTestScripterController()
    {
    // Delete CTestScripterController(s).
    iTestScripter.ResetAndDestroy();
    iTestScripter.Close();

    // After this is deleted base class also, see:
    // CTestModuleController::~CTestModuleController(). 

    }

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

    Class: CTestScripterController

    Method: AddConfigFileL

    Description: Add config file.
                 - Creates CTestModuleController(Gives test case file name)
                 - Initializes CTestModuleController( creates a server session)
                 - Adds config file

    Parameters: TFileName& aConfigFile: in: Config file for TestScripter

    Return Values: None

    Errors/Exceptions: Leaves if AppendL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::AddConfigFileL( TFileName& aConfigFile )
    {
    // Check that this config file does not already exists
    for(  TInt a = 0; a < iTestScripter.Count(); a++ )
        {
        for ( TInt i = 0; i < iTestScripter[a]->iConfigFiles.Count(); i++ )
            {
            // HBufC to TPtrC
            TPtrC name( iTestScripter[a]->iConfigFiles[i]->Des() );
            if ( KErrNone == aConfigFile.CompareF( name ) )
                {
                LeaveWithNotifyL( KErrAlreadyExists,  
                    _L( "Adding config file failed: Config file already exists" ) );
                }
            }
        }

    __TRACE( KInit, ( 
        _L( "CTestScripterController::AddConfigFileL aConfigFile=[%S]" ) ,
        &aConfigFile ) );

    HBufC* testScripterAndTestCaseFile = NULL; // InitL() takes TFileName
    testScripterAndTestCaseFile = CreateTestScripterNameL( 
                                            aConfigFile,
                                            testScripterAndTestCaseFile );
    // Add to cleanup stack here, because CreateTestScripterNameL needs to be
    // trapped in other methods.
    CleanupStack::PushL( testScripterAndTestCaseFile );

    //Create server and active object(This uses CTestModuleController::InitL())
    CTestModuleController* module = CTestModuleController::NewL( 
                                        iEngine,
                                        testScripterAndTestCaseFile->Des(),
                                        iAfterReboot, EFalse, this );
    CleanupStack::PopAndDestroy( testScripterAndTestCaseFile );
    CleanupStack::PushL( module );

    User::LeaveIfError( iTestScripter.Append( module ) );

    // Now is used TestScripter so give test case file also(used
    // in caps modifier cases). 
    TRAPD ( err, module->InitL( iInifile, aConfigFile ) );
    if( err != KErrNone )
        {
        __TRACE( KInit, ( _L( "InitL fails with error: %d" ), err ) );
        User::Leave( err );
        }

    module->AddConfigFileL( aConfigFile );

    CleanupStack::Pop( module );

    }

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

    Class: CTestScripterController

    Method: RemoveConfigFileL

    Description: Remove config file

    Parameters: TFileName& aConfigFile: in: Config file name

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::RemoveConfigFileL( TFileName& aConfigFile )
    {
     __TRACE( KInit, ( _L( "CTestScripterController::RemoveConfigFileL" ) ) );

    HBufC* testScripterAndTestCaseFile = NULL;
    testScripterAndTestCaseFile = CreateTestScripterNameL( aConfigFile,
                                         testScripterAndTestCaseFile );
    // Add to cleanup stack here, because CreateTestScripterNameL needs to be
    // trapped in other methods.
    CleanupStack::PushL( testScripterAndTestCaseFile );

    // Get correct iTestScripter
    TInt index( -1 );
    for( TInt a = 0; a < iTestScripter.Count(); a++ )
        {
        if( ( iTestScripter[a]->iName->CompareF( 
                        testScripterAndTestCaseFile->Des() ) == KErrNone ) )
            {
            index = a;
            break;
            }
        }

    CleanupStack::PopAndDestroy( testScripterAndTestCaseFile );

    if( index == -1 )
        {
        LeaveWithNotifyL( KErrNotFound, 
            _L( "Removing config file failed: Config file not found" ) );
        }

    __TRACE( KInit, ( 
        _L( "CTestScripterController[%S]::RemoveConfigFileL aConfigFile=[%S]"),
        iTestScripter[index]->iName, &aConfigFile ) );

    // Find config file
    for ( TInt i = 0; i < iTestScripter[index]->iConfigFiles.Count(); i++ )
        {
        // HBufC to TPtrC
        TPtrC name( iTestScripter[index]->iConfigFiles[i]->Des() );
        if ( KErrNone == aConfigFile.CompareF( name ) )
            {
            HBufC* configFile = iTestScripter[index]->iConfigFiles[i];
            iTestScripter[index]->iConfigFiles.Remove(i);
            delete configFile;
            // Cancel enumerate and free test cases
            Cancel();
            FreeTestCases();
            // Testcasefile(config) is found, so we can return
            return;
            }
        }

    LeaveWithNotifyL( KErrNotFound, 
        _L( "Removing config file failed: Config file not found" ) );

    }

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

    Class: CTestScripterController

    Method: StartEnumerateL

    Description: Start test case enumeration

    Parameters: None

    Return Values: None

    Errors/Exceptions: LeaveWithNotifyL if no test case added. 

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::StartEnumerateL()
    {
    if( iTestScripter.Count() <= 0 )
        {
        RDebug::Print( 
            _L( "There is no test case file for TestScripter registered yet. Enumeraton aborted." ) );
        LeaveWithNotifyL( KErrNotFound,
            _L( "There is no test case file for TestScripter registered yet. Enumeraton aborted." ) );
        return;
        }

    for( TInt a = 0; a < iTestScripter.Count(); a++ )
        {
        __TRACE( KVerbose, ( 
                _L( "CTestScripterController[%S]::StartEnumerateL" ),
                iTestScripter[a]->iName ) );
        iTestScripter[a]->iTestCaseCount = 0;
        iTestScripter[a]->iEnumerateCount = 0;
        iTestScripter[a]->iFailedEnumerateCount = 0;
        iTestScripter[a]->iFailedEnumerateConfig.Reset();
        iTestScripter[a]->iEnumerateComplete = EFalse;

        iTestScripter[a]->iState = ETestModuleEnumerateCases;
        
        if ( iTestScripter[a]->iConfigFiles.Count() > 0 )
            {
            // HBufC to TPtrC
            iTestScripter[a]->iEnumConfigFile.Set( 
                                iTestScripter[a]->iConfigFiles[0]->Des() );
            }

        __TRACE( KInit, ( 
            _L( "Getting testcases from module [%S], test case file[%S]" ),
            iTestScripter[a]->iName, &iTestScripter[a]->iEnumConfigFile ) );
        
        iTestScripter[a]->SetActive();
        iTestScripter[a]->iModule.EnumerateTestCases( 
                                    iTestScripter[a]->iEnumConfigFile,
                                    iTestScripter[a]->iEnumResultPackage,
                                    iTestScripter[a]->iStatus );
        } // End of for-loop

    }

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

    Class: CTestScripterController

    Method: GetCurrentIndex

    Description: Get current CTestScripterController.

    Parameters: CTestModuleController* aTestModuleController: in:
                Pointer current to CTestModuleController

    Return Values: KErrNotFound returned if CTestModuleController not found
                   else current index returned.

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestScripterController::GetCurrentIndex( CTestModuleController*
                                                    aTestModuleController )
    {
    // Get correct iTestScripter
    return iTestScripter.Find( aTestModuleController );

    }

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

    Class: CTestScripterController

    Method: RunL

    Description: RunL handles completed requests.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::RunL()
    {
    // Should never come here because one TestScripter have one test case
    // file per server session.
    // CTestScripterController's base class is an active object but this class
    // not used as an active object. So there not used RunL => Panic.

    User::Panic( _L( "CTestScripterController::RunL()" ), KErrCorrupt );

    }

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

    Class: CTestScripterController

    Method: RunLEmulator

    Description: RunLEmulator handles completed requests(Emulates RunL()).
                 This is called from CTestModuleController::RunL.

    Parameters: CTestModuleController* aTestModuleController: in: pointer to
                CTestModuleController.

    Return Values: None

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

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::RunLEmulator( CTestModuleController*
                                                    aTestModuleController )
    {
    iTestScripterIndicator++;
    TInt index = GetCurrentIndex( aTestModuleController );
    if( index < KErrNone )
        {
        User::Leave( KErrNotFound );
        }

    __TRACE( KVerbose, ( 
        _L( "CTestScripterController[%S]::RunLEmulator [iStatus = %d]"),
        iTestScripter[index]->iName, iTestScripter[index]->iStatus.Int() ) );

    // Note:
    // If test case not found there may be existing cases from previous
    // enumerations, so those cases are valid. e.g. case: "add test case file",
    // "add test case file that not exist" and "get test cases".

    TInt ret( KErrNone );

    // Check that request was successful
    if( iTestScripter[index]->iStatus.Int() == KErrNone )
        {
        // Get enumerated test cases and append them to array
        CFixedFlatArray<TTestCaseInfo>* testCases = 
                        CFixedFlatArray<TTestCaseInfo>::NewL( 
                        iTestScripter[index]->iEnumResultPackage() );
        CleanupStack::PushL( testCases );
        ret = iTestScripter[index]->iModule.GetTestCases( *testCases );
        __TRACE( KInit, ( 
                _L( "RunL()'s GetTestCases method returns: %d" ), ret ) );

        iTestScripter[index]->iTestCaseCount += testCases->Count();

        if ( testCases->Count() == 0 )
            {

            if (iTestScripter[index]->iConfigFiles.Count() > 0)
                {
                __TRACE( KInit, ( 
                    CStifLogger::EBold, 
                    _L( "Module [%S], test case file[%S] returned 0 cases" ),
                    iTestScripter[index]->iName,
                    iTestScripter[index]->iConfigFiles[iTestScripter[index]->iEnumerateCount] ) );
                }
            else
                {
                __TRACE( KInit, ( CStifLogger::EBold,
                    _L("Module [%S] without test case file, returned 0 cases"),
                    iTestScripter[index]->iName ) );
                }
            iTestScripter[index]->iEngine->ErrorPrint( 1,
                _L("Someone returned 0 test cases. Check testengine log"));
            iTestScripter[index]->iAtsLogger->CommentL( 
                _L("Test module returned 0 test cases") );   
            }

        // Store test cases for later use
        User::LeaveIfError( iTestScripter[index]->iTestCaseArray.Append( 
                                                                testCases ) );
        CleanupStack::Pop( testCases );
        
        }
    else
        {
        // Calculate failed enumeration count
        iTestScripter[index]->iFailedEnumerateCount++;
        // Add failed config(test case) file to array for later removing
        if( iTestScripter[index]->iConfigFiles.Count() != NULL )
            {
            __TRACE( KError, (
                CStifLogger::ERed, 
                _L( "Test case[%S] enumeration fails with error: %d" ),
                iTestScripter[index]->iConfigFiles[iTestScripter[index]->iEnumerateCount],
                iTestScripter[index]->iStatus.Int() ) );
            // Append
            iTestScripter[index]->iFailedEnumerateConfig.Append(
                iTestScripter[index]->iConfigFiles[iTestScripter[index]->iEnumerateCount] );
            }
        }

    TInt count = iTestScripter.Count();

    // All TestScripter enumerations is finished for cleaning if necessarily
    // and complete request up to engine.
    if( count == iTestScripterIndicator )
        {
        TInt testCaseCount( 0 );
        for( TInt a = 0; a < count; a++  )
            {
            // Remove faulty config (test case) file(s) and 
            // iEnumerateCount not increased.
            if( iTestScripter[a]->iTestCaseCount == 0 )
                {
                // Check that test case file is not allready removed.
                if( iTestScripter[a]->iConfigFiles.Count() != 0 )
                    {
                    iTestScripter[a]->iConfigFiles.Remove( 0 );
                    }
                }
            else
                {
                iTestScripter[a]->iEnumerateCount++;
                testCaseCount += iTestScripter[a]->iTestCaseCount;
                }

            // All test cases enumerated
            iTestScripter[a]->iState = ETestModuleEnumerateCasesCompleted;
            iTestScripter[a]->iEnumerateComplete = ETrue;
            }

        iTestScripterIndicator = 0; // Initialization back to 0, enumerations
                                    // are done at this run.
        iEngine->EnumerationCompleted( testCaseCount );
        }

    }

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

    Class: CTestScripterController

    Method: TestCasesL

    Description: Return Test Cases

    Parameters: None

    Return Values: CFixedFlatArray<TTestInfo>*: Pointer to created array

    Errors/Exceptions: Leaves if NewL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
CFixedFlatArray<TTestInfo>* CTestScripterController::TestCasesL()
    {
    TInt testCaseCount( 0 );
    for( TInt i = 0; i < iTestScripter.Count(); i++  )
        {
        testCaseCount += iTestScripter[i]->iTestCaseCount;
        }

    CFixedFlatArray<TTestInfo>* testCases = 
        CFixedFlatArray<TTestInfo>::NewL( testCaseCount );

    CleanupStack::PushL( testCases );

    // Loop through all test cases from all config files
    TInt totalCount = 0;
    // HBufC to TPtrC
    for( TInt a = 0; a < iTestScripter.Count(); a++ )
        {
        TPtrC name( iTestScripter[a]->iName->Des() );
        for ( TInt i = 0; i < iTestScripter[a]->iEnumerateCount; i++ )
            {
            TTestInfo tmpInfo;
            tmpInfo.iModuleName = name;
            if ( iTestScripter[a]->iConfigFiles.Count() > 0 )
                {
                tmpInfo.iConfig = *iTestScripter[a]->iConfigFiles[i];
                }

            // Get test cases from iTestCaseArray at [i]
            if( (iTestScripter[a]->iTestCaseArray)[i] )
                {
                CFixedFlatArray<TTestCaseInfo>* tempTestCases = 
                                    (iTestScripter[a]->iTestCaseArray)[i];
                for ( TInt j = 0; j < tempTestCases->Count(); j++ )
                    {
                    tmpInfo.iTestCaseInfo = (*tempTestCases)[j];
                    // Set TestCaseInfo to testCases array
                    testCases->Set( totalCount, tmpInfo );
                    totalCount++;
                    }
                }
            }
        }

    CleanupStack::Pop( testCases );

    return testCases;

    }

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

    Class: CTestScripterController

    Method: FreeTestCases

    Description: Free memory used for test cases

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::FreeTestCases()
    {
    for( TInt a = 0; a < iTestScripter.Count(); a++ )
        {
        // Reset and destroy test cases
        iTestScripter[a]->iTestCaseArray.ResetAndDestroy();
        iTestScripter[a]->iTestCaseArray.Close();

        iTestScripter[a]->iTestCaseCount = 0;
        iTestScripter[a]->iEnumerateComplete = EFalse;
        }

    }

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

    Class: CTestScripterController

    Method: DoCancel

    Description: Cancel active request

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::DoCancel()
    {
    // Should never come here because one TestScripter have one test case
    // file per server session.
    // CTestScripterController's base class is an active object but this class
    // not used as an active object. So there not used DoCancel => Panic.

    User::Panic( _L( "CTestScripterController::DoCancel()" ), KErrCorrupt );

    }

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

    Class: CTestScripterController

    Method: DoCancelEmulator

    Description: Cancel active request(Emulates DoCancel)
                 This is called from CTestModuleController::DoCancel.

    Parameters: CTestModuleController* aTestModuleController: in: pointer to
                CTestModuleController.

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestScripterController::DoCancelEmulator(
                                CTestModuleController* aTestModuleController )
    {
    TInt index = GetCurrentIndex( aTestModuleController );
    if( index < KErrNone )
        {
        User::Leave( KErrNotFound );
        }

    __TRACE( KVerbose, ( 
        _L( "CTestScripterController[%S]::RunDoCancelEmulator" ),
        iTestScripter[index]->iName ) );

    switch ( iTestScripter[index]->iState )
        {
        case ETestModuleEnumerateCases:
            iTestScripter[index]->iModule.CancelAsyncRequest(
                                            ETestModuleEnumerateTestCases );
            iTestScripter[index]->iEnumerateComplete = ETrue;
            // Enumeration canceled, complete with KErrCancel
            iTestScripter[index]->iEngine->EnumerationCompleted(
                                                            0, KErrCancel );

            // Free allocated test cases because EnumerateTestCases was
            // canceled
            FreeTestCases();
            break;
        case ETestModuleIdle:
        case ETestModuleEnumerateCasesCompleted:
        default:
            // DoCancel called in wrong state => Panic
            _LIT( KTestModuleController, "CTestModuleController" );
            User::Panic( KTestModuleController, EDoCancelDisorder );
            break;
        }

    iTestScripter[index]->iAtsLogger->ErrorL( 
                        _L("Test case enumeration cancelled") );
    iTestScripter[index]->iState = ETestModuleIdle;

    }

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

    Class: CTestScripterController

    Method: RunError

    Description: Handle errors.

    Parameters: TInt aError: in: Symbian OS error: Error code

    Return Values: TInt KErrNone: Always returned KErrNone

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestScripterController::RunError( TInt /*aError*/ )
    {
    // Should never come here because one TestScripter have one test case
    // file per server session.
    // CTestScripterController's base class is an active object but this class
    // not used as an active object. So there not used RunError => Panic.

    User::Panic( _L( "CTestScripterController::RunError()" ), KErrCorrupt );
    return KErrNone;

    }

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

    Class: CTestScripterController

    Method: RunErrorEmulator

    Description: Handle errors(Emulates RunError).
                 This is called from CTestModuleController::RunError.

    Parameters: TInt aError: in: Symbian OS error: Error code.
                CTestModuleController* aTestModuleController: in: pointer to
                CTestModuleController.

    Return Values: TInt KErrNone: Always returned KErrNone

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestScripterController::RunErrorEmulator( TInt aError,
                                CTestModuleController* aTestModuleController )
    {
    TInt index = GetCurrentIndex( aTestModuleController );
    if( index < KErrNone )
        {
        User::Leave( KErrNotFound );
        }
    
    __TRACE( KError, ( CStifLogger::ERed,
        _L( "CTestScripterController[%S]::RunErrorEmulator aError=[%d]" ),
        iTestScripter[index]->iName, aError ) );
    if( aError == KErrNoMemory )
        {
        __TRACE( KError, ( CStifLogger::ERed, 
            _L( "No memory available. Test case file's size might be too big." ) ) );
        }

    iTestScripter[index]->iEnumerateComplete = ETrue;

    iTestScripter[index]->iAtsLogger->ErrorL( 
                            _L("Test module did not return any test cases") );
    
    _LIT( KErrorText, " did not return any test cases [error: ");
    if( KErrorText().Length() +
            iTestScripter[index]->iName->Length() +
            1 < KMaxName )
        {
        // Enumeration failed, print warning and complete with KErrNone
        TName error( iTestScripter[index]->iName->Des() );
        error.Append( KErrorText );  
        error.AppendNum( aError );  
        error.Append( _L("]") );  
        iEngine->ErrorPrint ( 0, error );
    
        iTestScripter[index]->iEngine->EnumerationCompleted( 0, KErrNone );
        }
    else 
        {
        // Cannot only print warning, complete with error
        iTestScripter[index]->iEngine->EnumerationCompleted( 0, aError );
        }

    // Free allocated test cases because EnumerateTestCases failed
    FreeTestCases();
    iTestScripter[index]->iEnumerateComplete = ETrue;

    return KErrNone;

    }

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

    Class: CTestScripterController

    Method: EnumerationComplete

    Description: Is enumeration of test cases complete.

    Parameters: None
    
    Return Values: TBool ETrue: Enumeration of test cases is complete
                         EFalse: Enumeration is not complete

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TBool CTestScripterController::EnumerationComplete()
    {
    for( TInt a = 0; a < iTestScripter.Count(); a++ )
        {
        if( !iTestScripter[a]->iEnumerateComplete )
            {
            return EFalse;
            }
        }
    return ETrue;

    }

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

    Class: CTestScripterController

    Method: Server

    Description: Return handle to Test Server

    Parameters: TTestInfo& aTestInfo: in: Test info for this test case

    Return Values: RTestServer& : Reference to RTestServer

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
RTestServer& CTestScripterController::Server( TTestInfo& aTestInfo )
    {
    HBufC* testScripterAndTestCaseFile = NULL;
    TRAPD( ret, testScripterAndTestCaseFile = CreateTestScripterNameL( 
                                            aTestInfo.iConfig,
                                            testScripterAndTestCaseFile ) );
    // Add to cleanup stack here, because CreateTestScripterNameL needs to be
    // trapped in other methods.
    CleanupStack::PushL( testScripterAndTestCaseFile );
    if( ret != KErrNone )
        {
        User::Panic( 
            _L( "CTestScripterController::Server(): CreateTestScripterNameL" ),
            ret );
        }

    // Get correct handle
    TInt index( KErrNotFound );
    for( TInt a = 0; a < iTestScripter.Count(); a++ )
        {
        if( testScripterAndTestCaseFile->Des() == 
                                            iTestScripter[a]->iName->Des() )
            {
            index = a;
            break;
            }
        }

    CleanupStack::PopAndDestroy( testScripterAndTestCaseFile );

    if( index == KErrNotFound )
        {
        User::Panic(
            _L( "CTestScripterController::Server(): Index not found" ),
            KErrNotFound );
        }

    // Return handle
    return iTestScripter[index]->iServer;
    }

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

    Class: CTestScripterController

    Method: GetFreeOrCreateModuleControllerL

    Description: Return pointer to test module controller.
                 Find controller which does not run test case
                 and if this is not possible then create new one.

    Parameters: TTestInfo& aTestInfo: in: Test info for this test case
                TBool aUITestingSupport: in: Is UI testing mode enabled

    Return Values: CTestModuleController* : pointer to controller

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestModuleController* CTestScripterController::GetFreeOrCreateModuleControllerL(TTestInfo& aTestInfo, TBool aUITestingSupport)
    {
    HBufC* testScripterAndTestCaseFile = NULL;
    TRAPD(ret, testScripterAndTestCaseFile = CreateTestScripterNameL(aTestInfo.iConfig, testScripterAndTestCaseFile));

    // Add to cleanup stack here, because CreateTestScripterNameL needs to be trapped in other methods.
    CleanupStack::PushL(testScripterAndTestCaseFile);
    if(ret != KErrNone)
        {
        User::Panic(_L("CTestScripterController::GetFreeOrCreateModuleControllerL(): CreateTestScripterNameL"), ret);
        }

    CTestModuleController* resultController = NULL;
    CTestModuleController* parentController = NULL;
    TInt j;
    
    __TRACE(KInit, (_L("Find free real module controller (or create new one)")));

    // Get handle to correct "parent" module controller
    __TRACE(KInit, (_L("Searching for parent module controller named [%S]"), testScripterAndTestCaseFile));
    for(TInt a = 0; a < iTestScripter.Count(); a++)
        {
        //Check if module name matches to given name
        if(iTestScripter[a]->iName->Des() == testScripterAndTestCaseFile->Des())
            {
            parentController = iTestScripter[a]; 
            __TRACE(KInit, (_L("Parent module controller [%S] has been found. Checking its %d children"), parentController->iName, parentController->iChildrenControllers.Count()));
            //Now check all its children and find free one
            //In UI testing mode always create new module controller
            if(!aUITestingSupport)
                {
                for(j = 0; j < parentController->iChildrenControllers.Count(); j++)
                    {
                    if(parentController->iChildrenControllers[j]->iTestCaseCounter == 0)
                        {
                        resultController = parentController->iChildrenControllers[j];
                        __TRACE(KInit, (_L("Free real module controller found [%S]"), resultController->iName));
                        break;
                        }
                    else
                        {
                        __TRACE(KInit, (_L("Module controller found [%S] but is not free (it runs %d test cases)"), parentController->iChildrenControllers[j]->iName, parentController->iChildrenControllers[j]->iTestCaseCounter));
                        }
                    }
                }
            else
                {
                __TRACE(KInit, (_L("In UITestingSupport mode new module controller will be always created")));
                }
            }
        }

    //Append underscore to name
    TPtr ptr = testScripterAndTestCaseFile->Des();
    ptr.Append(_L("@"));

    //Create new module controller if free one has not been found
    if(!resultController)
        {
        TBuf<10> ind;
        ind.Format(_L("%d"), iEngine->GetIndexForNewTestModuleController());
        TPtr ptr = testScripterAndTestCaseFile->Des();
        ptr.Append(ind);
        __TRACE(KInit, (_L("Free real module controller not found. Creating new one [%S]."), testScripterAndTestCaseFile));
            
        //Create server and active object (This uses CTestModuleController::InitL())
        CTestModuleController* module = CTestModuleController::NewL( 
                                            iEngine,
                                            testScripterAndTestCaseFile->Des(),
                                            iAfterReboot, EFalse, this);
        CleanupStack::PushL(module);
        parentController->iChildrenControllers.AppendL(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));
            }

        // Now is used TestScripter so give test case file also(used
        // in caps modifier cases). 
        TRAPD(err, module->InitL(iInifile, aTestInfo.iConfig));
        if(err != KErrNone)
            {
            __TRACE(KVerbose, (_L("InitL fails with error: %d" ), err));
            User::Leave(err);
            }

        module->AddConfigFileL(aTestInfo.iConfig);

        __TRACE(KInit, (_L("New module controller created [%S]."), testScripterAndTestCaseFile));

        //Enumerate test cases
        module->EnumerateSynchronously();

        CleanupStack::Pop(module);
        resultController = module;
        }

    CleanupStack::PopAndDestroy(testScripterAndTestCaseFile);

    // Return handle
    return resultController;
    }

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

    Class: CTestScripterController

    Method: ModuleName

    Description: Return the name of Test Scripter

    Parameters: const TDesC& aModuleName: in: Module name

    Return Values: const TDesC : Name of Test Scripter

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
const TDesC& CTestScripterController::ModuleName( const TDesC& aModuleName )
    {
    // If test case file not added yet.
    if( iTestScripter.Count() == 0 || aModuleName == KTestScripterName )
        {
        return *iName;
        }

    // Test case(s) is(are) added. Scan the name from corrent TestScripter
    // session
    for( TInt a = 0; a < iTestScripter.Count(); a++ )
        {
        if( aModuleName == iTestScripter[a]->iName->Des() )
            {
            return *iTestScripter[a]->iName;
            }
        }

    return KNullDesC;

    }

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

    Class: CTestScripterController

    Method: CreateTestScripterNameL

    Description: Create name according to TestScripter and Test case file.

    Parameters: TFileName& aTestCaseFile: in: Test case file with path and name
                TFileName& aCreatedName: inout: Created name

    Return Values: None

    Errors/Exceptions: Leaves is test case file is too long

    Status: Approved

-------------------------------------------------------------------------------
*/
HBufC* CTestScripterController::CreateTestScripterNameL( 
                                                    TFileName& aTestCaseFile,
                                                    HBufC* aCreatedName )
    {
    TParse parse;
    parse.Set( aTestCaseFile, NULL, NULL );

    TInt length( 0 );
    length = parse.Name().Length();
    length += ( KTestScripterNameLength + 1 );
    length += 10; //this will be used to add unique identifier (when run test case in separate process is on)

    // aCreatedName to CleanupStack
    aCreatedName = HBufC::NewLC( length );
    TPtr ptr = aCreatedName->Des();

    // Maximum length of TestScripter's name(Max limitation from
    // CTestModuleController creation)
    TInt maximumLength = KMaxName - ( KTestScripterNameLength + 1 );

    // Start create name. Format is testscripter_testcasefile
    ptr.Copy( KTestScripterName );
    ptr.Append( _L( "_" ) );
    if( parse.Name().Length() < maximumLength )
        {
        ptr.Append( parse.Name() );
        ptr.LowerCase();
        }
    else
        {
        __TRACE( KInit, ( CStifLogger::ERed,
            _L( "TestScripter test case file(config)'s name is too long. Current length[%d], allowed max length[%d]. Cannot continue" ),
            parse.Name().Length(), maximumLength ) );
        User::Leave( KErrArgument );
        }

    // Pop here because this method can be trapped and trap panics with
    // E32USER-CBase if cleap up stack is not empty.
    CleanupStack::Pop( aCreatedName );

    return aCreatedName;

    }

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

    Class: CTestScripterController

    Method: DeleteModuleController

    Description: Finds specified module controller and deletes it.

    Parameters: CTestModuleController* aRealModuleController: module controller
                   to be deleted.
    
    Return Values: None
    
    Errors/Exceptions: None

    Status: 

-------------------------------------------------------------------------------
*/    
void CTestScripterController::DeleteModuleController(CTestModuleController* aRealModuleController)
    {
    __TRACE(KInit, (_L("Attempting to delete real module controller [%S]"), aRealModuleController->iName));

    TInt i, j, k;
    TInt children;
    TInt subcontrollers = iTestScripter.Count();
    
    for(k = 0; k < subcontrollers; k++)
        {
        children = iTestScripter[k]->iChildrenControllers.Count();
        __TRACE(KInit, (_L("...checking controller [%S] which has %d children"), iTestScripter[k]->iName, children));

        for(i = 0; i < children; i++)
            {
            if(iTestScripter[k]->iChildrenControllers[i] == aRealModuleController)
                {
                __TRACE(KInit, (_L("Real module controller found... deleting")));
                delete iTestScripter[k]->iChildrenControllers[i];
                iTestScripter[k]->iChildrenControllers.Remove(i);
    
                __TRACE(KInit, (_L("Child removed from [%S] controller. Currently it has %d children:"), iTestScripter[k]->iName, iTestScripter[k]->iChildrenControllers.Count()));
                for(j = 0; j < iTestScripter[k]->iChildrenControllers.Count(); j++)
                    {
                    __TRACE(KInit, (_L("    %d. [%S]"), j + 1, iTestScripter[k]->iChildrenControllers[j]->iName));
                    }
    
                return;
                }
            }
        }
    __TRACE(KInit, (_L("Real module controller NOT found... NOT deleting")));
    }

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

    Class: CTestScripterController

    Method: RemoveModuleController

    Description: Finds specified module controller and removes it from children list.

    Parameters: CTestModuleController* aRealModuleController: module controller
                   to be removed.
    
    Return Values: None
    
    Errors/Exceptions: None

    Status: 

-------------------------------------------------------------------------------
*/    
void CTestScripterController::RemoveModuleController(CTestModuleController* aRealModuleController)
    {
    __TRACE(KInit, (_L("Attempting to remove real module controller [%x]"), aRealModuleController));

    TInt i, j, k;
    TInt children;
    TInt subcontrollers = iTestScripter.Count();
    
    for(k = 0; k < subcontrollers; k++)
        {
        children = iTestScripter[k]->iChildrenControllers.Count();
        __TRACE(KInit, (_L("...checking controller [%S] which has %d children"), iTestScripter[k]->iName, children));

        for(i = 0; i < children; i++)
            {
            if(iTestScripter[k]->iChildrenControllers[i] == aRealModuleController)
                {
                __TRACE(KInit, (_L("Real module controller found... removing")));
                iTestScripter[k]->iChildrenControllers.Remove(i);
    
                __TRACE(KInit, (_L("Child removed from [%S] controller. Currently it has %d children:"), iTestScripter[k]->iName, iTestScripter[k]->iChildrenControllers.Count()));
                for(j = 0; j < iTestScripter[k]->iChildrenControllers.Count(); j++)
                    {
                    __TRACE(KInit, (_L("    %d. [%S]"), j + 1, iTestScripter[k]->iChildrenControllers[j]->iName));
                    }
    
                return;
                }
            }
        }
    __TRACE(KInit, (_L("Real module controller NOT found... NOT removing")));
    }

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

    DESCRIPTION

    This module contains implementation of CErrorPrinter class member
    functions.

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

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

    Class: CErrorPrinter

    Method: NewL

    Description: Create a testcase runner.

    Parameters: CTestEngine* aMain: in: Pointer to console main

    Return Values: CErrorPrinter* : pointer to created object

    Errors/Exceptions: Leaves if memory allocation for object fails
                       Leaves if ConstructL leaves

    Status: Approved

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

    }

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

    Class: CErrorPrinter

    Method: ConstructL

    Description: Second level constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to Engine

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CErrorPrinter::ConstructL( CTestEngine* aEngine )
    {
    iEngine = aEngine;

    }

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

    Class: CErrorPrinter

    Method: CErrorPrinter

    Description: Constructor.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CErrorPrinter::CErrorPrinter( ) : CActive( EPriorityStandard ),
                                      iErrorPckg( iError )
    {

    }

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

    Class: CErrorPrinter

    Method: ~CErrorPrinter

    Description: Destructor.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CErrorPrinter::~CErrorPrinter( )
    {
    Cancel();

    }

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

    Class: CErrorPrinter

    Method: StartL

    Description: Starts a test case and sets the active object to active.

    Parameters: RTestModule& aServer: in: Reference to the server object

    Return Values: None

    Errors/Exceptions: TInt: Return KErrNone

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CErrorPrinter::StartL( RTestModule& aServer )
    {
    iServer = aServer;

    CActiveScheduler::Add ( this );

    SetActive();
    aServer.ErrorNotification ( iErrorPckg, iStatus );

    return KErrNone;

    }

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

    Class: CErrorPrinter

    Method: RunL

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CErrorPrinter::RunL()
    {

    if ( iStatus.Int() != KErrNone )
        {
        __TRACE( KVerbose, ( _L( "In CErrorPrinter::RunL [iStatus = %d]" ), iStatus.Int() ) );
        }
    else
       {
        // Forward error print to UI and set request again active.
        iEngine->ErrorPrint( iErrorPckg );
        SetActive();
        iServer.ErrorNotification ( iErrorPckg, iStatus );
       }
    }

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

    Class: CErrorPrinter

    Method: DoCancel

    Description: Cancels the asynchronous request

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CErrorPrinter::DoCancel()
    {
    iServer.CancelAsyncRequest ( ETestModuleErrorNotification );

    }

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

    Class: CErrorPrinter

    Method: RunError

    Description: Handles errors. RunL can't leave so just forward error
    and let framework handle error.

    Parameters: TInt aError: in: Error code

    Return Values: TInt: Error code

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CErrorPrinter::RunError( TInt aError )
    {
    return aError;

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

    Class: CServerStateHandler

    Method: NewL

    Description: Constructs a new CServerStateHandler object.

    Parameters: CTestEngine* aMain

    Return Values: CServerStateHandler*: New undertaker

    Errors/Exceptions: Leaves if memory allocation or ConstructL leaves.

    Status: Proposal

-------------------------------------------------------------------------------
*/
CServerStateHandler* CServerStateHandler::NewL( CTestEngine* aTestEngine, 
                                                CTestModuleController* aTestModuleController )
    {

    CServerStateHandler* self = 
                        new( ELeave ) CServerStateHandler( aTestEngine, aTestModuleController );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;

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

    Class: CServerStateHandler

    Method: ConstructL

    Description: Second level constructor.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CServerStateHandler::ConstructL()
    {

    }

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

    Class: CServerStateHandler

    Method: CServerStateHandler

    Description: Constructor

    Parameters: CTestEngine* aMain

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal
    
-------------------------------------------------------------------------------
*/
CServerStateHandler::CServerStateHandler( CTestEngine* aTestEngine, 
                                          CTestModuleController* aTestModuleController ) :
    CActive( CActive::EPriorityStandard ),
    iEngine( aTestEngine ),
    iTestModuleController( aTestModuleController )
    {
    
    }

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

    Class: CServerStateHandler

    Method: ~CServerStateHandler

    Description: Destructor. 
    Cancels active request.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal
    
-------------------------------------------------------------------------------
*/
CServerStateHandler::~CServerStateHandler()
    {
    
    Cancel();

    iServerThread.Close();
    
    }
/*
-------------------------------------------------------------------------------

    Class: CServerStateHandler

    Method: StartL

    Description: Starts to monitor server thread.

    Parameters: RTestServer& aServer

    Return Values: TInt: 

    Errors/Exceptions: 

    Status: Proposal
    
-------------------------------------------------------------------------------
*/
TInt CServerStateHandler::StartL( RTestServer& aServer )
    {
    
    __TRACE( KVerbose, ( _L( "CServerStateHandler::StartL" ) ) );
     
    TThreadId serverThreadId; 
     
    iStatus = KRequestPending;
  
    // Asks from server its thread ID value
    User::LeaveIfError( aServer.GetServerThreadId ( serverThreadId ) ); 
      
    // Opens handle to thread
    User::LeaveIfError( iServerThread.Open( serverThreadId ) );
    
    CActiveScheduler::Add( this );
        
    // Requests notification when this thread dies, normally or otherwise   
    iServerThread.Logon( iStatus ); // Miten RThread hanska ko serveriin..
   
    SetActive();

    return KErrNone;

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

    Class: CServerStateHandler

    Method: RunL

    Description: Handles thread death.
  
    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CServerStateHandler::RunL()
    {
    
    // something went badly wrong!
    __TRACE( KInit, ( CStifLogger::ERed, 
        _L( "Test case execution fails. Possible reason: KErrServerTerminated" ) ) );
 
    RDebug::Print( _L("Test case execution fails. Possible reason: KErrServerTerminated") );     
             
    // Note: 
    // More Info about STIF panic with KErrServerTerminated 
    // will be informed to the user via testengine log and testreport    
    // in CTestCaseController::RunL() method
   
    // TestModuleCrash is called for doing all needed recovering operations for enabling STIF 
    // to continue test case execution
    iEngine->TestModuleCrash( iTestModuleController );
      
    }
/*
-------------------------------------------------------------------------------

    Class: CServerStateHandler

    Method: DoCancel

    Description: Stops listening TestServer status.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal
    
-------------------------------------------------------------------------------
*/
void CServerStateHandler::DoCancel()
    {

    __TRACE( KVerbose, ( _L( "CServerStateHandler::DoCancel" ) ) );

    // Cancels an outstanding request for notification of the death of this thread.
    iServerThread.LogonCancel( iStatus );
    
    }
/*
-------------------------------------------------------------------------------

    Class: CServerStateHandler

    Method: RunError

    Description: Handle errors. RunL function does not leave, so one should
    never come here. 

    Print trace and let framework handle error( i.e to do Panic )

    Parameters: TInt aError: in: Error code

    Return Values:  TInt: Error code

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
TInt CServerStateHandler::RunError( TInt aError )
    {
    __TRACE( KError,( _L( "CServerStateHandler::RunError" ) ) );
    return aError;

    }

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

    Class: -

    Method: GenerateModuleName

    Description: Check is module TestScripter. Does parsing and returns new
                 module name and error codes(Needed operations when creating
                 server sessions to TestScripter). 

    Parameters: const TFileName& aModuleName: in: Module name for checking.
                TFileName& aNewModuleName: inout: Parsed module name.

    Return Values: KErrNone if TestScripter releated module.
                   KErrNotFound if not TestScripter releated module.

    Errors/Exceptions: None

    Status: Proposal

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

TInt GenerateModuleName(const TDesC& aModuleName,
                        TDes& aNewModuleName)
    {
    // Check that length is greated than KTestScripterNameLength
    if( aModuleName.Length() < KTestScripterNameLength )
        {
        return KErrNotFound;
        }
    // Check is TestScripter
    TPtrC check( aModuleName.Mid( 0, KTestScripterNameLength ) );
    TInt ret = check.CompareF( KTestScripterName );
    if( ret == KErrNone )
        {
        aNewModuleName.Copy( aModuleName.Mid( 0, KTestScripterNameLength ) );
        aNewModuleName.LowerCase();
        }
    else
        {
        return KErrNotFound;
        }

    return KErrNone;

    }

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

// None

//  End of File
