/*
 * 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.GObject;
import org.gnu.glib.Type;
import org.gnu.gtk.event.StatusBarEvent;
import org.gnu.gtk.event.StatusBarListener;
import org.gnu.glib.Handle;

/**
 * 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)}.
 *
 * @deprecated This class is part of the java-gnome 2.x family of libraries,
 *             which, due to their inefficiency and complexity, are no longer
 *             being maintained and have been abandoned by the java-gnome
 *             project. This class may in the future have an equivalent in
 *             java-gnome 4.0, try looking for
 *             <code>org.gnome.gtk.StatusBar</code>.
 *             You should be aware that there is a considerably different API
 *             in the new library: the architecture is completely different
 *             and most notably internals are no longer exposed to public view.
 */
public class StatusBar extends HBox {
    /**
     * Creates a new StatusBar Widget
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    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.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public StatusBar(Handle handle) {
        super(handle);
    }

    /**
     * Internal static factory method to be used by Java-Gnome only.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public static StatusBar getStatusBar(Handle handle) {
        if (handle == null) {
            return null;
        }

        StatusBar obj = (StatusBar) GObject.getGObjectFromHandle(handle);

        if (obj == null) {
            obj = new StatusBar(handle);
        }

        return obj;
    }

    /**
     * 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.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    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)}
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    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.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    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)}.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    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.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    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.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    public boolean getHasResizeGrip() {
        return gtk_statusbar_get_has_resize_grip(getHandle());
    }

    /**
     * Retrieve the runtime type used by the GLib library.
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    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
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    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)
     * @deprecated Superceeded by java-gnome 4.0; a method along these lines
     *             may well exist in the new bindings, but if it does it likely
     *             has a different name or signature due to the shift to an
     *             algorithmic mapping of the underlying native libraries.
     */
    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);
}
