/*
 *
 *
 * 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.content;

import javax.microedition.content.ResponseListener;

/**
 * Thread to monitor pending invocations and notify a listener
 * when a matching one is present.
 */
class ResponseListenerImpl implements Runnable {

    /** ContenHandlerServer for which this is listening. */
    private final RegistryImpl registry;

    /** The listener to notify. */
    private ResponseListener listener;

    /** The active thread processing the run method. */
    private Thread thread;

    /**
     * Create a new listener for pending invocations.
     *
     * @param registry the RegistryImpl to listen for
     * @param listener the listener to notify when present
     */
    ResponseListenerImpl(RegistryImpl registry,
			 ResponseListener listener) {
	this.registry = registry;
	setListener(listener);
    }

    /**
     * Set the listener to be notified and start/stop the monitoring
     * thread as necesary.
     * If the listener is non-null make sure there is a thread active
     * to monitor it.
     * If there is no listener, then stop the monitor thread.
     * Unblock any blocked threads so they can get the updated listener.
     * @param listener the listener to update
     */
    void setListener(ResponseListener listener) {
	this.listener = listener;

	if (listener != null) {
	    // Ensure a thread is running to watch for it
	    if (thread == null || !thread.isAlive()) {
		thread = new Thread(this);
		thread.start();
	    }
	} else {
	    // Forget the thread doing the listening; it will exit
	    thread = null;
	}

	/*
	 * Reset notified flags on pending responses.
	 * Unblock any threads waiting to notify current listeners
	 */
	InvocationStore.setListenNotify(registry.application.getStorageId(),
					registry.application.getClassname(),
					false);
	InvocationStore.cancel();
    }

    /**
     * The run method checks for pending invocations for a
     * desired Registry.
     * When an invocation is available the listener is
     * notified.
     */
    public void run() {
	Thread mythread = Thread.currentThread();
	while (mythread == thread) {
	    // Remember the listener to notify to avoid a race condition
	    ResponseListener l = listener;
	    if (l != null) {
		// Wait for a matching invocation
		boolean pending =
		    InvocationStore.listen(registry.application.getStorageId(),
					   registry.application.getClassname(),
					   false, true);
		if (pending) {
		    l.invocationResponseNotify(registry.getRegistry());
		}
	    }
	}
    }
}
