/*
 * 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.Type;
import org.gnu.gtk.event.NotebookEvent;
import org.gnu.gtk.event.NotebookListener;
import org.gnu.glib.Handle;

/**
 * A Notebook widget is a container whose children are pages that can be
 * switched between using tab labels along one edge.
 * <p>
 * There are many configuration options for a Notebook. Among other things you
 * can choose on which edge the tabs appear, whether, if there are too many tabs
 * to fit th notebook should be made bigger or scrolling arrows added, and
 * whether there will be a popup menu allowing the user to switch between pages.
 */
public class Notebook extends Container {

    /**
     * Container to hold all listeners that are to receive events.
     */
    private Vector listeners = null;

    /**
     * Construct a new Notebook object with no pages.
     */
    public Notebook() {
        super(gtk_notebook_new());
    }

    /**
     * Construct a new Notebook from a handle to a native resource.
     */
    public Notebook(Handle handle) {
        super(handle);
    }

    /**
     * Internal static factory method to be used by Java-Gnome only.
     */
    public static Notebook getNotebook(Handle handle) {
        if (handle == null)
            return null;

        Notebook obj = (Notebook) getGObjectFromHandle(handle);
        if (obj == null)
            obj = new Notebook(handle);

        return obj;
    }

    /**
     * Append a page to the Notebook.
     * 
     * @param child
     *            The child widget to add to the newly created page.
     * @param tabLabel
     *            The Widget to be used as the label for the page or
     *            <code>null</code
     * to use the default label, 'page N'.
     */
    public void appendPage(Widget child, Widget tabLabel) {
        if (null == tabLabel) {
            Notebook.gtk_notebook_append_page(getHandle(), child.getHandle(),
                    null);
        } else {
            Notebook.gtk_notebook_append_page(getHandle(), child.getHandle(),
                    tabLabel.getHandle());
        }
    }

    /**
     * Append a page to the Notebook.
     * 
     * @param child
     *            The child widget to add to the newly created page.
     * @param tabLabel
     *            The Widget to be used as the label for the page or
     *            <code>null</code
     * to use the default label, 'page N'.
     * @param menuLabel The widget to use as a label for the page-switching menu, if that is
     * enabled.  If <code>null</code> and <code>tabLabel</code> is a Label or <code>null</code>
     * then the menu label will be a newly created label with the same text as the <code>tabLabel</code>.
     */
    public void appendPage(Widget child, Widget tabLabel, Widget menuLabel) {
        if (null == menuLabel) {
            if (null == tabLabel) {
                Notebook.gtk_notebook_append_page_menu(getHandle(), child
                        .getHandle(), null, null);
            } else {
                Notebook.gtk_notebook_append_page_menu(getHandle(), child
                        .getHandle(), tabLabel.getHandle(), null);
            }
        } else {
            Notebook.gtk_notebook_append_page_menu(getHandle(), child
                    .getHandle(), tabLabel.getHandle(), menuLabel.getHandle());
        }
    }

    /**
     * Prepend a page to the Notebook.
     * 
     * @param child
     *            The child widget to add to the newly created page.
     * @param tabLabel
     *            The Widget to be used as the label for the page or
     *            <code>null</code
     * to use the default label, 'page N'.
     */
    public void prependPage(Widget child, Widget tabLabel) {
        if (null == tabLabel) {
            Notebook.gtk_notebook_prepend_page(getHandle(), child.getHandle(),
                    null);
        } else {
            Notebook.gtk_notebook_prepend_page(getHandle(), child.getHandle(),
                    tabLabel.getHandle());
        }
    }

    /**
     * Prepend a page to the Notebook.
     * 
     * @param child
     *            The child widget to add to the newly created page.
     * @param tabLabel
     *            The Widget to be used as the label for the page or
     *            <code>null</code
     * to use the default label, 'page N'.
     * @param menuLabel The widget to use as a label for the page-switching menu, if that is
     * enabled.  If <code>null</code> and <code>tabLabel</code> is a Label or <code>null</code>
     * then the menu label will be a newly created label with the same text as the <code>tabLabel</code>.
     */
    public void prependPage(Widget child, Widget tabLabel, Widget menuLabel) {
        if (null == menuLabel) {
            if (null == tabLabel) {
                Notebook.gtk_notebook_prepend_page_menu(getHandle(), child
                        .getHandle(), null, null);
            } else {
                Notebook.gtk_notebook_prepend_page_menu(getHandle(), child
                        .getHandle(), tabLabel.getHandle(), null);
            }
        } else {
            Notebook.gtk_notebook_prepend_page_menu(getHandle(), child
                    .getHandle(), tabLabel.getHandle(), menuLabel.getHandle());
        }
    }

    /**
     * Insert a page into the Notebook at the given position.
     * 
     * @param child
     *            The child widget to add to the newly created page.
     * @param tabLabel
     *            The Widget to be used as the label for the page or
     *            <code>null</code
     * to use the default label, 'page N'.
     * @param position The index (starting at 0) at which to insert the page.
     */
    public void insertPage(Widget child, Widget tabLabel, int position) {
        if (null == tabLabel) {
            Notebook.gtk_notebook_insert_page(getHandle(), child.getHandle(),
                    null, position);
        } else {
            Notebook.gtk_notebook_insert_page(getHandle(), child.getHandle(),
                    tabLabel.getHandle(), position);
        }
    }

    /**
     * Insert a page into the Notebook at the given position.
     * 
     * @param child
     *            The child widget to add to the newly created page.
     * @param tabLabel
     *            The Widget to be used as the label for the page or
     *            <code>null</code
     * to use the default label, 'page N'.
     * @param menuLabel The widget to use as a label for the page-switching menu, if that is
     * enabled.  If <code>null</code> and <code>tabLabel</code> is a Label or <code>null</code>
     * then the menu label will be a newly created label with the same text as the <code>tabLabel</code>.
     * @param position The index (starting at 0) at which to insert the page.
     */
    public void insertPage(Widget child, Widget tabLabel, Widget menuLabel,
            int position) {
        if (null == menuLabel) {
            if (null == tabLabel) {
                Notebook.gtk_notebook_insert_page_menu(getHandle(), child
                        .getHandle(), null, null, position);
            } else {
                Notebook.gtk_notebook_insert_page_menu(getHandle(), child
                        .getHandle(), tabLabel.getHandle(), null, position);
            }
        } else {
            Notebook.gtk_notebook_insert_page_menu(getHandle(), child
                    .getHandle(), tabLabel.getHandle(), menuLabel.getHandle(),
                    position);
        }
    }

    /**
     * Removes a page fro the Notegook given its index in the notebook.
     * 
     * @param pageNumber
     *            The offset (starting with 0) for the page to remove.
     */
    public void removePage(int pageNumber) {
        Notebook.gtk_notebook_remove_page(getHandle(), pageNumber);
    }

    /**
     * Finds the index of the page which contains the given child.
     * 
     * @param child
     *            The widget to locate.
     * @return The index of the page which contains the given child.
     */
    public int pageNum(Widget child) {
        return Notebook.gtk_notebook_page_num(getHandle(), child.getHandle());
    }

    /**
     * Switches to the next page. Nothing happens if the current page is the
     * last page.
     */
    public void nextPage() {
        Notebook.gtk_notebook_next_page(getHandle());
    }

    /**
     * Switches to the previous page. Nothing happens if the current page is the
     * first page.
     */
    public void prevPage() {
        Notebook.gtk_notebook_prev_page(getHandle());
    }

    /**
     * Reorders the page containing <code>child</code>, so that it appears in
     * position </code>position</code>. If <code>position</code> is greater
     * than or equal to the number of children in the list or negative, <code>child</code>
     * will be moved to the end of the list.
     * 
     * @param child
     *            The widget to move.
     * @param position
     *            The index (starting with 0) to move the child.
     */
    public void reorderChild(Widget child, int position) {
        Notebook.gtk_notebook_reorder_child(getHandle(), child.getHandle(),
                position);
    }

    /**
     * Sets the edge at which the tabs for switching pages in the Notebook are
     * drawn.
     */
    public void setTabPosition(PositionType pos) {
        Notebook.gtk_notebook_set_tab_pos(getHandle(), pos.getValue());
    }

    /**
     * sets whether to show the tabs for the notebook or not.
     */
    public void setShowTabs(boolean showTabs) {
        Notebook.gtk_notebook_set_show_tabs(getHandle(), showTabs);
    }

    /**
     * Sets whether a bevel will be drawn around the notebook pages.
     */
    public void setShowBorder(boolean showBorder) {
        Notebook.gtk_notebook_set_show_border(getHandle(), showBorder);
    }

    /**
     * Sets whether the tab label area will have arrows for scrolling if there
     * are too many tabs to fit in the area.
     */
    public void setScrollable(boolean scrollable) {
        Notebook.gtk_notebook_set_scrollable(getHandle(), scrollable);
    }

    /**
     * Enables the popup menu.
     */
    public void popupEnable() {
        Notebook.gtk_notebook_popup_enable(getHandle());
    }

    /**
     * disables the popup menu.
     */
    public void popupDisable() {
        Notebook.gtk_notebook_popup_disable(getHandle());
    }

    /**
     * Returns the page number of the current page. If the notebook has no
     * pages, then -1 will be returned.
     */
    public int getCurrentPage() {
        return Notebook.gtk_notebook_get_current_page(getHandle());
    }

    /**
     * Retrieves the text of the tab label for the page containing child.
     * 
     * @param child
     *            a widget contained in a page of notebook
     * @return value: the text of the tab label, or NULL if the tab label widget
     *         is not a Label.
     */
    public String getTabLabelText(Widget child) {
        return gtk_notebook_get_tab_label_text(getHandle(), child.getHandle());
    }

    /**
     * sets the page at offset <code>pageNum</code> to the current page.
     */
    public void setCurrentPage(int pageNum) {
        Notebook.gtk_notebook_set_current_page(getHandle(), pageNum);
    }

    /**
     * Returns the child Widget contained int he page number
     * <code>pageNum</code>.
     */
    public Widget getPage(int pageNum) {
        Handle hndl = Notebook.gtk_notebook_get_nth_page(getHandle(), pageNum);
        return Widget.getWidget(hndl);
    }

    /**
     * Changes the menu label for the page containing <code>child</code>.
     */
    public void setMenuLabel(Widget child, Widget menuLabel) {
        Notebook.gtk_notebook_set_menu_label(getHandle(), child.getHandle(),
                menuLabel.getHandle());
    }

    /**
     * Creates a new label and sets it as the menu label of <code>child</code>.
     */
    public void setMenuLabel(Widget child, String menuText) {
        Notebook.gtk_notebook_set_menu_label_text(getHandle(), child
                .getHandle(), menuText);
    }

    /**
     * Changes the tab label for <code>child</code>.
     */
    public void setTabLabel(Widget child, Widget tabLabel) {
        if (null == tabLabel) {
            Notebook.gtk_notebook_set_tab_label(getHandle(), child.getHandle(),
                    null);
        } else {
            Notebook.gtk_notebook_set_tab_label(getHandle(), child.getHandle(),
                    tabLabel.getHandle());
        }
    }

    /**
     * Creates a new label and sets it as the label of the page containing
     * <code>child</code>.
     */
    public void setTabLabel(Widget child, String tabText) {
        Notebook.gtk_notebook_set_tab_label_text(getHandle(),
                child.getHandle(), tabText);
    }

    /**
     * Sets the packing parameters for the tab label of the page containing
     * <code>child</code>.
     * 
     * @see Box
     */
    public void setTabLabelPacking(Widget child, boolean expand, boolean fill,
            PackType packType) {
        Notebook.gtk_notebook_set_tab_label_packing(getHandle(), child
                .getHandle(), expand, fill, packType.getValue());
    }

    /**
     * Return the number of pages currently on the notebook.
     */
    public int getNumPages() {
        return gtk_notebook_get_n_pages(getHandle());
    }

    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);
    }

    /**
     * Implementation method to build an EventMap for this widget class. Not
     * useful (or supported) for application use.
     */
    private static void addEvents(EventMap anEvtMap) {
        anEvtMap.addEvent("select_page", "handleSelectPage",
                NotebookEvent.Type.SELECT_PAGE, NotebookListener.class);
        anEvtMap.addEvent("switch_page", "handleSwitchPage",
                NotebookEvent.Type.SWITCH_PAGE, NotebookListener.class);
    }

    /**
     * Register an object to receive event notification.
     * 
     * @param listener
     *            The object that has implemented the NotebookListener interface
     *            that is to receive the notebook events.
     */
    public void addListener(NotebookListener 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, NotebookEvent.Type.SELECT_PAGE);
                evtMap.initialize(this, NotebookEvent.Type.SWITCH_PAGE);
                listeners = new Vector();
            }
            listeners.addElement(listener);
        }
    }

    /**
     * Unregister an object that was receiving notebook event notification.
     * 
     * @param listener
     *            The object that is to no longer receive notebook events.
     */
    public void removeListener(NotebookListener listener) {
        int i = findListener(listeners, listener);
        if (i > -1) {
            listeners.remove(i);
        }
        if (0 == listeners.size()) {
            evtMap.uninitialize(this, NotebookEvent.Type.SELECT_PAGE);
            evtMap.uninitialize(this, NotebookEvent.Type.SWITCH_PAGE);
            listeners = null;
        }
    }

    protected void fireNotebookEvent(NotebookEvent event) {
        if (null == listeners) {
            return;
        }
        int size = listeners.size();
        int i = 0;
        while (i < size) {
            NotebookListener nl = (NotebookListener) listeners.elementAt(i);
            nl.notebookEvent(event);
            i++;
        }
    }

    private boolean handleSelectPage(boolean moveFocus) {
        fireNotebookEvent(new NotebookEvent(this,
                NotebookEvent.Type.SELECT_PAGE));
        return true;
    }

    private void handleSwitchPage(Handle page, int pageNum) {
        fireNotebookEvent(new NotebookEvent(this,
                NotebookEvent.Type.SWITCH_PAGE, pageNum));
    }

    /**
     * Retrieve the runtime type used by the GLib library.
     */
    public static Type getType() {
        return new Type(gtk_notebook_get_type());
    }

    native static final protected int gtk_notebook_get_type();

    native static final protected Handle gtk_notebook_new();

    native static final protected void gtk_notebook_append_page(
            Handle notebook, Handle child, Handle tabLabel);

    native static final protected void gtk_notebook_append_page_menu(
            Handle notebook, Handle child, Handle tabLabel, Handle menuLabel);

    native static final protected void gtk_notebook_prepend_page(
            Handle notebook, Handle child, Handle tabLabel);

    native static final protected void gtk_notebook_prepend_page_menu(
            Handle notebook, Handle child, Handle tabLabel, Handle menuLabel);

    native static final protected void gtk_notebook_insert_page(
            Handle notebook, Handle child, Handle tabLabel, int position);

    native static final protected void gtk_notebook_insert_page_menu(
            Handle notebook, Handle child, Handle tabLabel, Handle menuLabel,
            int position);

    native static final protected void gtk_notebook_remove_page(
            Handle notebook, int pageNum);

    native static final protected int gtk_notebook_get_current_page(
            Handle notebook);

    native static final protected Handle gtk_notebook_get_nth_page(
            Handle notebook, int pageNum);

    native static final protected int gtk_notebook_page_num(Handle notebook,
            Handle child);

    native static final protected void gtk_notebook_set_current_page(
            Handle notebook, int pageNum);

    native static final protected void gtk_notebook_next_page(Handle notebook);

    native static final protected void gtk_notebook_prev_page(Handle notebook);

    native static final protected void gtk_notebook_set_show_border(
            Handle notebook, boolean showBorder);

    native static final protected boolean gtk_notebook_get_show_border(
            Handle notebook);

    native static final protected void gtk_notebook_set_show_tabs(
            Handle notebook, boolean showTabs);

    native static final protected boolean gtk_notebook_get_show_tabs(
            Handle notebook);

    native static final protected void gtk_notebook_set_tab_pos(
            Handle notebook, int pos);

    native static final protected int gtk_notebook_get_tab_pos(Handle notebook);

    native static final protected void gtk_notebook_set_scrollable(
            Handle notebook, boolean scrollable);

    native static final protected boolean gtk_notebook_get_scrollable(
            Handle notebook);

    native static final protected void gtk_notebook_popup_enable(Handle notebook);

    native static final protected void gtk_notebook_popup_disable(
            Handle notebook);

    native static final protected Handle gtk_notebook_get_tab_label(
            Handle notebook, Handle child);

    native static final protected void gtk_notebook_set_tab_label(
            Handle notebook, Handle child, Handle tabLabel);

    native static final protected void gtk_notebook_set_tab_label_text(
            Handle notebook, Handle child, String tabText);

    native static final protected String gtk_notebook_get_tab_label_text(
            Handle notebook, Handle child);

    native static final protected Handle gtk_notebook_get_menu_label(
            Handle notebook, Handle child);

    native static final protected void gtk_notebook_set_menu_label(
            Handle notebook, Handle child, Handle menuLabel);

    native static final protected void gtk_notebook_set_menu_label_text(
            Handle notebook, Handle child, String menuText);

    native static final protected String gtk_notebook_get_menu_label_text(
            Handle notebook, Handle child);

    native static final protected void gtk_notebook_query_tab_label_packing(
            Handle notebook, Handle child, boolean[] expand, boolean[] fill,
            int[] packType);

    native static final protected void gtk_notebook_set_tab_label_packing(
            Handle notebook, Handle child, boolean expand, boolean fill,
            int packType);

    native static final protected void gtk_notebook_reorder_child(
            Handle notebook, Handle child, int position);

    native static final protected int gtk_notebook_get_n_pages(Handle notebook);

    /*
     * Deprecated functions. native static final private void
     * gtk_notebook_set_homogeneous_tabs(Handle notebook, boolean homogeneous);
     * native static final private void gtk_notebook_set_tab_border(Handle
     * notebook, int border_width); native static final private void
     * gtk_notebook_set_tab_hborder(Handle notebook, int tab_hborder); native
     * static final private void gtk_notebook_set_tab_vborder(Handle notebook,
     * int tab_vborder);
     */
}
