/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (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.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */
package com.queplix.core.client.app;

import com.google.gwt.user.client.Timer;

import java.util.ArrayList;

/**
 * Lengthy Task Manager. Registers lengthy tasks (those that run long enough
 * to be visible by end users) and notifies listeners when those tasks
 * start and end. Used primarily for 'application is busy' indication purposes.
 *
 * @author Sultan Tezadov
 * @since 15 Nov 2006
 */
public class LengthyTaskManager {

    public interface Runnable {
        public void run();
    }

    // ------------------------- Lengthy Task events ---------------------------
    public static interface LengthyTaskListener {
        public void onLengthyTaskStart();

        public void onLengthyTaskEnd();
    }

    private static ArrayList listeners = new ArrayList();

    public static void addLengthyTaskListener(LengthyTaskListener listener) {
        listeners.add(listener);
    }

    private static void fireLengthyTaskStart() {
        for(int i = 0; i < listeners.size(); i++) {
            LengthyTaskListener listener = (LengthyTaskListener) listeners.get(
                    i);
            listener.onLengthyTaskStart();
        }
    }

    private static void fireLengthyTaskEnd() {
        for(int i = 0; i < listeners.size(); i++) {
            LengthyTaskListener listener = (LengthyTaskListener) listeners.get(
                    i);
            listener.onLengthyTaskEnd();
        }
    }
    // ---------------------- End of Lengthy Task events -----------------------

    private static volatile int runningTasks;

    /**
     * Warning: call to this method should be the last is the sequence
     * of statements; otherwise the sequence will continue before this task
     * is run.
     */
    public static void runLengthyTask(final Runnable task) {
        runningTasks++;
        if(runningTasks == 1) { // the first task started
            fireLengthyTaskStart();
            yieldAndRun(new Runnable() {
                public void run() {
                    doRunLengthyTask(task);
                }
            });
        } else {
            doRunLengthyTask(task);
        }
    }

    private static void doRunLengthyTask(final Runnable task) {
        try {
            task.run();
        } finally {
            runningTasks--;
            if(runningTasks == 0) {
                fireLengthyTaskEnd();
            }
        }
    }

    /**
     * Makes the browser refresh the displayed area prior to running
     * long tasks. Primarily used to display busy indicators.
     * Warning: call to this method should be the last is the sequence
     * of statements; otherwise the sequence will continue before this task
     * is run.
     *
     * @param runnable the long running task that will be started once
     *                 the browser refreshed the displyed area.
     */
    public static void yieldAndRun(final Runnable runnable) {
        Timer timer = new Timer() {
            public void run() {
                runnable.run();
            }
        };
        timer.schedule(50);
    }
}
