// UB_ACT.CPP
//
// Copyright (c) 1995-1999 Symbian Ltd.  All rights reserved.
//

#include "ub_std.h"

#pragma warning( disable : 4705 )	// statement has no effect
EXPORT_C CActive::CActive(TInt aPriority)
//
// Constructor
//
	{

//	iActive(EFalse)
//	iLink.iNext=NULL; // Mark request as not on the event queue
	iLink.iPriority=aPriority;
	__DECLARE_NAME(_S("CActive"));
	}
#pragma warning( default : 4705 )

EXPORT_C CActive::~CActive()
//
// Destructor
//
	{

	__ASSERT_ALWAYS(!iActive,Panic(EReqStillActiveOnDestruct));
	if (IsAdded())
		iLink.Deque();
	}

EXPORT_C void CActive::Cancel()
//
// Cancel a request
//
	{

	if (iActive)
		{
		DoCancel();
		User::WaitForRequest(iStatus);
    	iActive=EFalse;
		}
	}

EXPORT_C void CActive::Deque()
//
// Remove the object from the active scheduler.
//
	{

	__ASSERT_ALWAYS(IsAdded(),Panic(EActiveNotAdded));
	Cancel();
	iLink.Deque();
	}

EXPORT_C void CActive::SetActive()
//
// Set the current request active.
//
	{

	__ASSERT_ALWAYS(!iActive,Panic(EReqAlreadyActive));
	__ASSERT_ALWAYS(IsAdded(),Panic(EActiveNotAdded));
	iActive=ETrue;
	}

EXPORT_C void CActive::SetPriority(TInt aPriority)
//
// Set a new priority for the active object
//
	{

	__ASSERT_ALWAYS(!iActive,Panic(ESetPriorityActive));
	iLink.iPriority=aPriority;
	if (IsAdded())
		{
		Deque();
		iLink.iNext=NULL; // Make this not added
		CActiveScheduler::Add(this);
		}
	}

EXPORT_C CIdle* CIdle::New(TInt aPriority)
//
// Create a new idle object.
//
	{

	CIdle *pI=new CIdle(aPriority);
	if (pI!=NULL)
		CActiveScheduler::Add(pI);
	return(pI);
	}

EXPORT_C CIdle* CIdle::NewL(TInt aPriority)
//
// Create a new idle object.
//
	{

	CIdle *pI=new(ELeave) CIdle(aPriority);
	CActiveScheduler::Add(pI);
	return(pI);
	}

EXPORT_C CIdle::CIdle(TInt aPriority)
//
// Constructor.
//
	: CActive(aPriority)
	{}

EXPORT_C CIdle::~CIdle()
//
// Destructor.
//
	{

	Cancel();
	}

EXPORT_C void CIdle::Start(TCallBack aCallBack)
//
// Start the idler.
//
	{

	iCallBack=aCallBack;
	TRequestStatus *pS=(&iStatus);
	User::RequestComplete(pS,0);
	SetActive();
	}

EXPORT_C void CIdle::RunL()
//
// Called when nothing of a higher priority can be scheduled.
//
	{

	if (iCallBack.CallBack())
		Start(iCallBack);
	}

EXPORT_C void CIdle::DoCancel()
//
// Cancel
//
	{
	}

EXPORT_C void CAsyncOneShot::Call()
//
// Queue the active object to be run once
//
// CAsyncOneShot never needs to enter Active and KRequestPending state
// A CAsyncOneShot is always either not active or active and ready to run
//
	{
	__ASSERT_DEBUG(IsAdded(),Panic(ECAsyncOneShotNotAdded));
	TRequestStatus *pS=(&iStatus);
	SetActive();
	iThread.RequestComplete(pS,0);
	}

EXPORT_C void CAsyncOneShot::DoCancel()
//
// Cancel any existing Call
//
	{
	// Empty
	}

EXPORT_C CAsyncOneShot::CAsyncOneShot(TInt aPriority)
//
// C'tor
//
	:CActive(aPriority)
	{
	Setup();
	}

void CAsyncOneShot::Setup()
//
// ensures that we are added to the Scheduler.
//
	{

	iThread.Duplicate(RThread());

	// Add ourself to the current active scheduler
	// This is because we might be being used as an inter thread call
	// we need to make sure that we're on the correct scheduler for
	// the RThread were going to duplicate.
	CActiveScheduler::Add(this);
	}


EXPORT_C CAsyncOneShot::~CAsyncOneShot()
//
//
//
	{
	Cancel();
	iThread.Close();
	}

EXPORT_C CAsyncCallBack::CAsyncCallBack(TInt aPriority)
	: CAsyncOneShot(aPriority), iCallBack(NULL)
	{
	__DECLARE_NAME(_S("CAsyncCallBack"));
	}


EXPORT_C CAsyncCallBack::CAsyncCallBack(TCallBack& aCallBack, TInt aPriority)
	: CAsyncOneShot(aPriority), iCallBack(aCallBack)
	{
	__DECLARE_NAME(_S("CAsyncCallBack"));
	}

EXPORT_C void CAsyncCallBack::CallBack()
//
// TCallBack parameterised version of CAsyncOneShot
//
	{
	if (!IsActive())
		Call();
	}

EXPORT_C void CAsyncCallBack::Set(TCallBack& aCallBack)
//
// Set the user function
//
	{
	__ASSERT_ALWAYS(!IsActive(), Panic(ECAsyncCBIsActive));
	iCallBack = aCallBack;
	}

void CAsyncCallBack::RunL()
//
// Call user function
//
	{
	iCallBack.CallBack();
	}

EXPORT_C CActiveScheduler::CActiveScheduler()
//
// Constructor.
//
	: iActiveQ(_FOFF(CActive,iLink))
	{

//	iLevel=0;
	__DECLARE_NAME(_S("CActiveScheduler"));
	}

EXPORT_C CActiveScheduler::~CActiveScheduler()
//
// Destructor.
//
	{

	while (!iActiveQ.IsEmpty())
		iActiveQ.First()->Deque();
	if (Exec::ActiveScheduler()==this)
		Exec::SetActiveScheduler(NULL);
	}

EXPORT_C void CActiveScheduler::Install(CActiveScheduler *aManager)
//
// Install the request manager.
//
	{

	if (aManager!=NULL)
		__ASSERT_ALWAYS(Exec::ActiveScheduler()==NULL,Panic(EReqManagerAlreadyExists));
	Exec::SetActiveScheduler(aManager);
	}

EXPORT_C void CActiveScheduler::Add(CActive *aRequest)
//
// Add a request to the managers queue.
//
	{

	CActiveScheduler *pS=Exec::ActiveScheduler();
	__ASSERT_ALWAYS(pS!=NULL,Panic(EReqManagerDoesNotExist));
	__ASSERT_ALWAYS(aRequest,Panic(EReqNull));
	__ASSERT_ALWAYS(!aRequest->IsAdded(),Panic(EReqAlreadyAdded));
	pS->iActiveQ.Add(*aRequest);
	}

EXPORT_C void CActiveScheduler::WaitForAnyRequest()
//
// Wait for any event to occur.
//
	{


	User::WaitForAnyRequest();
	}

#ifndef __CACTIVESCHEDULER_MACHINE_CODED__
EXPORT_C void CActiveScheduler::Start()
//
// Start despatching request completions.
//
	{

	CActiveScheduler *pS=Exec::ActiveScheduler();
	__ASSERT_ALWAYS(pS!=NULL,Panic(EReqManagerDoesNotExist));
	TDblQueIter<CActive> q(pS->iActiveQ);
	TInt level=pS->iLevel++;
	while (pS->iLevel>level)
		{
		pS->WaitForAnyRequest();
		q.SetToFirst();
		FOREVER
			{
			CActive *pR=q++;
			__ASSERT_ALWAYS(pR!=NULL,Panic(EReqStrayEvent));
			if (pR->IsActive() && pR->iStatus!=KRequestPending)
				{
				pR->iActive=EFalse;
				TRAPD(r,pR->RunL());
				if (r!=KErrNone)
					pS->Error(r);
				break;
				}
			}
		}
	}
#else
GLDEF_C void PanicReqMgrNotExist()
	{
	Panic(EReqManagerDoesNotExist);
	}

GLDEF_C void PanicStrayEvent()
	{
	Panic(EReqStrayEvent);
	}
#endif

EXPORT_C void CActiveScheduler::Stop()
//
// Stop despatching request completions.
//
	{

	CActiveScheduler *pS=Exec::ActiveScheduler();
	__ASSERT_ALWAYS(pS!=NULL,Panic(EReqManagerDoesNotExist));
	pS->iLevel--;
	__ASSERT_ALWAYS(pS->iLevel>=0,Panic(EReqTooManyStops));
	}

EXPORT_C CActiveScheduler *CActiveScheduler::Current()
//
// Return the currently installed active scheduler.
//
	{

	return(Exec::ActiveScheduler());
	}

EXPORT_C void CActiveScheduler::Error(TInt /*anError*/) const
//
// Default error, called when a RunL method leaves
//
	{

	Panic(EReqActiveObjectLeave);
	}
