/**
 * Classes ITimingTestStopwatch and IStartStopTimingTest: General timing measurement classes.
 *
 * ITimingTestStopwatch provides client-controllable timing services for TStartStopTimingTest.
 * IStartStopTimingTest is an abstract framework class derived from ITimingTest. Clients should
 * write derived classes of IStartStopTimingTest to accomplish timing measurements too complicated
 * to achieve with ITimingTest. TStartStopTimingTest is less accurate than ITimingTest, so it
 * should not be used if ITimingTest can be used.
 *
 * @package Test Framework
 * @category Testing
 *
 * @author Alan Liu
 * @task Initial Test Framework
 * @author Esther Tong
 * @task TestFrameworkLite
 * @author David McCusker, Christoper Miller, Carol Widra, and Kwansook Nam
 * @task Many of the other Contributors to TestFramework
 *
 * @copyright
 *      IBM Open Class Library
 *      (C) Copyright International Business Machines Corporation 1997
 *      Licensed Material - Program-Property of IBM - All Rights Reserved.
 *
 */
// Revision: 04 1.6.1.4 source/core/testfw/issttest.hpp, testfw, ioc.v400, 980918 
//

#ifndef _ISSTTEST_
#define _ISSTTEST_

#include "itimetst.hpp"

#if __IBMCPP__ >= 400
#pragma namemangling(compat)
#endif

class ISimpleClock;
class ITimingTestStopwatch;

#pragma enum(4)
#pragma pack(push,4)

//------------------------------------------------------------------------------
// ITimingTestStopwatch
//------------------------------------------------------------------------------

/**
 * ITimingTestStopwatch acts as a client-controllable stopwatch for the IStartStopTimingTest class.
 */
class ITimingTestStopwatch {
public:


/** @group Constructors, Destructors, and Assignment Operators */

/**
 * Constructor.
 *
 * Make a new stopped & reset stopwatch.
 */
ITimingTestStopwatch();


/**
 * Destructor.
 */
~ITimingTestStopwatch();


/**
 * Copy Constructor.
 */
ITimingTestStopwatch(const ITimingTestStopwatch&);


/**
 * Standard Assignment Operator.
 */
ITimingTestStopwatch& operator=(const ITimingTestStopwatch&);


/** @group stopwatch functions */


/**
 * Starts a stopwatch without resetting it, so that time can be accumulated into the stopwatch.
 */
void start();                    // Starts or resumes stopwatch


/**
 * Stops time measurements, but does not reset the stopwatch.
 */
void stop();

//---------------------------------------------------------------------------
private:
void reset();                    // Resets stopwatch to 0; does NOT stop
void elapsedTime(double&);       // Return time elapsed
void copyDataMembers(const ITimingTestStopwatch&);

ISimpleClock* fClock;
double fElapsedTime;
double fStartTime;
double fScratchTime;             // To avoid ct time
bool fIsRunning;
long fStartCount;                // Incremented on each functional call to start
long fStopCount;                 // Incremented on each functional call to stop

    friend class IStartStopTimingTest;

};

//-----------------------------------------------------------------------------
// IStartStopTimingTest
//-----------------------------------------------------------------------------

/**
 * IStartStopTimingTest is an abstract framework class for timing measurements
 * too complicated to do with ITimingTest. It is a subclass of ITimingTest
 * with:
 *
 *<PRE>
 *      (1) Lower precision, and
 *      (2) The ability to start and stop the timer.
 *</PRE>
 * It is used when the timer needs to be started and stopped multiple times.
 * Because this results in a loss of precision, us ITimingTest whenever possible.
 *
 * To use, subclass and override startStopTimingTest much as you would override
 * ITimingTest::timingTest.
 *
 */
class IStartStopTimingTest : public ITimingTest {
public:
//-------------------------------------------------------------------------
// Canonical methods
//-------------------------------------------------------------------------


/** @group Construction, Destruction, and Assignment */

/**
 * Destructor.
 */
virtual ~IStartStopTimingTest();


/**
 * Copy Constructor.
 *
 * @param other IStartStopTimingTest to be copied
 */
IStartStopTimingTest(const IStartStopTimingTest& other);


/**
 * Standard assignment operator.
 */
IStartStopTimingTest& operator=(const IStartStopTimingTest& other);

protected:
//-------------------------------------------------------------------------
// Canonical methods
//-------------------------------------------------------------------------


/**
 * Default Constructor.
 */
IStartStopTimingTest();


/**
 * Constructor that explicitly sets timing count and sample count.
 *
 * @param timingCount     Explicit timing count
 * @param sampleCount     Explicit sample count
 *
 */
IStartStopTimingTest(unsigned long timingCount, unsigned long sampleCount);


//-------------------------------------------------------------------------
// ITimingTest overrides
//-------------------------------------------------------------------------

// virtual void timingSetup();   // Inherited unchanged from ITimingTest


/**
 * This method is analogous to ITimingTest::timingTest.  Subclasses override this method to:
 *
 *<PRE>
 *     - do necessary setup
 *     - start the timer (which is passed into the method)
 *     - do the timed operation
 *     - stop the timer
 *     - do necessary cleanup
 *
 * For example
 *     {
 *       // Setup the test
 *       timer.start();
 *       // Do the operation to be timed
 *       // ...
 *       // Stop the timer
 *       timer.stop();
 *       // Cleanup
 *     };
 *</PRE>
 *
 * If necessary, the timer can be started and stopped more than once, but this
 * should be avoided if at all possible.
 *
 * The startStopTimingTest method should always assume the timer is stopped
 * on entry into the method, and should always stop the timer before exiting
 * the method.
 *
 * @param ITimingTestStopwatch     An ITimingTestStopwatch object
 *
 */
virtual void startStopTimingTest(ITimingTestStopwatch&) = 0; // Subclass must override


// virtual void timingCleanup(); // Inherited unchanged from ITimingTest


/**
 * This class calls the timer repeatedly to calibrate times and account for the
 * overhead involved in starting or stoppping the timer.  If your startStopTimingTest
 * method starts and stops the timer more than once then override
 * emptyStartStopTimingTest.  In your version, start and stop the timer as many
 * times as you do in startStopTimingTest.  The class will use this method to
 * calibrate times and to account for the overhead involved in starting or stopping
 * the timer.
 *
 * @param ITimingTestStopwatch      This is the stopwatch object which clients should
 *                                  start and stop. In your overridden version, start
 *                                  and stop this object as many times as you do in
 *                                  startStopTimingTest, for example: Start, stop, start,
 *                                  stop. IStartStopTimingTest uses this function to
 *                                  calibrate times and account for the overhead
 *                                  involved in starting or stopping the timer.
 *
 */
virtual void emptyStartStopTimingTest(ITimingTestStopwatch&);


//-------------------------------------------------------------------------
// Advanced Subclass Specialization Methods: Authorized Personnel Only
//-------------------------------------------------------------------------


/** @group Specialization Methods */

/**
 * Determine the time it takes to run one sample.
 *
 * @return theTime    The time to run the one sample
 */
virtual double oneSample();


/**
 * Run the startStopTimingTest without performing the timing.
 * (e.g., execute only timingSetup, startStopTimingTest,  and
 * timingCleanup). Useful to debug the startStopTimingTest without
 * concern for the timing aspects.
 */
virtual void   doUntimedTest();


/**
 * Runs an empty sample.
 * Useful to determine the amount of time necessary
 * for the overhead of doing the timing.
 *
 * @return theTime     The time to run the empty sample
 */
virtual double oneEmptySample();


/**
 * Returns the sampling error.
 *
 * For start-stop tests, the sampling error per sample is (k alpha), where
 * k is the number of calls to start or stop per call to startStopTimingTest.
 *
 * @return double     The sampling error
 */
virtual double samplingErrorMicroseconds() const;


//-------------------------------------------------------------------
private:
virtual void timingTest();       // No function; just to make compiler happy

ITimingTestStopwatch fStopwatch;
long fStopwatchOverhead;         // count of calls to start/stop


};

#pragma pack(pop)
#pragma enum(pop)

#if __IBMCPP__ >= 400
#pragma namemangling()
#endif

#endif // _ISSTTEST_
