/*
 * Java-Gnome Bindings Library
 *
 * Copyright 1998-2004 the Java-Gnome Team, all rights reserved.
 *
 * The Java-Gnome bindings library is free software distributed under
 * the terms of the GNU Library General Public License version 2.
 */

package org.gnu.gtk;

import java.util.Vector;

import org.gnu.glib.EventMap;
import org.gnu.glib.EventType;
import org.gnu.glib.Handle;
import org.gnu.glib.Type;
import org.gnu.gtk.event.StatusBarEvent;
import org.gnu.gtk.event.StatusBarListener;

/**
 * A Statusbar is usually placed along the bottom of an application's main 
 * {@link Window}. It may provide a regular commentary of the application's 
 * status (as is usually the case in a web browser, for example), or may be 
 * used to simply output a message when the status changes, (when an upload 
 * is complete in an FTP client, for example). It may also have a resize 
 * grip (a triangular area in the lower right corner) which can be clicked 
 * on to resize the window containing the statusbar.
 * <p>Status bars in Gtk+ maintain a stack of messages. The message at the 
 * top of the each bar's stack is the one that will currently be displayed.
 * <p>Any messages added to a statusbar's stack must specify a contextID
 * that is used to uniquely identify the source of a message. This 
 * contextID can be generated by {@link #getContextID(String)}, given a message. 
 * Note that messages are stored in a stack, and when choosing which message 
 * to display, the stack structure is adhered to, regardless of the context 
 * identifier of a message.
 * <p>Messages are added to the bar's stack with {@link #push(int,String)}.
 * <p>The message at the top of the stack can be removed using {@link #pop(int)}.
 * A message can be removed from anywhere in the stack if it's messageID 
 * was recorded at the time it was added. This is done using {@link #remove(int,
 * int)}.
 */
public class StatusBar extends HBox {
	/**
	 * Creates a new StatusBar Widget
	 */
	public StatusBar() {
		super(gtk_statusbar_new());
	}

	/**
	 * Creates a new StatusBar from a handle to native resources. This should
	 * only be used internally by the Java-Gnome packages.
	 */
	public StatusBar(Handle handle) {
	    super(handle);
	}

	/**
	 * Returns a new context identifier, given a description of the actual 
	 * context.
	 * @see StatusBar
	 * @param description textual description of what context the new message 
	 * is being used in.
	 */
	public int getContextID(String description) {
		return gtk_statusbar_get_context_id(getHandle(), description);
	}

	/**
	 * Pushes a new message onto a statusbar's stack.
	 * @param contextID The message's context id, as returned by 
	 * {@link #getContextID(String)}
	 * @param text The message to add to the statusbar.
	 * @return The message's new message id for use with {@link #remove(int,
	 * int)}
	 */
	public int push(int contextID, String text) {
		return gtk_statusbar_push(getHandle(), contextID, text);
	}

	/**
	 * Removes the message at the top of the statusbar's stack.
	 * @param contextID a context identifier.
	 */
	public void pop(int contextID) {
		gtk_statusbar_pop(getHandle(), contextID);
	}

	/**
	 * Forces the removal of a message from a statusbar's stack. 
	 * The exact contextID and messageID must be specified.
	 * @param contextID A context identifier.
	 * @param messageID A message identifier, as returned by {@link #push(int,
	 * String)}.
	 */
	public void remove(int contextID, int messageID) {
		gtk_statusbar_remove(getHandle(), contextID, messageID);
	}

	/**
	 * Sets whether the statusbar has a resize grip. TRUE by default.
	 * @param setting TRUE to have a resize grip.
	 */
	public void setHasResizeGrip(boolean setting) {
		gtk_statusbar_set_has_resize_grip(getHandle(), setting);
	}

	/**
	 * Returns whether the statusbar has a resize grip.
	 * @return TRUE if the statusbar has a resize grip.
	 */
	public boolean getHasResizeGrip() {
		return gtk_statusbar_get_has_resize_grip(getHandle());
	}

	/**
	 * Retrieve the runtime type used by the GLib library.
	 */
	public static Type getType() {
		return new Type(gtk_statusbar_get_type());
	}

	/****************************************
	 * Event Handling
	 ****************************************/

	/** Listeners for handling StatusBar events */
	private Vector listeners = null;

	/**
	 * Register an object to handle StatusBar events.
	 * @see org.gnu.gtk.event.StatusBarListener
	 */
	public void addListener(StatusBarListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(listeners, listener);
		if (i == -1) {
			if (null == listeners) {
				evtMap.initialize(this, StatusBarEvent.Type.TEXT_POPPED);
				evtMap.initialize(this, StatusBarEvent.Type.TEXT_PUSHED);
				listeners = new Vector();
			}
			listeners.addElement(listener);
		}
	}
	/**
	 * Removes a listener
	 * @see #addListener(StatusBarListener)
	 */
	public void removeListener(StatusBarListener listener) {
		int i = findListener(listeners, listener);
		if (i > -1)
			listeners.remove(i);
		if (0 == listeners.size()) {
			evtMap.uninitialize(this, StatusBarEvent.Type.TEXT_POPPED);
			evtMap.uninitialize(this, StatusBarEvent.Type.TEXT_PUSHED);
			listeners = null;
		}
	}

	protected void fireStatusBarEvent(StatusBarEvent event) {
		if (null == listeners)
			return;
		int size = listeners.size();
		int i = 0;
		while (i < size) {
			StatusBarListener sl = (StatusBarListener)listeners.elementAt(i);
			sl.statusBarEvent(event);
			i++;
		}
	}

	private void handleTextPushed(int context, String text) {
		StatusBarEvent evt = new StatusBarEvent(this, StatusBarEvent.Type.TEXT_PUSHED);
		evt.setText(text);
		fireStatusBarEvent(evt);
	}

	private void handleTextPopped(int context, String text) {
		StatusBarEvent evt = new StatusBarEvent(this, StatusBarEvent.Type.TEXT_POPPED);
		evt.setText(text);
		fireStatusBarEvent(evt);
	}

	public Class getEventListenerClass(String signal) {
		Class cls = evtMap.getEventListenerClass(signal);
		if (cls == null) cls = super.getEventListenerClass(signal);
		return cls;
	}

	public EventType getEventType(String signal) {
		EventType et = evtMap.getEventType(signal);
		if (et == null) et = super.getEventType(signal);
		return et;
	}

	private static EventMap evtMap = new EventMap();
	static {
		addEvents(evtMap);
	}

	private static void addEvents(EventMap anEvtMap) {
		anEvtMap.addEvent("text_pushed", "handleTextPushed", StatusBarEvent.Type.TEXT_PUSHED, StatusBarListener.class);
		anEvtMap.addEvent("text_popped", "handleTextPopped", StatusBarEvent.Type.TEXT_POPPED, StatusBarListener.class);
	}

	native static final protected Handle getFrame(Handle cptr);
	native static final protected Handle getLabel(Handle cptr);
	native static final protected int gtk_statusbar_get_type();
	native static final protected Handle gtk_statusbar_new();
	native static final protected int gtk_statusbar_get_context_id(Handle statusbar, String contextDescription);
	native static final protected int gtk_statusbar_push(Handle statusbar, int contextId, String text);
	native static final protected void gtk_statusbar_pop(Handle statusbar, int contextId);
	native static final protected void gtk_statusbar_remove(Handle statusbar, int contextId, int messageId);
	native static final protected void gtk_statusbar_set_has_resize_grip(Handle statusbar, boolean setting);
	native static final protected boolean gtk_statusbar_get_has_resize_grip(Handle statusbar);
}
