package com.fujitsu.iflowqa.testframe;

/**
* The purpose of SafeSleep is to make a convenient way to "wait" during test routines.
* It does so the proper way by:
*
* 1. Specify a maximum sleep period in seconds which it keeps track of
* 2. offering a method that sleeps for short periods (100ms "naps") up to the maximum
* 3. catches and handles sleep exceptions that can occur simplifying the code.
* 4. Provides a consistent way to report timeout situations
*
* Here is the typical usage pattern.  Create a sleeper with a message which indicates
* what condition you will wait for. Create a loop testing the condition that you are 
* waiting for.  Inside the loop call nap(), which will throw an exception if the 
* timeout is up.  The exception will include the string passed in the constructor.
* The code looks like this:
* <pre>
*    SafeSleep sleeper = new SafeSleep("Waiting for the 'operation' to be 'ready'");
*    while ( operation() != ready ) {
*        sleeper.nap();
*    }
* </pre>
*
* The one argument constructor shown above is the the preferred constructor. It uses
* a default 30 second timeout. Most operations should not take more that 30 seconds.
* Also, the SafeSleep will not sleep the full 30 seconds, but will take short naps of 
* 100ms till the condition is satisfied. So this constructor is suitable for most situations.
*/

public class SafeSleep
{
    String msg;                 //the message to report upon exceeding
    long   timeout;             //the time in milliseconds from 1970
    int    period;              //the original number of seconds
    final int napPeriod=100;    //milliseconds

    /**
     * Default constructor. Creates a SafeSleep object with 30 second timeout and no message
     */
    public SafeSleep()
    {
        this(30, null);
    }
    
    /**
     * This is the preferred constructor. Creates a SafeSleep object with 30 second timeout 
     * and the specified message.
     */
    public SafeSleep(String message)
    {
        this(30, message);
    }
    
    /**
     * Creates a SafeSleep object with the specified timeout and the specified message. 
     * Use this constructor if a timeout other than 30 seconds is needed. Otherwise use the 
     * preferred one argument constructor.   
     */
    public SafeSleep(int seconds, String message)
    {
        msg = message;
        period = seconds;
        timeout = System.currentTimeMillis() + (seconds*1000);
    }

    /**
     * Test whether the time period has been exceeded.
     */
    private boolean exceeded()
    {
        if (System.currentTimeMillis() > timeout) {
            return true;
        }
        return false;
    }

    /**
     * Sleeps for short period of time (100ms by default)
     * Throws an exception when the time period has been exceeded.
     */
    public void nap()
        throws Exception
    {
        if (exceeded()) {
            throw new Exception(period+" second wait timed out: "+msg);
        }
        Thread.sleep(napPeriod);
    }
}

