/*
* Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
* Contact: http://www.qt-project.org/legal
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/


#include "threadbase.h"
_LIT(KSemaphoreNameOne, "SemaphoneNameOne");
_LIT(KSemaphoreNameTwo, "SemaphoneNameTwo");
const TInt KMaxHeapSize=0x400; // 1024 

///////////////////////////////////////////////////////////////////////////////
/* CThreadBase - Implementation                                              */
CThreadBase::CThreadBase()
	{
	}

CThreadBase::~CThreadBase()
	{
	iThread.Close();
	CloseSemaphore();
	}

void CThreadBase::Go()
	{
	iThread.Create( ThreadName(), CThreadBase::ThreadFunction, KDefaultStackSize, 0x2000, 0x20000, this );
	iThread.Logon( iThreadStatus );
	iThread.Resume();
	}
	
void CThreadBase::WaitForCompetion()
	{
	User::WaitForRequest( iThreadStatus );
	}

void CThreadBase::SetUpTestL( const TDesC& aThreadName )
	{
	// Set's up extra resources.
	CConsoleBase* console = NULL;
	TSize size;

	// Create and name an RTest
	iTest = new(ELeave) RTest(aThreadName);
	iTest->Start(_L("Starting test"));

	// Position our console window
	size = iTest->Console()->ScreenSize();
	size.iWidth = size.iWidth - 4;
	size.iHeight = (size.iHeight / 2) - 3;

	console = Console::NewL(aThreadName, size);
	delete const_cast<RTest*>(iTest)->Console();
	
	iTest->SetConsole(console);
	console->ClearScreen();
	}

void CThreadBase::TakeDownTest()
	{
	iTest->Close();
	delete iTest;
	iTest = NULL;
	}


void CThreadBase::OpenSemaphore()
	{
	TInt success = KErrNone;

	success = iSemaphoreSignal.OpenGlobal( KSemaphoreNameOne );
	if ( success == KErrNotFound )
		{
		iSemaphoreSignal.CreateGlobal( KSemaphoreNameOne, 0 );
		success = KErrNone;
		}


	success = iSemaphoreWait.OpenGlobal( KSemaphoreNameTwo );
	if ( success == KErrNotFound )
		{
		iSemaphoreWait.CreateGlobal( KSemaphoreNameTwo, 0 );
		}

	iSemaphoreOpen = ETrue;
	}

void CThreadBase::CloseSemaphore()
	{
	if (iSemaphoreOpen)
		{
		iSemaphoreSignal.Close();
		iSemaphoreWait.Close();
		}

	iSemaphoreOpen = EFalse;
	}

void CThreadBase::SyncronizeSignal()
	{
	iSemaphoreSignal.Signal();
	iSemaphoreWait.Wait();
	iSemaphoreSignal.Signal();
	}

void CThreadBase::SyncronizeWait()
	{
	iSemaphoreSignal.Wait();
	iSemaphoreWait.Signal();
	iSemaphoreSignal.Wait();
	}


void CThreadBase::RandomDelay(TInt aMax, TInt aMin) const 
	{
	TInt delay;
	TTime timeNow;
	TInt64 seed;
	TReal randomNumber;

	timeNow.UniversalTime();
	seed = timeNow.Int64();
	randomNumber = Math::FRand( seed );
	delay = static_cast<TInt>( (randomNumber * static_cast<TReal>(aMax)) + aMin ) ;
	delay = delay % aMax;

	User::After( delay );
	}

void CThreadBase::DoRunThreadL()
	{
	CActiveScheduler*  scheduler = NULL;
	scheduler = new (ELeave) CActiveScheduler;
	CleanupStack::PushL(scheduler);
	CActiveScheduler::Install(scheduler);

	OpenSemaphore();
	SetUpTestL( ThreadName() );
	
	ThreadL();
	
	TakeDownTest();
	CloseSemaphore();
	
	CleanupStack::PopAndDestroy(scheduler);
	}

TInt CThreadBase::RunThread()
	{
	
	TInt retval = KErrNone;
	
    iCleanup = CTrapCleanup::New();
    
	if	(iCleanup)
		{	
		TRAP(retval, DoRunThreadL());
		}
	else
		{
		retval = KErrNoMemory;
		}
		
    delete iCleanup;
    iCleanup = NULL;
	return retval;	
	}

TInt CThreadBase::ThreadFunction(TAny* aMe)
	{
	CThreadBase* me = static_cast<CThreadBase*>(aMe);
	return me->RunThread();
	}
