/*
 * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the
 * License at http://www.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.notification;

import java.util.TimerTask;
import java.util.Date;


/**
 * This class serves as a container for a TimerTask that can be
 * dispatched at any time. After creation, the first run is invoked
 * with start(), thereafter with restart().
 *
 * The TimerTasks to be tested in the context of this package are
 * RequestManager, DigestQueueManager, SimpleQueueManger. Calling
 * the respective run method once, assumes that the Manager does
 * its job once and then exits. The ManagerDispatcher counts the
 * cycles of execution and waits until the next run.
 *
 * Note, that this class represents a reusable Thread without using
 * the deprecated suspend/resume methods. The difference to java.
 * util.Timer is that execution is triggered explicitly rather than
 * scheduled periodically.
 *
 * @author Stefan Deusch
 * @version $Id: //core-platform/dev/test/src/com/arsdigita/notification/ManagerDispatcher.java#8 $
 *
 */

public class ManagerDispatcher extends Thread {

    public static final String versionId = "$Id: //core-platform/dev/test/src/com/arsdigita/notification/ManagerDispatcher.java#8 $ by $Author: dennis $, $DateTime: 2004/04/07 16:07:11 $";

    TimerTask mgr;
    private boolean suspendRequested;
    private int cycle;
    private Date start;


    /**
     * construct a ManagerDispatcher for a TimerTask
     */
    public ManagerDispatcher(TimerTask m) {
        this.mgr = m;
        start = new Date();
    }

    /*
     * suspend thread
     */
    public void requestSuspend() {
        suspendRequested = true;
    }

    private synchronized void checkSuspend() throws InterruptedException {
        while(suspendRequested)
            wait();
    }


    /**
     * re-run thread for one cycle
     */
    public synchronized void restart() {
        suspendRequested = false;
        notify();                // order of calling is relevant here!
    }


    /**
     * run method executes one cycle of the assoociated TimerTask
     */
    public synchronized void run() {
        while(true) {
            try {
                checkSuspend();
                cycle++;
                mgr.run();
                requestSuspend();
            } catch(InterruptedException e) { }
        }
    }

    /**
     * wait for the currently running cycle to finish; needed to synchronize
     * with calling stack for tests to have up-to-date results of TimerTask.
     */
    public void waitCycle(){
        int maxwait = 10;
        float wait = 0;
        try {
            while(!suspendRequested && wait<=maxwait) {
                Thread.sleep(200);
                wait += 0.2;
            }
        } catch(InterruptedException e){}
    }

    /**
     * serves public information on since when this thread is up, and how many
     * cycles it cranked through the associated TimerTask
     */
    public String getInfo() {
        float upmin = (float)((new Date().getTime() - start.getTime())/60000.0);
        String info = "Manager Dispatcher for "+mgr.getClass().getName()+"\n"+
                          "creation date    : "+start+"\n"+
                          "uptime [min]     : "+upmin+"\n"+
                          "cycles completed : "+cycle+"\n";

        return info;
    }

    /**
     * @return how many times this Thread has been invoked
     */
    public int getCycles() {
        return cycle;
    }

}
