import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
/*
 * TimeResolution.java
 *
 * Created on May 2, 2007, 3:38 PM
 *
 * Copyright (c) 2007, Sun Microsystems, Inc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the TimingFramework project nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 *
 * @author Chet
 */
public class TimeResolution implements ActionListener {
    
    private static int INCREMENT = 5;
    private static int MAX = 50;
    
    /**
     * Measures how much time has elapsed according to both currentTimeMillis()
     * and nanoTime() at each interval. Note that the time reported for 
     * sleep() may not be accurate since the internal sleep timer may not
     * have the appropriate resolution to sleep for the requested time.
     * The main utility of this function is to compare the two timing
     * functions, although it is also interesting to see how the measured
     * time varies from the sleep() time.
     */
    private void measureTimeFunctions(int increment, int max) {
        long startTime = System.currentTimeMillis();
        long startNanos = System.nanoTime();
        long elapsedTimeActual = 0;
        long elapsedTimeMeasured = 0;
        long elapsedNanosMeasured = 0;
        System.out.printf("sleep   currentTimeMillis   nanoTime\n");
        while (elapsedTimeActual < max) {
            try {
                Thread.sleep(increment);
            } catch (Exception e) {}
            long currentTime = System.currentTimeMillis();
            long currentNanos = System.nanoTime();
            elapsedTimeActual += increment;
            elapsedTimeMeasured = currentTime - startTime;
            elapsedNanosMeasured = (currentNanos - startNanos) / 1000000;
            System.out.printf(" %3d           %4d          %4d\n",
                    elapsedTimeActual, elapsedTimeMeasured, elapsedNanosMeasured);
        }
    }

    /**
     * This method measures the actual time slept, compared to the requested
     * sleep() time. We run many iterations for each value of sleep() to
     * get more accurate timing values; this accounts for possible 
     * inaccuracies of our nanoTime() method for small time differences.
     */
    private void measureSleep() {
        System.out.printf("                                 zmierzony\n");
        System.out.printf("czas sleep   iteracje   czas całkowity   na sleep\n");
        for (int sleepTime = 0; sleepTime <= 20; ++sleepTime) {
            int iterations = (sleepTime == 0) ? 10000 : (1000 / sleepTime);
            long startTime = System.nanoTime();
            for (int i = 0; i < iterations; ++i) {
                try {
                    Thread.sleep(sleepTime);
                } catch (Exception e) {
                }
            }
            long endTime = System.nanoTime();
            long totalTime = (endTime - startTime) / 1000000;
            float calculatedSleepTime = totalTime / (float)iterations;
            System.out.printf("   %2d          %5d         %4d         %5.2f\n", 
                    sleepTime, iterations, totalTime, calculatedSleepTime);
        }
    }

    /**
     * This method is like the measureSleep() method above, only for the
     * wait() method instead of sleep().
     */
    private synchronized void measureWait() {
        System.out.printf("                                zmierzony\n");
        System.out.printf("czas wait    iteracje   czas całkowity    na wait\n");
        for (int sleepTime = 1; sleepTime <= 20; ++sleepTime) {
            int iterations = (sleepTime == 0) ? 10000 : (1000 / sleepTime);
            long startTime = System.nanoTime();
            for (int i = 0; i < iterations; ++i) {
                try {
                    wait(sleepTime);
                } catch (Exception e) {
                    System.out.println("Exception: " + e);
                    Thread.dumpStack();
                }
            }
            long endTime = System.nanoTime();
            long totalTime = (endTime - startTime) / 1000000;
            float calculatedSleepTime = totalTime / (float)iterations;
            System.out.printf("  %2d          %5d         %4d          %5.2f\n", 
                    sleepTime, iterations, totalTime, calculatedSleepTime);
        }
    }
    
    // Variables used in measurement of Swing timer
    int timerIteration = 0;
    int iterations = 0;
    Timer timer;
    long startTime, endTime;
    int sleepTime;
    
    /**
     * This method is called during the execution of the Swing timer.
     */
    public void actionPerformed(ActionEvent ae) {
        if (++timerIteration > iterations) {
            timer.stop();
            timerIteration = 0;
            endTime = System.nanoTime();
            long totalTime = (endTime - startTime) / 1000000;
            float calculatedDelayTime = totalTime / (float)iterations;
            System.out.printf("  %2d          %5d         %5d         %5.2f\n", 
                    sleepTime, iterations, totalTime, calculatedDelayTime);
        }
    }
       
    /**
     * This method measures the accuracy of the Swing timer, which is 
     * internally dependent upon both the internal timing mechanisms
     * (either currentTimeMillis() or nanoTime()) and the wait() method.
     * So the results we see here should be predictable from the results
     * we see in the other measurement methods.
     */
    public void measureTimer() {
        System.out.printf("                                  zmierzony\n");
        System.out.printf("czas Timer   iteracje   czas całkowity   na Timer\n");
        for (sleepTime = 0; sleepTime <= 20; ++sleepTime) {
            iterations = (sleepTime == 0) ? 1000 : (1000 / sleepTime);
            timerIteration = 1;
            timer = new Timer(sleepTime, this);
            startTime = System.nanoTime();
            timer.start();
            while (timerIteration > 0) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {}
            }
        }
    }

    /**
     * Execute the various timer resolution tests.
     */
    public static void main(String args[]) {
        TimeResolution timeResolution = new TimeResolution();
        timeResolution.measureTimer();
//        timeResolution.measureTimeFunctions(INCREMENT, MAX);
//        timeResolution.measureSleep();
//        timeResolution.measureWait();
    }
    
}
