/*
* 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 the implementation of 
* CTestThreadContainerRunner class member functions.
*
*/

// INCLUDE FILES
#include "TestThreadContainerRunner.h"
#include "ThreadLogging.h"
#include "TestThreadContainer.h"
#include "TestServer.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


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

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

     Class: CTestThreadContainerRunner

     Method: NewL

     Description: NewL is first phase of two-phased constructor.

     NewL is first phase of two-phased constructor.

     Parameters: TThreadId aMainThreadId: in: Main thread id.
     			 CActiveScheduler* aMainThreadActiveScheduler: in: Pointer to main thread active scheduler.
     
     Return Values: Pointer to new CTestThreadContainerRunner object.

     Errors/Exceptions: None

     Status: Draft
    
-------------------------------------------------------------------------------
*/
EXPORT_C CTestThreadContainerRunner* CTestThreadContainerRunner::NewL( TThreadId aMainThreadId, 
		CActiveScheduler* aMainThreadActiveScheduler )
	{	
	CTestThreadContainerRunner* self = new(ELeave) CTestThreadContainerRunner();
	CleanupStack::PushL( self );
	self->ConstructL( aMainThreadId, aMainThreadActiveScheduler );
	CleanupStack::Pop( self );
	
	return self;
	}

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

     Class: CTestThreadContainerRunner

     Method: CTestThreadContainerRunner

     Description: Default constructor.

	 Default constructor.

     Parameters: None.
     
     Return Values: None.

     Errors/Exceptions: None.

     Status: Draft
    
-------------------------------------------------------------------------------
*/
CTestThreadContainerRunner::CTestThreadContainerRunner()
:CActive( EPriorityNormal )
	{
	}

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

     Class: CTestThreadContainerRunner

     Method: ~CTestThreadContainerRunner

     Description: Default destructor.

	 Default destructor.

     Parameters: None.
     
     Return Values: None.

     Errors/Exceptions: None.

     Status: Draft
    
-------------------------------------------------------------------------------
*/
CTestThreadContainerRunner::~CTestThreadContainerRunner()
	{
	Cancel();
	}

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

     Class: CTestThreadContainerRunner

     Method: ConstructL

     Description: Second phase of two-phased constructor.

	 Second phase of two-phased constructor.

     Parameters: TThreadId aMainThreadId: in: Main thread id.
     			 CActiveScheduler* aMainThreadActiveScheduler: in: Pointer to main thread active scheduler.
     
     Return Values: None.

     Errors/Exceptions: None.

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::ConstructL( TThreadId aMainThreadId, 
		CActiveScheduler* aMainThreadActiveScheduler )
	{
	User::LeaveIfNull( aMainThreadActiveScheduler );
	
	iMainThreadId = aMainThreadId;

	iMainThreadActiveScheduler = aMainThreadActiveScheduler;	
	aMainThreadActiveScheduler->Add( this );
	
	iOperationOngoing.CreateLocal( 0 );
	
	iTestThreadContainer = NULL;
	iCurrentOperation = ENone;
	}

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

     Class: CTestThreadContainerRunner

     Method: Setup

     Description: Emulates setup part of CTestThreadContainer::ExecutionThread method

	 Setup is performed in main thread.

     Parameters: CTestModuleContainer* aTestModuleContainer: in: Pointer to test CTestModuleContainer
     
     Return Values: None.

     Errors/Exceptions: None.

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::Setup( CTestModuleContainer* aTestModuleContainer )
	{	
	iTestModuleContainer = aTestModuleContainer;
	iCurrentOperation = ESetup;
	SetActive();
	CompleteRequest();
	iOperationOngoing.Wait();
	}

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

     Class: CTestThreadContainerRunner

     Method: RunOneIteration

     Description: Emulates one iteration of while loop from CTestThreadContainer::ExecutionThread method

	 Iterations is performed in main thread.

     Parameters: None
     
     Return Values: None.

     Errors/Exceptions: None.

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::RunOneIteration()
	{	
	iCurrentOperation = ERunOneIteration;
	SetActive();
	CompleteRequest();
	iOperationOngoing.Wait();
	}

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

     Class: CTestThreadContainerRunner

     Method: TeareDown

     Description: Emulates teare down part of CTestThreadContainer::ExecutionThread method

	 Teare down is performed in main thread.

     Parameters: None
     
     Return Values: None

     Errors/Exceptions: None

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::TeareDown()
	{	
	iCurrentOperation = ETearDown;
	SetActive();
	CompleteRequest();
	iOperationOngoing.Wait();
	}

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

     Class: CTestThreadContainerRunner

     Method: CheckSignalFromSuspend

     Description: Checks if operation change signal was signaled from suspend state.

	 Main part of code is executed in main thread.

     Parameters: None
     
     Return Values: None

     Errors/Exceptions: None

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::CheckSignalFromSuspend()
	{
    if ( iSignalFromSuspend )
        {
        iSignalFromSuspend = EFalse;
        iTestThreadContainer->TestComplete( iReturnCode );
        }
	}

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

     Class: CTestThreadContainerRunner

     Method: IsReusable

     Description: Checks if test thread is reusable.

	 Checks if test thread is reusable.

     Parameters: None
     
     Return Values: True if TestThreadContainer is reusable.

     Errors/Exceptions: None

     Status: Draft
    
-------------------------------------------------------------------------------
*/
TBool CTestThreadContainerRunner::IsReusable()
	{
	return iReusable;
	}

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

     Class: CTestThreadContainerRunner

     Method: ExceptionHandler

     Description: Test thread exception handler.

	 Test thread exception handler.

     Parameters: TExcType aType: in: Exception type.
     
     Return Values: None

     Errors/Exceptions: None

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::ExceptionHandler ( TExcType aType )
	{
	// Kill the current thread, undertaker handles rest
	RThread current;
	current.Kill( aType );
	
	// This line is never executed, because thread has been killed.
	}

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

     Class: CTestThreadContainerRunner

     Method: RunL

     Description: RunL derived from CActive handles the completed requests.

	 RunL derived from CActive handles the completed requests.

     Parameters: None.
     
     Return Values: None.

     Errors/Exceptions: Leaves if one of the called method leavs.

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::RunL()
	{
	switch( iCurrentOperation )
		{
		case ESetup:
			{
		    TInt error( KErrNone );
		    
		    const TUint32 KAll = 0xFFFFFFFF;
		#ifndef __HIDE_IPC_V1__ // e.g. 7.0s, 8.0a
		    RThread currentThread;
		    currentThread.SetExceptionHandler( ExceptionHandler, KAll );
		#else // PlatSec used. Thread exception management is part of the User class.
		    User::SetExceptionHandler( ExceptionHandler, KAll );
		#endif // __HIDE_IPC_V1__

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

		    iTestThreadContainer = NULL;    
		    TRAPD( err,
		    	iTestThreadContainer = CTestThreadContainer::NewL( iTestModuleContainer, 
		    			iTestModuleContainer->ServerThreadId() );
		        );    
		    if( err != KErrNone )
		        {
		        Panic( ENullTestThreadContainer );
		        }

		    // Construct the logger
		    TName path = _L("C:\\logs\\testframework\\testserver\\");
		    TFileName name = _L("testserver_thread_");  
		    name.Append( iTestModuleContainer->TestModuleName() );

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

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

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

		    TRAP ( error, iTestThreadContainer->SetThreadLogger( CStifLogger::NewL( path, name,
		                                                            loggerSettings ) ) );

		    iReusable = ETrue;             // Is test module reusable?
		    iInitialized = EFalse;         // Is module initialized?
		    iSignalFromSuspend = EFalse;   // Send signal from suspend state?
		    
		    iReturnCode = KErrNone;			
			}
			break;
		case ERunOneIteration:
			{			
	        iReturnCode = KErrNone;
	        
	        switch ( iTestModuleContainer->OperationType() )
	            {
	            // Test module initialisation
	            case CTestModuleContainer::EInitializeModule:
	                {
	                __ASSERT_ALWAYS ( !iInitialized,
	                                  Panic( EReInitializingTestModule ) );

	                // Initialize module
	                if ( iTestThreadContainer->InitializeModuleInThread( iModule ) == KErrNone )
	                    {
	                    iInitialized = ETrue;
	                    }

	                iSignalFromSuspend = ETrue;
	                break;
	                }

	            // Test case enumeration
	            case CTestModuleContainer::EEnumerateInThread:
	                {
	                __ASSERT_ALWAYS ( iInitialized,
	                                  Panic( ETestModuleNotInitialized ) );
	                iReturnCode = iTestThreadContainer->EnumerateInThread();

	                iSignalFromSuspend = ETrue;
	                break;
	                }

	            // Free test case enumeration data
	            case CTestModuleContainer::EFreeEnumerationData:
	                {
	                __ASSERT_ALWAYS ( iInitialized,
	                                  Panic( ETestModuleNotInitialized ) );
	                iTestThreadContainer->FreeEnumerationDataInThread ();
	                
	                iSignalFromSuspend = ETrue;
	                break;
	                }

	            // Execute test case
	            case CTestModuleContainer::EExecuteTestInThread:
	                {
	                __ASSERT_ALWAYS ( iInitialized,
	                                  Panic( ETestModuleNotInitialized ) );
	                iReturnCode = iTestThreadContainer->ExecuteTestCaseInThread ();

	                iSignalFromSuspend = ETrue;
	                break;
	                }

	            // Exiting (i.e test server is unloading)
	            case CTestModuleContainer::EExit:
	                {
	                iReusable = EFalse;
	                break;
	                }

	            // Illegal state
	            default:
	                {
	                Panic( EInvalidTestModuleOperation );
	                }
	            }
			}
			break;
		case ETearDown:
			{
			iTestThreadContainer->DeleteTestModule();

		    // Close handle to module. No function calls to test
		    // module are possible after this line.
			iModule.Close();

		    // Delete logger    
			CStifLogger* threadLogger = iTestThreadContainer->GetThreadLogger();
			iTestThreadContainer->SetThreadLogger( NULL );
			delete threadLogger;
			threadLogger = NULL;

		    // Delete clean-up stack.
//		    delete tc;
//		    tc = NULL;
			
		    // Operation completed ( = Exit completed )
		    iTestThreadContainer->TestComplete( KErrNone );
		    
		    delete iTestThreadContainer;
			}
			break;
		}
		
	iCurrentOperation = ENone;
	iOperationOngoing.Signal();
	}

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

     Class: CTestThreadContainerRunner

     Method: Panic

     Description: Raises panic.

	 Raises panic.

     Parameters: TInt aReason: in: Panic reason.
     
     Return Values: None.

     Errors/Exceptions: None.

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::Panic( TInt aReason )
    {    
    RDebug::Print( _L("CTestThreadContainer::Panic %d"), aReason );    
    User::Panic( _L("CTestThreadContainer::Panic"), aReason );    
    }

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

     Class: CTestThreadContainerRunner

     Method: DoCancel

     Description: DoCancel derived from CActive handles the Cancel.

	 DoCancel derived from CActive handles the Cancel.

     Parameters: None.
     
     Return Values: None.

     Errors/Exceptions: None.

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::DoCancel()
	{
	}

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

     Class: CTestThreadContainerRunner

     Method: CompleteRequest

     Description: Complets current operation request.

     Complets current operation request, what causes execution of RunL method 
     in main thread of UITestServerStarter.


     Parameters: None.
     
     Return Values: None.

     Errors/Exceptions: None.

     Status: Draft
    
-------------------------------------------------------------------------------
*/
void CTestThreadContainerRunner::CompleteRequest()
	{
	iStatus = KRequestPending;
	TRequestStatus* statusPtr = &iStatus;		            	
	RThread mainThread;
	User::LeaveIfError( mainThread.Open( iMainThreadId ) );
	mainThread.RequestComplete( statusPtr, KErrNone );
	mainThread.Close();	
	}

// End of File
