/*
 *  
 *
 * Copyright  1990-2006 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation. 
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt). 
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA 
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions. 
 */

package com.sun.midp.util;

import javax.microedition.lcdui.Display;

/**
 * An adaptor class that lets a caller synchronize with the event thread. The
 * invokeAndWait() method enqueues an event using Display.callSerially() and
 * blocks the caller. When the event reaches the front of the queue, it calls
 * this object's run() method on the event thread, and unblocks the caller.
 *
 * Clients may override the run() method if they wish to provide specialized 
 * behavior that must be run on the event thread. If run() is not overridden, 
 * invokeAndWait() simply blocks until the event thread has processed the 
 * event. This is useful for callers that need to wait until after an event 
 * has been processed.
 *
 * The invokeAndWait() method must not be called on the event thread, 
 * otherwise the system will deadlock.
 */
public class SerialCallback implements Runnable {

    Display dpy;
    Callback callback;
    boolean done;

    /**
     * Constructs this callback object. Requires a Display object upon which 
     * the callSerially() method is to be invoked.
     */
    public SerialCallback(Display dpy) {
        this.dpy = dpy;
        callback = new Callback();
    }
    

    /**
     * Blocks the caller until the events currently in the event queue have 
     * been processed, calls the run() method on the event thread, then 
     * unblocks the caller.
     */
    public synchronized void invokeAndWait() {
        dpy.callSerially(callback);
        done = false;

        try {
            while (!done) {
                wait();
            }
        } catch (InterruptedException ignore) { }
    }


    /**
     * Subclassers may override this if they wish to provide any specialized
     * behavior.  The default implementation does nothing.
     */
    public void run() {
    }


    /**
     * Called on the event thread when the callSerially event reaches the
     * front of the queue. Calls the client's run() method and awakens the 
     * thread that had called invokeAndWait().
     */
    synchronized void called() {
        run();
        done = true;
        notifyAll();
    }


    /**
     * A nested class that provides a run() method to callSerially(), distinct 
     * from the run() method that can be overridden by clients.
     */
    class Callback implements Runnable {
        public void run() {
            called();
        }
    }
}
