// Copyright (c) 1996-2010 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// e32test\active\t_dtim.cpp
// Overview:
// Test delta timers. 
// API Information:
// CDeltaTimer.
// Details:
// - Create a delta timer and queue a number of timed events with different time intervals.
// The callback functions of the timed events perform various actions: 
// - Requeuing itself
// - Cancelling the previous or next timer
// - Doing nothing
// - Stopping the active scheduler
// - Verifies the timed events are run correctly and orderly
// - The callback for each timed event increments a counter each time they are run
// - The counters are checked to check how many times each callback has been called
// Platforms/Drives/Compatibility:
// All.
// Assumptions/Requirement/Pre-requisites:
// Failures and causes:
// Base Port information:
// 
//

#include <e32std.h>
#include <e32std_private.h>
#include <e32base.h>
#include <e32base_private.h>
#include <e32test.h>
#include <e32hal.h>
#include <e32def.h>
#include <e32def_private.h>

RTest test(_L("T_DTIM"));


TInt theResults[10];
TCallBack* theCallBacks;
TDeltaTimerEntry TheTimers[10];
CDeltaTimer* theTimer;

class CMyActiveScheduler : public CActiveScheduler
	{
public:
	void Error(TInt anError)const;
	static CMyActiveScheduler* NewL();
	};

void CMyActiveScheduler::Error(TInt /*anError*/) const
//
//
//
	{
	User::Panic(_L("MYActiveScheduler"),0);
	}

CMyActiveScheduler* CMyActiveScheduler::NewL()
	{
	return new(ELeave) CMyActiveScheduler;
	}

struct TDeltaTimerCallData
	{
	CDeltaTimer* iTimer;
	TDeltaTimerEntry *iTimers;
	TInt iIndex;
	};

TInt print(TAny* anArg)
//
// Null entry. Just prints and increments it's counter.
//
	{
	TInt index=(TInt)anArg;
	theResults[index]++;
	test.Printf(_L("Callback %d\r\n"),index);
	return 0;
	}

TInt cancelNext(TAny * anArg)
//
// Cancels the next entry - assumes it is valid.
//
	{
	TInt index=(TInt)anArg;
	theTimer->Remove(TheTimers[index+1]);
	return print(anArg);
	}

TInt requeue(TAny * anArg)
//
// Note that a requeue will run once every 200 ms until stop is called.
//
	{
	TTimeIntervalMicroSeconds32 tickPeriod;
	UserHal::TickPeriod(tickPeriod);
	const TInt K13Ticks = 13 * tickPeriod.Int();

	TInt index=(TInt)anArg;
	theTimer->Queue(K13Ticks*2/3,TheTimers[index]);
	return print(anArg);
	}

TInt requeuePrevious(TAny * anArg)
//
// Requeue the previous entry (assumes previous entry is valid handle)
//
	{
	TTimeIntervalMicroSeconds32 tickPeriod;
	UserHal::TickPeriod(tickPeriod);
	const TInt K13Ticks = 13 * tickPeriod.Int();

	TInt index=(TInt)anArg - 1;
	theTimer->Queue(K13Ticks,TheTimers[index]);
	return print(anArg);
	}

TInt cancel2ndFollowing(TAny * anArg)
//
// Assumes that 2nd following timer handle is valid.
//
	{
	TInt index=(TInt)anArg;
	theTimer->Remove(TheTimers[index+2]);
	return print(anArg);
	}

TInt stop(TAny * anArg)
//
// Stops the active schduler
//
	{
	TInt index=(TInt)anArg;
	theResults[index]++;
	test.Printf(_L("Callback %d, stopping\r\n"),index);
	CMyActiveScheduler::Stop();

	return 0;
	}

TInt E32Main()
//
//
//
	{
	COMPLETE_POST_BOOT_SYSTEM_TASKS();

	CMyActiveScheduler* s=NULL;
	TRAPD(ret,s=CMyActiveScheduler::NewL())
	test(ret==KErrNone);

	CActiveScheduler::Install(s);
	test.Title();
	test.Start(_L("Timer"));
	
	__KHEAP_MARK;

	TTimeIntervalMicroSeconds32 tickPeriod;
	UserHal::TickPeriod(tickPeriod);

	TRAP(ret,theTimer=CDeltaTimer::NewL(100, tickPeriod.Int()));
	test(ret==KErrNone);

	Mem::FillZ(theResults,10*sizeof(TInt));

	TCallBack callBacks[10]=
		{
		/* 0 */ TCallBack(print,(TAny*)0),
		/* 1 */ TCallBack(cancelNext,(TAny*)1),
		/* 2 */ TCallBack(print,(TAny*)2),	// Gets cancelled
		/* 3 */ TCallBack(print,(TAny*)3),		// Runs twice
		/* 4 */ TCallBack(requeuePrevious,(TAny*)4),
		/* 5 */ TCallBack(cancel2ndFollowing,(TAny*)5),
		/* 6 */ TCallBack(print,(TAny*)6),
		/* 7 */ TCallBack(cancelNext,(TAny*)7),	// Gets cancelled
		/* 8 */ TCallBack(requeue,(TAny*)8),	// Runs twice, once on the same RunL as the stop
		/* 9 */ TCallBack(stop,(TAny*)9),
		};

	theCallBacks=callBacks;
	for (TInt i=0;i<10;i++)
		TheTimers[i].Set(theCallBacks[i]);

	const TInt K13Ticks = 13 * tickPeriod.Int();

	theTimer->Queue(K13Ticks,TheTimers[0]);
	theTimer->Queue(2*K13Ticks,TheTimers[1]);
	theTimer->Queue(3*K13Ticks,TheTimers[2]);
	theTimer->Queue(4*K13Ticks,TheTimers[3]);
	theTimer->Queue(5*K13Ticks,TheTimers[4]);
	theTimer->Queue(6*K13Ticks,TheTimers[5]);
	theTimer->Queue(7*K13Ticks,TheTimers[6]);
	theTimer->Queue(8*K13Ticks,TheTimers[7]);
	theTimer->Queue(9*K13Ticks,TheTimers[8]);
	theTimer->Queue(10*K13Ticks,TheTimers[9]);

	CActiveScheduler::Start();

	test(theResults[0]==1);
	test(theResults[1]==1);
	test(theResults[2]==0);
	test(theResults[3]==2);
	test(theResults[4]==1);
	test(theResults[5]==1);
	test(theResults[6]==1);
	test(theResults[7]==0);
	test(theResults[8]==2);
	test(theResults[9]==1);

	delete theTimer;

	__KHEAP_MARKEND;

	test.End();
	return 0;
	}
