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


// INCLUDE FILES
#include <e32svr.h>
#include <e32uid.h>
#include <StifLogger.h>
#include "StifTFwIfProt.h"
#include "TestCaseController.h"
#include "TestModuleController.h"
#include "TestReport.h"
#include "Logging.h"
#include "StifHWReset.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: CTestCaseController

    Method: CTestCaseController

    Description: Default constructor

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

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                RTestExecution aTestExecution: in: Handle to RTestExecution
                CAtsLogger& aAtsLogger: in: Reference to CAtsLogger
                RTestExecution aTestExecution: in: Handle to RTestExecution
                const TTestInfo& aTestInfo: in: Test Info

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestCaseController::CTestCaseController( CTestEngine* aEngine,
                                          CTestReport* aTestReport,
                                          CAtsLogger& aAtsLogger,
                                          RTestExecution aTestExecution,
                                          const TTestInfo& aTestInfo ) :
    CActive( CActive::EPriorityStandard ),
    iEngine( aEngine ),
    iTestReport( aTestReport ),
    iTestExecution( aTestExecution ),
    iTestInfo( aTestInfo ),
    iState( ETestCaseIdle ),
    iResultPckg( iResult ),
    iAtsLogger( aAtsLogger )
    {
    CActiveScheduler::Add( this );

    }

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

    Class: CTestCaseController

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestCaseController::ConstructL()
    {
    __TRACE( KVerbose, ( _L( "CTestCaseController::ConstructL, [%S]" ), &iTestInfo.iTestCaseInfo.iTitle ) );

    // Logger settings
    TLoggerSettings loggerSettings;
    loggerSettings.iCreateLogDirectories = EFalse;
    loggerSettings.iOverwrite = ETrue;
    loggerSettings.iTimeStamp = EFalse;
    loggerSettings.iLineBreak = EFalse;
    loggerSettings.iEventRanking = EFalse;
    loggerSettings.iThreadId = EFalse;
    loggerSettings.iHardwareFormat = CStifLogger::ETxt;
    loggerSettings.iHardwareOutput = CStifLogger::ERDebug;
    loggerSettings.iEmulatorFormat = CStifLogger::ETxt;
    loggerSettings.iEmulatorOutput = CStifLogger::ERDebug;
    loggerSettings.iUnicode = EFalse;
    loggerSettings.iAddTestCaseTitle = EFalse;

    iRDebugLogger = CStifLogger::NewL( _L( "" ), _L( "" ), loggerSettings );

    // If timeout is specified, then create timeout handler.
    if ( iTestInfo.iTestCaseInfo.iTimeout > TTimeIntervalMicroSeconds(0) )
        {
        iTimeout = CTestCaseTimeout::NewL ( this,
                                            iTestInfo.iTestCaseInfo.iTimeout );
        }

    }

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

    Class: CTestCaseController

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                CTestReport* aTestReport: in: Pointer to CTestReport
                CAtsLogger& aAtsLogger: in: Reference to CAtsLogger
                RTestExecution aTestExecution: in: Handle to RTestExecution
                const TTestInfo& aTestInfo: in: Test Info

    Return Values: CTestCaseController* : pointer to created object

    Errors/Exceptions: Leaves if construction of CTestCaseController fails

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestCaseController* CTestCaseController::NewL( CTestEngine* aEngine,
                                               CTestReport* aTestReport,
                                               CAtsLogger& aAtsLogger,
                                               RTestExecution aTestExecution,
                                               const TTestInfo& aTestInfo )
    {
    CTestCaseController* self = new ( ELeave ) CTestCaseController( aEngine,
        aTestReport, aAtsLogger, aTestExecution, aTestInfo );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;

    }

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

    Class: CTestCaseController

    Method: ~CTestCaseController

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
CTestCaseController::~CTestCaseController()
    {
    __TRACE( KVerbose, ( _L( "CTestCaseController::~CTestCaseController" ) ) );
    Cancel();

    delete iRDebugLogger;
    delete iTimeout;

    }

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

    Class: CTestCaseController

    Method: StartL

    Description: Start active object

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestCaseController::StartL( const RMessage2& aMessage )
    {
    iRDebugLogger->Log( _L( "Starting testcase [%S]" ), &iTestInfo.iTestCaseInfo.iTitle );
    __TRACE( KInit, ( _L(" Starting testcase [%S]"), &iTestInfo.iTestCaseInfo.iTitle ) );

    // Check that this request is not pending!!
    __ASSERT_ALWAYS( iState != ETestCaseRunning,
                            iEngine->PanicClient( EReqPending, aMessage ) );
    iMessage = aMessage;

    iState = ETestCaseRunning;
    
    SetActive();

    iTestExecution.RunTestCase( iResultPckg, iStatus );    

    // If testcase has timeout (handler), then start it
    if ( iTimeout )
        {
        iTimeout->Start();
        }

    }

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

    Class: CTestCaseController

    Method: Timeout

    Description: Timeouts active request.
    - Cancel request

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestCaseController::Timeout()
    {
    if ( iState == ETestCaseRunning )
        {
        iState = ETestCaseTimeout;
        Cancel();
        }

    }

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

    Class: CTestCaseController

    Method: RunL

    Description: RunL handles completed requests. Leaves are handled in
                 RunError method

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if AddTestCaseResultL leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCaseController::RunL()
    {
    iState = ETestCaseCompleted;


    // "iStatus.Int()" error code is received from system's framework not from
    // test case execution.
    if ( iStatus.Int() != KErrNone )
        {
            if ( iStatus.Int() == KErrServerTerminated )
            {
            // something went badly wrong!
            __TRACE( KInit, ( CStifLogger::ERed, 
                _L( "TestCase [%S] cannot be executed, STIF panics with[%d]" ),
                &iTestInfo.iTestCaseInfo.iTitle,
                iStatus.Int() ) );       
                
            __TRACE( KInit, ( CStifLogger::ERed, 
                _L( "Possible reason: Test case has paniced seriously" ) ) );

            // We don't leave here but we write information to 
            // forward(testreport etc.)
            _LIT( KLeaveInfo, "Test case execution fails" );
            // Sets test case to crash category
            iResult.iCaseExecutionResultCode = iStatus.Int();
            // Test case result
            iResult.iTestResult.iResult = iStatus.Int();
            iResult.iTestResult.iResultDes = KLeaveInfo;

            } 
        
            else
            {   
        // For example testmodule's NewL or testmodule's constructor has
        // leaved and STIF cannot connect to test module
        __TRACE( KInit, ( CStifLogger::ERed, 
            _L( "TestCase [%S] cannot execute, TestModule loading operations fails with[%d]" ),
            &iTestInfo.iTestCaseInfo.iTitle,
            iStatus.Int() ) );
        __TRACE( KInit, ( CStifLogger::ERed, 
            _L( "Possible reason: TestModule's NewL or Constructor has leaved and STIF cannot connect to test module" ) ) );

        // We don't leave here but we write information to 
        // forward(testreport etc.)
        _LIT( KLeaveInfo, "TestModule loading fails, cannot connect to the TestModule" );
        // Sets test case to crash category
        iResult.iCaseExecutionResultCode = iStatus.Int();
        // Test case result
        iResult.iTestResult.iResult = iStatus.Int();
        iResult.iTestResult.iResultDes = KLeaveInfo;
            }
        }
        
	else
	{
			
    // Cancel event request, because the testcase is completed
    iTestExecution.CancelAsyncRequest( ETestExecutionNotifyEvent );        
	}

    // Test case is executed
    if( iTestInfo.iTestCaseInfo.iTitle.Length() > 0 )
        {
        iRDebugLogger->Log( _L( "TestCase [%S] finished with verdict[%d]" ),
                            &iTestInfo.iTestCaseInfo.iTitle,
                            iResult.iTestResult.iResult );

        __TRACE( KInit, ( _L( " TestCase [%S] finished with verdict[%d]" ),
                            &iTestInfo.iTestCaseInfo.iTitle,
                            iResult.iTestResult.iResult ) );
        }
    else
        {
        iRDebugLogger->Log( _L( "TestCase [%d] finished with verdict[%d]" ),
                            iTestInfo.iTestCaseInfo.iCaseNumber,
                            iResult.iTestResult.iResult );

        __TRACE( KInit, ( _L( " TestCase [%d] finished with verdict[%d]" ),
                            iTestInfo.iTestCaseInfo.iCaseNumber,
                            iResult.iTestResult.iResult ) );
        }
    __TRACE( KVerbose, ( 
            _L( "CTestCaseController::RunL: iStatus=[%d]" ), iStatus.Int() ));

    GenerateXmlLogL();

    // Report test case result
    if( iTestReport )
        {
        iTestReport->AddTestCaseResultL( iTestInfo, iResult, iStatus.Int() );
        iTestReport->UpdateReportSummaryL();
        }

    TRAPD( ret, iMessage.WriteL( 0, iResultPckg ) );

    // Case done
    iMessage.Complete( ret );

    }

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

    Class: CTestCaseController

    Method: DoCancel

    Description: Cancel active request

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

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

    switch ( iState )
        {
        case ETestCaseRunning:
            iTestExecution.CancelAsyncRequest( ETestExecutionRunTestCase );
            if( iTestInfo.iTestCaseInfo.iTitle.Length() > 0 )
                {
                iRDebugLogger->Log( _L( "TestCase [%S] execution aborted" ),
                                    &iTestInfo.iTestCaseInfo.iTitle );

                __TRACE( KInit, ( _L( "TestCase [%S] execution aborted" ),
                                    &iTestInfo.iTestCaseInfo.iTitle ) );
                }
            else
                {
                iRDebugLogger->Log( _L( "TestCase [%S] execution aborted" ),
                                    iTestInfo.iTestCaseInfo.iCaseNumber );

                __TRACE( KInit, ( _L( "TestCase [%S] execution aborted" ),
                                    iTestInfo.iTestCaseInfo.iCaseNumber ) );
                }
            break;
        case ETestCaseTimeout:
            iTestExecution.CancelAsyncRequest( ETestExecutionRunTestCase );
            // Update result to timeout
            iResult.iCaseExecutionResultType = TFullTestResult::ECaseTimeout;
            iResult.iTestResult.iResultDes = _L("Test case was timeouted and cancelled");

            if( iTestReport )
                {
                iTestReport->AddTestCaseResultL( iTestInfo, iResult, KErrTimedOut );
                }

            if( iTestInfo.iTestCaseInfo.iTitle.Length() > 0 )
                {
                iRDebugLogger->Log( _L( "TestCase [%S] finished with verdict[%d]" ),
                                    &iTestInfo.iTestCaseInfo.iTitle,
                                    iResult.iTestResult.iResult );

                __TRACE( KInit, ( _L( " TestCase [%S] finished with verdict[%d]" ),
                                    &iTestInfo.iTestCaseInfo.iTitle,
                                    iResult.iTestResult.iResult ) );
                }
            else
                {
                iRDebugLogger->Log( _L( "TestCase [%d] finished with verdict[%d]" ),
                                    iTestInfo.iTestCaseInfo.iCaseNumber,
                                    iResult.iTestResult.iResult );

                __TRACE( KInit, ( _L( " TestCase [%d] finished with verdict[%d]" ),
                                    iTestInfo.iTestCaseInfo.iCaseNumber,
                                    iResult.iTestResult.iResult ) );
                }            
            
            break;
        case ETestCaseSuicided:
            {
            //Store current results because cancel operation overwrites it
            TInt currentTestResult = iResult.iTestResult.iResult;
            TInt currentExecutionResult = iResult.iCaseExecutionResultCode;
            iTestExecution.CancelAsyncRequest(ETestExecutionRunTestCase);
            // Update result to suicide
            switch(iStopExecutionType)
                {
                case EOk:
                    iResult.iCaseExecutionResultType = TFullTestResult::ECaseExecuted;
                    iResult.iTestResult.iResultDes = _L("Test case passed (StopExecution())");
                    break;
                case EFail:
                    iResult.iCaseExecutionResultType = TFullTestResult::ECaseExecuted;
                    iResult.iTestResult.iResultDes = _L("Test case failed (StopExecution())");
                    break;
                default: //EAbort
                    iResult.iCaseExecutionResultType = TFullTestResult::ECaseSuicided;
                    iResult.iTestResult.iResultDes = _L("Test case killed (StopExecution())");
                }
            iResult.iTestResult.iResult = currentTestResult;
            iResult.iCaseExecutionResultCode = currentExecutionResult;
            }
            if(iTestReport)
                {
                iTestReport->AddTestCaseResultL(iTestInfo, iResult, KErrNone);
                }

            // Log some message
            if(iTestInfo.iTestCaseInfo.iTitle.Length() > 0)
                {
                _LIT(KTestCaseDesc, "TestCase [%S] finished with verdict [%d]");
                switch(iStopExecutionType)
                    {
                    case EOk:
                        {
                        _LIT(KTestCaseResult, "***Testcase PASSED***");

                        iRDebugLogger->Log(KTestCaseResult);
                        __TRACE(KInit, (KTestCaseResult));
                        iRDebugLogger->Log(KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult);
                        __TRACE(KInit, (KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult));
                        break;
                        }
                    case EFail:
                        {
                        _LIT(KTestCaseResult, "***Testcase FAILED***");

                        iRDebugLogger->Log(KTestCaseResult);
                        __TRACE(KInit, (KTestCaseResult));
                        iRDebugLogger->Log(KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult);
                        __TRACE(KInit, (KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult));
                        break;
                        }
                    default: //EAbort
                        {
                        _LIT(KTestCaseResult, "***Testcase KILLED***");

                        iRDebugLogger->Log(KTestCaseResult);
                        __TRACE(KInit, (KTestCaseResult));
                        iRDebugLogger->Log(KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult);
                        __TRACE(KInit, (KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult));
                        }
                    }
                }
            else
                {
                _LIT(KTestCaseDesc, "TestCase [%d] finished with verdict [%d]");
                switch(iStopExecutionType)
                    {
                    case EOk:
                        {
                        _LIT(KTestCaseResult, "***Testcase PASSED***");

                        iRDebugLogger->Log(KTestCaseResult);
                        __TRACE(KInit, (KTestCaseResult));
                        iRDebugLogger->Log(KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult);
                        __TRACE(KInit, (KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult));
                        break;
                        }
                    case EFail:
                        {
                        _LIT(KTestCaseResult, "***Testcase FAILED***");

                        iRDebugLogger->Log(KTestCaseResult);
                        __TRACE(KInit, (KTestCaseResult));
                        iRDebugLogger->Log(KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult);
                        __TRACE(KInit, (KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult));
                        break;
                        }
                    default: //EAbort
                        {
                        _LIT(KTestCaseResult, "***Testcase KILLED***");

                        iRDebugLogger->Log(KTestCaseResult);
                        __TRACE(KInit, (KTestCaseResult));
                        iRDebugLogger->Log(KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult);
                        __TRACE(KInit, (KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult));
                        }
                    }
                }
            break;
        case ETestCaseIdle:
        case ETestCaseCompleted:
        default:
            // DoCancel called in wrong state => Panic
            _LIT( KTestCaseController, "CTestCaseController" );
            User::Panic( KTestCaseController, EDoCancelDisorder );
            break;
        }

    // Write result and complete 
    TRAPD( ret, iMessage.WriteL( 0, iResultPckg ) );

    iMessage.Complete( ret );  
        
    iState = ETestCaseCompleted;
    
    // Generate xml result log
    GenerateXmlLogL();

    }

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

    Class: CTestCaseController

    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 CTestCaseController::RunError( TInt aError )
    {
    __TRACE( KError, ( CStifLogger::ERed, 
        _L( "CTestCaseController::RunError: Test case execution has failed! aError=[%d]" ), aError ) );
    TInt completionError = aError;

    // Write result, because it could include descriptive result for
    // failed case
    TRAPD( err, iMessage.WriteL( 0, iResultPckg ); );

    if ( err != KErrNone )
        {
        completionError = err;
        }

    // Complete message with error
    iMessage.Complete( completionError );

    return KErrNone;

    }

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

    Class: CTestCaseController

    Method: GenerateXmlLogL

    Description: Generate XML log.

    Parameters: None

    Return Values: None
    
    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestCaseController::GenerateXmlLogL()
    {
    
    // Report result with AtsLogger
    iAtsLogger.BeginTestCaseReportL( iTestInfo.iTestCaseInfo.iTitle, 
                                     KErrNone,  // Expected result not supported
                                     iResult.iStartTime );
    
    if( iResult.iCaseExecutionResultCode != KErrNone )
        {
        iAtsLogger.SetTestCaseResultL( iResult.iCaseExecutionResultCode );
        iAtsLogger.TestCaseFailed();  
        if( iResult.iTestResult.iResultDes.Length() > 0 )
            {
            iAtsLogger.ErrorL( iResult.iTestResult.iResultDes );   
            } 
        }
     else
        {
        iAtsLogger.SetTestCaseResultL( iResult.iTestResult.iResult ); 
        if( iResult.iTestResult.iResult == KErrNone )
            {
            iAtsLogger.TestCasePassed();  
            }
        else
            {
            iAtsLogger.TestCaseFailed();  
            if( iResult.iTestResult.iResultDes.Length() > 0 )
                {
                iAtsLogger.ErrorL( iResult.iTestResult.iResultDes );    
                }
            }
        }
    // Set test case result to ATS Logger
    iAtsLogger.EndTestCaseL();

    }

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

    Class: CTestCaseController

    Method: GetTestCaseInfo

    Description: Get testcase info(test module, config file, test case, etc).

    Parameters: TTestInfo& aTestInfo: inout: Test information

    Return Values: None
    
    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestCaseController::GetTestCaseInfo( TTestInfo& aTestInfo )
    {
    aTestInfo = iTestInfo;

    }

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

    Class: CTestCaseController

    Method: Suicide

    Description: Cancels active request.

    Parameters: aCode: the reason of suicide

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
void CTestCaseController::Suicide(TStopExecutionType aType, TInt aCode)
    {
    if(iState == ETestCaseRunning)
        {
        iStopExecutionType = aType;
        switch(iStopExecutionType)
            {
            case EOk:
                iResult.iTestResult.iResult = KErrNone;
                iResult.iCaseExecutionResultCode = KErrNone;
                break;
            case EFail:
                iResult.iTestResult.iResult = aCode;
                iResult.iCaseExecutionResultCode = KErrNone;
                break;
            default: //EAbort
                iResult.iTestResult.iResult = aCode;
                iResult.iCaseExecutionResultCode = aCode;
            }
        iState = ETestCaseSuicided;
        Cancel();
        }
    }

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

    DESCRIPTION

    This module contains implementation of CTestProgressNotifier class member
    functions.

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

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

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

    Class: CTestProgressNotifier

    Method: CTestProgressNotifier

    Description: Default constructor

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

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestProgressNotifier::CTestProgressNotifier( CTestEngine* aEngine,
                             RTestExecution aTestExecution ) :
    CActive( CActive::EPriorityStandard ),
    iEngine( aEngine ),
    iTestExecution( aTestExecution ),
    iState( ETestProgressIdle ),
    iProgressPckg( iProgress )
    {
    CActiveScheduler::Add( this );

    }

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

    Class: CTestProgressNotifier

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestProgressNotifier::ConstructL()
    {
    __TRACE( KVerbose, ( _L( "CTestProgressNotifier::ConstructL" ) ) );
    }

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

    Class: CTestProgressNotifier

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                RTestExecution aTestExecution: in: Handle to RTestExecution

    Return Values: CTestProgressNotifier* : pointer to created object

    Errors/Exceptions: Leaves if construction of CTestProgressNotifier fails

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestProgressNotifier* CTestProgressNotifier::NewL( CTestEngine* aEngine,
                             RTestExecution aTestExecution )
    {
    CTestProgressNotifier* self = new ( ELeave ) CTestProgressNotifier(
        aEngine, aTestExecution );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;

    }

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

    Class: CTestProgressNotifier

    Method: ~CTestProgressNotifier

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestProgressNotifier::~CTestProgressNotifier()
    {
    __TRACE( KVerbose, ( _L( "CTestProgressNotifier::~CTestProgressNotifier" ) ) );
    Cancel();

    }

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

    Class: CTestProgressNotifier

    Method: StartL

    Description: Start active object

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestProgressNotifier::StartL( const RMessage2& aMessage )
    {
    __TRACE( KVerbose, ( _L( "CTestProgressNotifier::StartL" ) ) );
    // Check that this request is not pending!!
    __ASSERT_ALWAYS( iState != ETestProgressPending,
                        iEngine->PanicClient( EReqPending, aMessage ) );
    iMessage = aMessage;

    iState = ETestProgressPending;
    SetActive();

    iTestExecution.NotifyProgress( iProgressPckg, iStatus );

    }

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

    Class: CTestProgressNotifier

    Method: RunL

    Description: RunL handles completed requests.

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if WriteL leaves
                       Leaves if iStatus is not KErrNone or KErrEof
                       Leaves are handled in RunError method

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestProgressNotifier::RunL()
    {
    __TRACE( KVerbose, (_L("CTestProgressNotifier::RunL: iStatus=[%d]" ), iStatus.Int() ));

    iState = ETestProgressCompleted;

    // Check that request was successful or completed with acceptable error
    // KErrEof is acceptable error and it means that the test case will not
    // send progresses anymore (because it is closed)
    if ( KErrNone == iStatus.Int() )
        {
        iMessage.WriteL( 0, iProgressPckg );
        }
    else if ( KErrEof != iStatus.Int() )
        {
        // Leave, error will be handled in RunError
        User::Leave( iStatus.Int() );
        }

    // Complete message
    iMessage.Complete( iStatus.Int() );

    }

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

    Class: CTestProgressNotifier

    Method: DoCancel

    Description: Cancel active request

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestProgressNotifier::DoCancel()
    {
    switch ( iState )
        {
        case ETestProgressPending:
            iTestExecution.CancelAsyncRequest( ETestExecutionNotifyProgress );
            iMessage.Complete( KErrCancel );
            break;
        case ETestProgressIdle:
        case ETestProgressCompleted:
        default:
            // DoCancel called in wrong state => Panic
            _LIT( KTestProgressNotifier, "CTestProgressNotifier" );
            User::Panic( KTestProgressNotifier, EDoCancelDisorder );
            break;
        }
    iState = ETestProgressIdle;

    }

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

    Class: CTestProgressNotifier

    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 CTestProgressNotifier::RunError( TInt aError )
    {
    // Complete message with error
    iMessage.Complete( aError );

    return KErrNone;

    }

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

    DESCRIPTION

    This module contains implementation of CTestEventNotifier class member
    functions.

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

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

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

    Class: CTestEventNotifier

    Method: CTestEventNotifier

    Description: Default constructor

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

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                RTestExecution aTestExecution: in: Handle to RTestExecution

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEventNotifier::CTestEventNotifier( CTestEngine* aEngine, 
                                        RTestExecution aTestExecution ) :
    CActive( CActive::EPriorityStandard ),
    iEngine( aEngine ),
    iTestExecution( aTestExecution ),
    iState( ETestEventIdle ),
    iEventPckg( iEvent ),
    iEventNotifyPckg( iEventNotify ),
    iController( NULL )
    {
    CActiveScheduler::Add( this );

    }

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

    Class: CTestEventNotifier

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEventNotifier::ConstructL( )
    {
    __TRACE( KVerbose, ( _L( "CTestEventNotifier::ConstructL" ) ) );

    }

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

    Class: CTestEventNotifier

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                RTestExecution aTestExecution: in: Handle to RTestExecution

    Return Values: CTestEventNotifier* : pointer to created object

    Errors/Exceptions: Leaves if construction of CTestEventNotifier fails

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEventNotifier* CTestEventNotifier::NewL( CTestEngine* aEngine,
                                              RTestExecution aTestExecution )
    {
    CTestEventNotifier* self = new ( ELeave ) CTestEventNotifier(
        aEngine, aTestExecution );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;

    }

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

    Class: CTestEventNotifier

    Method: ~CTestEventNotifier

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEventNotifier::~CTestEventNotifier()
    {
    __TRACE( KVerbose, ( _L( "CTestEventNotifier::~CTestEventNotifier" ) ) );
    Cancel();
    iEventArray.ResetAndDestroy();
    iEventArray.Close();
    delete iController;

    }

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

    Class: CTestEventNotifier

    Method: StartL

    Description: Start active object

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEventNotifier::Start()
    {
    __TRACE( KVerbose, ( _L( "CTestEventNotifier::StartL" ) ) );
    // Check that this request is not pending!!
    __ASSERT_ALWAYS( iState != ETestEventPending,
        User::Leave( KErrAlreadyExists ) );

    iEvent.SetType( TEventIf::EEnable );
    iState = ETestEventPending;
    iTestExecution.NotifyEvent( iEventPckg, iStatus );
    SetActive();

    }

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

    Class: CTestEventNotifier

    Method: RunL

    Description: RunL handles completed requests.

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if iStatus is not KErrNone
                       Leaves if iState is not ETestEventPending
                       Leaves if some leaving method called here leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEventNotifier::RunL()
    {
    __TRACE( KVerbose, ( _L( "CTestEventNotifier::RunL: iStatus=[%d]" ), iStatus.Int() ) );

    User::LeaveIfError( iStatus.Int() );

    switch( iState )
        {
        case ETestEventPending:
            {
            iState = ETestEventCompleted;
            
            switch( iEvent.Type() )
                {
                case TEventIf::EReqEvent:
                    {
                    __RDEBUG( ( _L("CTestEventNotifier(ReqEvent) %S"), 
                        &iEvent.Name() ));
                    if( iEngine->IsStateEventAndSet( iEvent.Name() ) )
                        {
                        __TRACE( KVerbose, ( _L( "CTestEventNotifier::RunL: Requested Global event already set" ) ) );
                        TEventIf event( TEventIf::ESetEvent, iEvent.Name(),
                                        TEventIf::EState );
                        TEventIfPckg eventPckg( event );
                        TRequestStatus status;
                        iTestExecution.NotifyEvent( eventPckg, status );
                        User::WaitForRequest( status );
                        }
                    //add to iEventArray
                    HBufC* name = iEvent.Name().AllocLC();
                    if( iEventArray.Append( name ) != KErrNone )
                        {
                        User::Leave( KErrNoMemory );
                        }
                    CleanupStack::Pop( name );
                    }
                    break;                    
                case TEventIf::ERelEvent:
                    {
                    __TRACE( KVerbose, ( _L( "CTestEventNotifier(RelEvent) %S" ), &iEvent.Name() ) );
                    //remove from iEventArray
                    TInt count = iEventArray.Count();
                    const TDesC& eventName = iEvent.Name();
                    TInt i;
                    for( i = 0; i < count; i++ )
                        {
                        TPtrC name = iEventArray[i]->Des();
                        if( name == eventName )
                            {
                            HBufC* tmp = iEventArray[i];
                            iEventArray.Remove( i );
                            delete tmp;
                            break;
                            }
                        }
                    // Check that event was found
                    if( i == count )
                        {
                        User::Leave( KErrGeneral );
                        }         
                    }
                    break;                    
                case TEventIf::ESetEvent:
                    {
                    __RDEBUG( ( _L("CTestEventNotifier(SetEvent) %S"), 
                        &iEvent.Name() ));
                    iController = iEngine->CtlEventL( iEvent, iStatus );
                    SetActive();
                    return;
                    }
                case TEventIf::EUnsetEvent:
                    {
                    __RDEBUG( ( _L("CTestEventNotifier(UnsetEvent) %S"), 
                        &iEvent.Name() ));
                    iController = iEngine->CtlEventL( iEvent, iStatus );
                    SetActive();
                    return;
                    }
                default:
                    {
                    User::Leave( KErrGeneral );
                    }
                }
            // Set request again
            Start();                
            // Otherwise request is enabled again later
            }
            break;
        case ETestEventCompleted:
            __RDEBUG( ( _L("CTestEventNotifier(Complete)")));
            Start();
            break;
        default:
            User::Leave( KErrGeneral );
            break;
        }

    }

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

    Class: CTestEventNotifier

    Method: DoCancel

    Description: Cancel active request

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEventNotifier::DoCancel()
    {
    __TRACE( KVerbose, ( _L( "CTestEventNotifier::DoCancel" ) ) );

    switch ( iState )
        {
        case ETestEventPending:
            iTestExecution.CancelAsyncRequest( ETestExecutionNotifyEvent );
            break;
        case ETestEventCompleted:
            delete iController;
            iController = NULL;
            break;
        default:
            // DoCancel called in wrong state => Panic
            _LIT( KTestEventNotifier, "CTestEventNotifier" );
            User::Panic( KTestEventNotifier, EDoCancelDisorder );
            break;
        }

    iState = ETestEventIdle;
    iEventArray.ResetAndDestroy();

    }

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

    Class: CTestEventNotifier

    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 CTestEventNotifier::RunError( TInt aError )
    {
    switch ( iState )
        {
        case ETestEventPending:
            if( aError != KErrCancel )
                {
                __TRACE( KError, ( CStifLogger::ERed, _L( "CTestEventNotifier::RunError %d"), aError) );
                }
            else
                {
                __TRACE( KVerbose, ( _L( "CTestEventNotifier stopped")) );
                }

            // We stop event notifier if we get error here
            // Clear requested event list
            iEventArray.ResetAndDestroy();
            break;
        case ETestEventCompleted:
            // Do not close here
            __TRACE( KError, ( CStifLogger::ERed, _L( "CTestEventNotifier::RunError %d"), aError) );
            delete iController;
            iController = NULL;
            // forward error to testcase
            iEvent.SetType( TEventIf::EEnable );
            iState = ETestEventPending;
            iTestExecution.NotifyEvent( iEventPckg, iStatus, aError );
            SetActive();
            break;
        default:
            __TRACE( KError, ( CStifLogger::ERed, _L( "CTestEventNotifier::RunError %d"), aError) );
            // DoCancel called in wrong state => Panic
            _LIT( KTestEventNotifier, "CTestEventNotifier" );
            User::Panic( KTestEventNotifier, EDoCancelDisorder );
            break;
        }

    return KErrNone;

    }

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

    Class: CTestEventNotifier

    Method: CtlEventL

    Description: Controls events

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

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEventNotifier::CtlEvent( const TEventIf& aEvent, 
                                    TRequestStatus& aStatus )
    {
    __TRACE( KVerbose, ( _L( "CTestEventNotifier::CtlEventL" ) ) );
    const TDesC& eventName = aEvent.Name();
    TInt count = iEventArray.Count();
    for( TInt i = 0; i < count; i++ )
        {
        TPtrC name = iEventArray[i]->Des();
        if( name == eventName )
            {
            iEventNotify.Copy( aEvent );
            iTestExecution.NotifyEvent( iEventNotifyPckg, aStatus );
            return;
            }
        }
    }

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

    Class: CTestEventNotifier

    Method: CheckCtlEventL

    Description: Checks if CtlEvent should be called

    Parameters: const TEventIf& aEvent: in: Event

    Return Values: ETrue: If CtlEvent sould be called.

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
TBool CTestEventNotifier::CheckCtlEvent( const TEventIf& aEvent )
    {
    const TDesC& eventName = aEvent.Name();
    TInt count = iEventArray.Count();
    for( TInt i = 0; i < count; i++ )
        {
        TPtrC name = iEventArray[i]->Des();
        if( name == eventName )
            {
            return ETrue;
            }
        }

    return EFalse;
    }

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

    DESCRIPTION

    This module contains implementation of CTestEventController class member
    functions.

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

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

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

    Class: CTestEventController

    Method: CTestEventController

    Description: Default constructor

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

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                const TEventIf& aEvent: in: Event

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEventController::CTestEventController( CTestEngine* aEngine, 
                                            const TEventIf& aEvent ) :
    iEngine( aEngine ),
    iRequestStatus( NULL ),
    iEventPckg( iEvent ),
    iActiveEventCmds( 0 )
    {
    iEvent.Copy( aEvent );

    }

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

    Class: CTestEventController

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: TRequestStatus* aStatus: in: Request status

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEventController::ConstructL( TRequestStatus* aStatus )
    {
    iEngine->Logger()->Log( _L( "CTestEventController::ConstructL" ) );

    if( CheckEventsL() == 0 )
        {
        // No request was pending, complete immediately
        User::RequestComplete( aStatus, KErrNone );
        }
    else
        {
        iRequestStatus = aStatus;
        }

    }

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

    Class: CTestEventController

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: RMessage& aMessage: inout: Message to be handled

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEventController::ConstructL( RMessage2& aMessage )
    {
    iEngine->Logger()->Log( _L( "CTestEventController::ConstructL" ) );

    if( CheckEventsL() == 0 )
        {
        // No request was pending, complete immediately
        aMessage.Complete( KErrNone );
        }
    else
        {
        iMessage = aMessage;
        }

    }

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

    Class: CTestEventNotifier

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                const TEventIf& aEvent: in: Event
                TRequestStatus* aStatus: in: Request status

    Return Values: CTestEventController* : pointer to created object

    Errors/Exceptions: Leaves if construction of CTestEventController fails

    Status: Approved

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

CTestEventController* CTestEventController::NewL( CTestEngine* aEngine,
                                                  const TEventIf& aEvent,
                                                  TRequestStatus* aStatus )
    {
    CTestEventController* self = 
        new ( ELeave )CTestEventController( aEngine, aEvent );
    CleanupStack::PushL( self );
    self->ConstructL( aStatus );
    CleanupStack::Pop( self );
    return self;

    }

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

    Class: CTestEventNotifier

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                const TEventIf& aEvent: in: Event
                RMessage& aMessage: inout: Message to be handled

    Return Values: CTestEventController* : pointer to created object

    Errors/Exceptions: Leaves if construction of CTestEventController fails

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestEventController* CTestEventController::NewL( CTestEngine* aEngine,
                                                  const TEventIf& aEvent,
                                                  RMessage2& aMessage )
    {
    CTestEventController* self = 
        new ( ELeave )CTestEventController( aEngine, aEvent );
    CleanupStack::PushL( self );
    self->ConstructL( aMessage );
    CleanupStack::Pop( self );
    return self;

    }

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

    Class: CTestEventController

    Method: ~CTestEventController

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Proposal

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

CTestEventController::~CTestEventController()
    {
	if( iEngine != NULL )
		{
		if( iEngine->Logger() != NULL )
			{
			iEngine->Logger()->Log( _L( "CTestEventController::~CTestEventController" ) );
			}
		}
    
    if( iRequestStatus )
        {
        // Must be completed if pending, otherwise  
        // CTestEventNotifier::DoCancel blocks
        User::RequestComplete( iRequestStatus, KErrCancel );
        }
            
    iEventCallBacks.ResetAndDestroy();
    iEventCallBacks.Close();

    }

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

    Class: CTestEventController

    Method: CheckEventsL

    Description: Check all events.

    Parameters: None

    Return Values: TInt: Active event commands

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

    Status: Approved

-------------------------------------------------------------------------------
*/  
TInt CTestEventController::CheckEventsL()
    {
    iEngine->Logger()->Log( _L( "CTestEventController::CheckEventsL" ) );

    iActiveEventCmds += CheckClientEventsL();
    iActiveEventCmds += CheckTestcaseEventsL();

    return iActiveEventCmds;

    }

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

    Class: CTestEventController

    Method: CheckClientEventsL

    Description: Check client events.

    Parameters: None

    Return Values: TInt: Request of pending

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

    Status: Approved

-------------------------------------------------------------------------------
*/  
TInt CTestEventController::CheckClientEventsL()
    {
    iEngine->Logger()->Log( _L( "CTestEventController::CheckClientEventsL" ) );
    TInt reqPending = 0;

    // Check client event requests
    TInt count = iEngine->ClientEvents().Count();
    for( TInt index = 0; index < count; index++ )
        {
        if( iEngine->ClientEvents()[index]->Name() == iEvent.Name() )
            {
            TEventMsg* event = iEngine->ClientEvents()[index]; 
            if( iEvent.Type() == TEventIf::ESetEvent )
                {
                // Set found event 
                event->Set( iEvent.EventType() );
                }
            else if( iEvent.Type() == TEventIf::EUnsetEvent )
                {
                // Unset found event
                // Create callback for change notifier
                TCallBack callBack( EventCallBack, this );
                CCallBack* eventCallBack = new (ELeave)CCallBack( callBack,
                                                    CActive::EPriorityHigh );
                CleanupStack::PushL( eventCallBack );
                
                event->Unset( eventCallBack->Status() ); 
                reqPending++;
                eventCallBack->SetActive();
                User::LeaveIfError( iEventCallBacks.Append( eventCallBack ) );
                CleanupStack::Pop( eventCallBack );
                }       
            break;
            }
        }

    return reqPending;

    }

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

    Class: CTestEventController

    Method: CheckTestcaseEventsL

    Description: Check testcase events.

    Parameters: None

    Return Values: TInt: Request of pending

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

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEventController::CheckTestcaseEventsL()
    {
    TInt reqPending = 0;
    TCallBack callBack( EventCallBack, this );
    CCallBack* eventCallBack = NULL;

    // Then check testcase event requests
    TInt count = iEngine->TestCaseArray().Count();
    eventCallBack = new (ELeave)CCallBack( callBack, 
                                           CActive::EPriorityHigh );
    CleanupStack::PushL( eventCallBack );
    for ( TInt index = 0; index < count; index++ )
        {

        if( iEngine->TestCaseArray()[index]->CheckCtlEvent( iEvent ))
            {
            reqPending++;
            eventCallBack->SetActive();
            iEngine->TestCaseArray()[index]->CtlEvent( iEvent, 
                                                          eventCallBack->Status() );                                                          
            User::LeaveIfError( iEventCallBacks.Append( eventCallBack ) );
            CleanupStack::Pop( eventCallBack );
            eventCallBack = new (ELeave)CCallBack( callBack, 
                                                   CActive::EPriorityHigh );
            CleanupStack::PushL( eventCallBack );    
            }
        }
    CleanupStack::PopAndDestroy( eventCallBack );
    return reqPending;

    }

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

    Class: CTestEventController

    Method: EventComplete

    Description: EventComplete handles completed event requests.

    Parameters: None

    Return Values: None

    Errors/Exceptions: 

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestEventController::EventComplete()
    {
    iEngine->Logger()->Log( _L( "CTestEventController::EventComplete" ));

    iActiveEventCmds--;
    
    if( iActiveEventCmds == 0 )
        {
        TInt error = KErrNone;
        TInt count = iEventCallBacks.Count();
        for( TInt i=0; i<count; i++ )
            {
            if( iEventCallBacks[i]->iStatus.Int() != KErrNone )
                {
                error = iEventCallBacks[i]->iStatus.Int();
                break;
                }
            }
        iEventCallBacks.ResetAndDestroy();
            
        // All event commands are completed
        if( iRequestStatus )
            {
            User::RequestComplete( iRequestStatus, error );
            }
        else
            {
            // No request was pending, complete immediately
            iMessage.Complete( error );
            }
        }

    }

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

    Class: CTestEventController

    Method: EventCallBack

    Description: static EventCallBack handles completed event requests.

    Parameters: TAny* aTestEventController: in: Test event controller

    Return Values: TInt: returns KErrNone

    Errors/Exceptions:None

    Status: Approved

-------------------------------------------------------------------------------
*/
TInt CTestEventController::EventCallBack( TAny* aTestEventController )
    {
    CTestEventController* controller =
                                (CTestEventController*) aTestEventController;
    controller->EventComplete();
    return KErrNone;

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

    DESCRIPTION

    This module contains implementation of CTestRemoteCmdNotifier class member
    functions.

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

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

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

    Class: CTestProgressNotifier

    Method: CTestRemoteCmdNotifier

    Description: Default constructor

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

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
CTestRemoteCmdNotifier::CTestRemoteCmdNotifier( CTestEngine* aEngine,
                             RTestExecution aTestExecution,
                             CTestCaseController* aTestCaseController,
                             CAtsLogger& aAtsLogger ) :
    CActive( CActive::EPriorityStandard ),
    iEngine( aEngine ),
    iTestExecution( aTestExecution ),
    iState( ETestProgressIdle ),
    iRemoteTypePckg( iRemoteType ),
    iMsgSizePckg( iMsgSize ),
    iTestCaseController( aTestCaseController ),
    iAtsLogger( aAtsLogger )
    {
    CActiveScheduler::Add( this );

    }

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

    Class: CTestRemoteCmdNotifier

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
void CTestRemoteCmdNotifier::ConstructL( )
    {
    __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::ConstructL" ) ) );

    }

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

    Class: CTestRemoteCmdNotifier

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                RTestExecution aTestExecution: in: Handle to RTestExecution

    Return Values: CTestRemoteCmdNotifier* : pointer to created object

    Errors/Exceptions: Leaves if construction of CTestRemoteCmdNotifier fails

    Status: Draft

-------------------------------------------------------------------------------
*/
CTestRemoteCmdNotifier* CTestRemoteCmdNotifier::NewL( CTestEngine* aEngine,
                             RTestExecution aTestExecution,
                             CTestCaseController* aTestCaseController,
                             CAtsLogger& aAtsLogger )
    {
    CTestRemoteCmdNotifier* self = new ( ELeave ) CTestRemoteCmdNotifier(
        aEngine, aTestExecution, aTestCaseController, aAtsLogger );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;

    }

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

    Class: CTestRemoteCmdNotifier

    Method: ~CTestRemoteCmdNotifier

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
CTestRemoteCmdNotifier::~CTestRemoteCmdNotifier()
    {
    __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::~CTestRemoteCmdNotifier" ) ) );
    Cancel();

    delete iReceivedMsg;
    iReceivedMsg = 0;

    }

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

    Class: CTestRemoteCmdNotifier

    Method: EnableReceive

    Description: Prepare to start active object

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
void CTestRemoteCmdNotifier::EnableReceive( const RMessage2& aMessage )
    {
    __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::EnableReceive" ) ) );
    
    iMessage = aMessage;
    iMessageAvail = ETrue;
    
    Start( aMessage );

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

    Class: CTestRemoteCmdNotifier

    Method: GetReceivedMsg

    Description: Read received message

    Parameters: const RMessage& aMessage: in: Server message

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
void CTestRemoteCmdNotifier::GetReceivedMsg( const RMessage2& aMessage )
    {
    __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::GetReceivedMsg" ) ) );
    
    TInt ret = KErrNone;
    if( iReceivedMsg )
        {
        TRAP( ret, aMessage.WriteL( 0, iReceivedMsg->Des() ) );
        delete iReceivedMsg;
        iReceivedMsg = 0;
        }
    else
        {
        ret = KErrNotFound;
        }
        
    // Complete message
    aMessage.Complete( ret );
                
    }

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

    Class: CTestRemoteCmdNotifier

    Method: StartL

    Description: Start active object

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
void CTestRemoteCmdNotifier::Start( const RMessage2& aMessage )
    {
    // Check that this request is not pending!!
    __ASSERT_ALWAYS( iState != ETestProgressPending,
                    iEngine->PanicClient( EReqPending, aMessage ) );
    iState = ETestProgressPending;
    SetActive();
    // Start first phase of the remote command's operations
    iTestExecution.NotifyRemoteCmd( iRemoteTypePckg, 
                                    iMsgSizePckg, 
                                    iStatus );

    }

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

    Class: CTestRemoteCmdNotifier

    Method: CancelReq

    Description: Cancel the request.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
void CTestRemoteCmdNotifier::CancelReq()
    {
    if(iMessageAvail)
        {
        iMessageAvail = EFalse;
        iMessage.Complete( KErrCancel );
        }
    }

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

    Class: CTestRemoteCmdNotifier

    Method: RunL

    Description: RunL handles completed requests.

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if WriteL leaves
                       Leaves if iStatus is not KErrNone or KErrEof
                       Leaves are handled in RunError method

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestRemoteCmdNotifier::RunL()
    {
    __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::StartL: iStatus=[%d]" ), iStatus.Int() ) );

    User::LeaveIfError( iStatus.Int() );
    
    iState = ETestProgressCompleted;

    TInt ret( 0 );
    switch( iRemoteType )
        {
        case EStifCmdSend:             // "Sending"
            {
            if( ( iMessageAvail == EFalse ) ||
                ( iMsgSize <= 0 ) )
                { 
                User::Leave( KErrGeneral );
                }
            // Delete previous if exists
            delete iReceivedMsg;
            iReceivedMsg = 0;
            // Create new buffer 
            iReceivedMsg = HBufC8::NewL( iMsgSize );

            // Start second phase of the remote command's operations,
            // buffer is read with GetReceivedMsg
            TPtr8 tmp = iReceivedMsg->Des();
            ret = iTestExecution.ReadRemoteCmdInfo( tmp, iRemoteType );

            // Writing received info to UI
            iMessage.WriteL( 0, iRemoteTypePckg );
            iMessage.WriteL( 1, iMsgSizePckg );
            
            // Complete message
            iMessage.Complete( ret );
            iMessageAvail = EFalse;

            break;
            }
        case EStifCmdReboot:           // "Sending"
            {
            TRebootParams remoteType;
            TRebootParamsPckg remoteTypePckg( remoteType );
            // Start second phase of the remote command's operations
            ret = iTestExecution.ReadRemoteCmdInfo( remoteTypePckg, iRemoteType );
            __TRACE( KInit, ( CStifLogger::ERed, _L("REBOOT PHONE (type %d)" ), remoteType.aType ) );

            if( remoteType.aType == CTestModuleIf::EKernelReset )
                {
                __TRACE( KInit, ( _L("Rebooting with kernel reset" ) ) );
                __TRACE( KInit, ( _L("Kernel reset implementation is ongoing, trying different reset..." ) ) );
                }

#ifdef __WINS__
            __TRACE( KInit, ( _L("Rebooting with Process kill(WINS)" ) ) );
            RProcess thisProcess;
            //thisProcess.SetSystem( ETrue );
            thisProcess.Kill( KErrNone );
            thisProcess.Close();
#else // Hardware specific
            TInt r( KErrNone );
            __TRACE( KInit, ( _L("Rebooting with reset module(HW)" ) ) );
            r = DynamicResetModule( remoteType.aType );
            if( r != KErrNone )
                {
                __TRACE( KInit, ( CStifLogger::EError, _L("This reseting type is failed, trying different reset...")) );
                }
#endif // Hardware specific

            // if( !remoteType.aType == CTestModuleIf::EDefaultReset )
            // Note this change needs an error code tranceiver between reboot
            // module and engine. (If reboot fails return error code, if reboot
            // is default then kill process else error code returning)

            // Do process kill as a last option
            __TRACE( KInit, ( _L("Rebooting with Process kill" ) ) );
           
            RProcess thisProcess2;         
            thisProcess2.Kill( KErrNone );
            thisProcess2.Close();

            // If this text is shown in UI something is wrong and this needs some investigation.
            iEngine->ErrorPrint( 0, _L( "Reboot phone...E.g. disconnect battery!!!" ) );
            break;
            }
        case EStifCmdStoreState:       // "Sending"
            {
            if( iMessageAvail == EFalse )
                { 
                User::Leave( KErrGeneral );
                }
            TRebootStateParams remoteState;
            TRebootStateParamsPckg remoteStatePckg( remoteState );

            // Start second phase of the remote command's operations
            ret = iTestExecution.ReadRemoteCmdInfo( remoteStatePckg,
                                                    iRemoteType );

            // Get test case information(test module, test case file, etc.)
            TTestInfo testInfo;
            iTestCaseController->GetTestCaseInfo( testInfo );

            // Write state informations to the file
            iEngine->WriteRebootParams( testInfo, remoteState.aCode,
                                        remoteState.aName );
                                                        
            // Write ATS loggers buffers to drive
            iEngine->FlushAtsLogger();

            // Pause test cases that there cannot make e.g. new store state
            // calls. iCaseNumber is index type value so increment by one to
            // get current test case.
            iEngine->PauseAllTestCases();
            // Resume current test case
            iTestCaseController->iTestExecution.Resume();

            // Writing received info to UI
            iMessage.WriteL( 0, iRemoteTypePckg );

            // Complete message
            iMessage.Complete( ret );
            iMessageAvail = EFalse;
            break;
            }
        case EStifCmdGetStoredState:   // "Reading, this must be done with two phase"
            {
            // Get test case information(test module, test case file, etc.)
            TTestInfo testInfo;
            iTestCaseController->GetTestCaseInfo( testInfo );

            TGetRebootStoredParams remoteStoredState;
            // Read state informations from the file
            TInt errorCodeToClient = 
                iEngine->ReadRebootParams( testInfo, 
                                           remoteStoredState.aName,
                                           remoteStoredState.aCode );

            TGetRebootStoredParamsPckg remoteStoredPckg( remoteStoredState );

            // Start second phase of the remote command's operations
            ret = iTestExecution.ReadRemoteCmdInfo( remoteStoredPckg,
                                                    iRemoteType,
                                                    errorCodeToClient );
            
            Start( iMessage ); // Starts active object

            break;
            }
       case EStifCmdMeasurement:   // "Reading, this must be done with two phase"
            {
            TGetMeasurementOptions remoteMeasurementOptions;
            remoteMeasurementOptions.iOptions = iEngine->StifMeasurement();

            TGetMeasurementOptionsPckg remoteMeasurementPckg( remoteMeasurementOptions );

            // Start second phase of the remote command's operations
            ret = iTestExecution.ReadRemoteCmdInfo( remoteMeasurementPckg,
                                                    iRemoteType,
                                                    KErrNone );
            
            Start( iMessage ); // Starts active object

            break;
            }

        case EStifCmdReceive:          // "Reading"
        default:
            User::Leave( KErrNotFound );
            break;
        }
    
    }

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

    Class: CTestRemoteCmdNotifier

    Method: DoCancel

    Description: Cancel active request

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Draft

-------------------------------------------------------------------------------
*/
void CTestRemoteCmdNotifier::DoCancel()
    {
    switch ( iState )
        {
        case ETestProgressPending:
            iTestExecution.CancelAsyncRequest( ETestExecutionNotifyRemoteCmd );
            //iMessage.Complete( KErrCancel );
            break;
        case ETestProgressIdle:
        case ETestProgressCompleted:
        default:
            // DoCancel called in wrong state => Panic
            _LIT( KTestRemoteCmdNotifier, "CTestRemoteCmdNotifier" );
            User::Panic( KTestRemoteCmdNotifier, EDoCancelDisorder );
            break;
        }
    iState = ETestProgressIdle;

    }

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

    Class: CTestRemoteCmdNotifier

    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: Draft

-------------------------------------------------------------------------------
*/
TInt CTestRemoteCmdNotifier::RunError( TInt aError )
    {
    // Complete message with error
    if(iMessageAvail)
        {
        iMessageAvail = EFalse;
        iMessage.Complete( aError );
        }
    
    return KErrNone;

    }

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

    Class: CTestRemoteCmdNotifier

    Method: ResetL

    Description: Reset HW/WINS. Loads dynamically reset module by name.

    Parameters: CTestModuleIf::TRebootType aResetType: in: Reset type

    Return Values: TInt: Symbian error code.

    Errors/Exceptions: None

    Status: Proposal

-------------------------------------------------------------------------------
*/
TInt CTestRemoteCmdNotifier::DynamicResetModule( 
                                        CTestModuleIf::TRebootType aResetType )
    {
    __TRACE( KInit, (  _L( "DynamicResetModule()" ) ) );
    RLibrary resetModule;
    // Load the module
    TPtrC dllName;
    dllName.Set( iEngine->GetDeviceResetDllName() );
    // Loading should work with and without '.dll' extension.
    TInt r = resetModule.Load( dllName );
    if ( r != KErrNone )
        {
        __TRACE( KError, ( CStifLogger::EError, _L("Can't initialize reset module[%S], code = %d"), &dllName, r ) );
        return KErrNotFound;
        }
    else
        {
        // Print reset module name
        __TRACE( KInit, (  _L("Loaded reset module[%S]"), &dllName ) );
        }

    

    // Get pointer to first exported function
    CTestInterfaceFactory libEntry;
    libEntry = (CTestInterfaceFactory) resetModule.Lookup( 1 );
    if ( libEntry == NULL )
        {
        // New instance can't be created
        __TRACE ( KError, ( CStifLogger::EError, _L("Can't initialize reset module, NULL libEntry" ) ) );
        return KErrNoMemory;
        }
    else
        {
        __TRACE ( KInit, ( _L("Pointer to 1st exported received")));
        }

    CStifHWReset* reset;
    reset = NULL;

    // initialize test module
    __TRACE ( KVerbose, (_L("Calling 1st exported at 0x%x"), (TUint32) libEntry ));
    TRAPD ( err, reset =  (*libEntry)() );

     // Handle leave from test module
    if ( err != KErrNone )
        {
        __TRACE (KError, ( CStifLogger::EError, _L("Leave when calling 1st exported function, code %d"), err));
        return err;
        }
    else if ( reset == NULL )     // Handle NULL from test module init
        {
        __TRACE (KError, ( CStifLogger::EError, _L("NULL pointer received when constructing test module")));
        delete reset;

        // Set error codes
        return KErrNoMemory;
        }
    else
        {
        __TRACE (KInit, (_L("Entrypoint successfully called, test module instance at 0x%x"), (TUint32)reset ) );
        }

    // Calls dynamically loaded reset module's method.
    TInt ret = reset->DoReset( aResetType );
    if( ret != KErrNone )
        {
        __TRACE (KInit, (_L("DynamicResetModule; DoReset fails with error: %d"), ret ) );
        return ret;
        }

    return KErrNone;

    }

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

    DESCRIPTION

    This module contains implementation of CTestCommandNotifier class member
    functions.

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

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

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

    Class: CTestCommandNotifier

    Method: CTestCommandNotifier

    Description: Default constructor

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

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                RTestExecution aTestExecution: in: Handle to RTestExecution

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestCommandNotifier::CTestCommandNotifier(CTestEngine* aEngine,
                                           RTestExecution aTestExecution):
    CActive(CActive::EPriorityStandard),
    iEngine(aEngine),
    iTestExecution(aTestExecution),
    iCommandPckg(iCommand)
    {
    CActiveScheduler::Add(this);
    }

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

    Class: CTestCommandNotifier

    Method: ConstructL

    Description: Symbian OS second phase constructor

    Symbian OS default constructor can leave.

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCommandNotifier::ConstructL( )
    {
    __TRACE(KVerbose, (_L("CTestCommandNotifier::ConstructL")));
    }

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

    Class: CTestCommandNotifier

    Method: NewL

    Description: Two-phased constructor.

    Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine
                RTestExecution aTestExecution: in: Handle to RTestExecution

    Return Values: CTestCommandNotifier* : pointer to created object

    Errors/Exceptions: Leaves if construction of CTestCommandNotifier fails

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestCommandNotifier* CTestCommandNotifier::NewL(CTestEngine* aEngine,
                                                 RTestExecution aTestExecution)
    {
    CTestCommandNotifier* self = new (ELeave) CTestCommandNotifier(aEngine, aTestExecution);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

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

    Class: CTestCommandNotifier

    Method: ~CTestCommandNotifier

    Description: Destructor

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
CTestCommandNotifier::~CTestCommandNotifier()
    {
    __TRACE(KVerbose, (_L("CTestEventNotifier::~CTestEventNotifier")));
    Cancel();
    }

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

    Class: CTestCommandNotifier

    Method: StartL

    Description: Start active object

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCommandNotifier::Start()
    {
    __TRACE(KVerbose, (_L("CTestEventNotifier::StartL")));

    TInt res = iTestExecution.NotifyCommand2(iCommandPckg, iParamsPckg, iStatus, KErrNone);
    SetActive();
    }

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

    Class: CTestCommandNotifier

    Method: RunL

    Description: RunL handles completed requests.

    Parameters: None

    Return Values: None

    Errors/Exceptions: Leaves if iStatus is not KErrNone
                       Leaves if iState is not ETestEventPending
                       Leaves if some leaving method called here leaves

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCommandNotifier::RunL()
    {
    __TRACE(KVerbose, (_L("CTestCommandNotifier::RunL: iStatus=[%d]"), iStatus.Int()));

    User::LeaveIfError(iStatus.Int());

    iEngine->ExecuteCommandL(iCommand, iParamsPckg);

    // Set request again
    Start();
    }

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

    Class: CTestCommandNotifier

    Method: DoCancel

    Description: Cancel active request

    Parameters: None

    Return Values: None

    Errors/Exceptions: None

    Status: Approved

-------------------------------------------------------------------------------
*/
void CTestCommandNotifier::DoCancel()
    {
    __TRACE(KVerbose, (_L( "CTestEventNotifier::DoCancel")));

    iTestExecution.CancelAsyncRequest(ETestExecutionNotifyCommand);
    }

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

    Class: CTestCommandNotifier

    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 CTestCommandNotifier::RunError(TInt aError)
    {
    __TRACE(KError, (CStifLogger::ERed, _L("CTestCommandNotifier::RunError %d"), aError));
    return KErrNone;
    }


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

// None

// End of File
