/*
 * 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.Handle;
import org.gnu.glib.Type;
import org.gnu.gtk.event.ContainerEvent;
import org.gnu.gtk.event.ContainerListener;

/**
 * The Container widget is a base class for container widgets.
 * Widgets that inherit from Container have the ability to contain,
 * position, size, and display one or more other widgets.
 */
public class Container extends Widget {

	protected Container(Handle handle) {
		super(handle);
	}


	/**
	 * Adds widget to the Container.
	 * 
	 * @param widget The Widget to be added to this Container.
	 */
	public void add(Widget widget) {
		Container.gtk_container_add(getHandle(), widget.getHandle());
	}

	/**
	 * Remove a Widget from the Container.
	 * 
	 * @param widget The Widget to remove from the Container.
	 */
	public void remove(Widget widget) {
		Container.gtk_container_remove(getHandle(), widget.getHandle());
	}

	/**
	 * Returns the ResizeMode for the Container.
	 * 
	 * @return The ResizeMode for the Container.
	 */
	public ResizeMode getResizeMode() {
		int val = Container.gtk_container_get_resize_mode(getHandle());
		return ResizeMode.intern(val);
	}

	/**
	 * Sets the ResizeMode for the Container.
	 * 
	 * @param mode The ResizeMode.
	 */
	public void setResizeMode(ResizeMode mode) {
		Container.gtk_container_set_resize_mode(getHandle(), mode.getValue());
	}

	/**
	 * Retrieves the border width for the Container.
	 * 
	 * @return The border width.
	 */
	public int getBorderWidth() {
		return Container.gtk_container_get_border_width(getHandle());
	}

	/**
	 * Sets the border width for the Container.
	 * 
	 * @param width The border width.
	 */
	public void setBorderWidth(int width) {
		Container.gtk_container_set_border_width(getHandle(), width);
	}

	/**
	 * Informs the container to resize all of its' children based
	 * on the size requirements of the children.
	 */
	public void resizeChildren() {
		Container.gtk_container_resize_children(getHandle());
	}
	
	/**
	 * Get an array of all children of this container.
	 * @return An array contain all children of this container or null.
	 */
	public Widget[] getChildren() {
	    Handle[] hndls = gtk_container_get_children(getHandle());
		if (null == hndls)
			return null;
		Widget[] widgets = new Widget[hndls.length];
		for (int i = 0; i < hndls.length; i++) {
			GObject obj = getGObjectFromHandle(hndls[i]);
			if (null != obj)
				widgets[i] = (Widget)obj;
			else
				widgets[i] = new Widget(hndls[i]);
		}
		return widgets;
	}

	/**
	 * Retrieve the runtime type used by the GLib library.
	 */
	public static Type getType() {
		return new Type(gtk_container_get_type());
	}

	/************************************
	* Event handling support
	************************************/

	/**
	 * Listeners for handling button events
	 */
	private Vector containerListeners = null;

	/**
	 * Register an object to handle container events.
	 * @see org.gnu.gtk.event.ContainerListener
	 */
	public void addListener(ContainerListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(containerListeners, listener);
		if (i == -1) {
			if (null == containerListeners) {
				evtMap.initialize(this,ContainerEvent.Type.ADD);
				evtMap.initialize(this,ContainerEvent.Type.CHECK_RESIZE);
				evtMap.initialize(this,ContainerEvent.Type.REMOVE);
				evtMap.initialize(this,ContainerEvent.Type.SET_FOCUS_CHILD);
				containerListeners = new Vector();
			}
			containerListeners.addElement(listener);
		}
	}
	/**
	 * Removes a listener
	 * @see #addListener(ContainerListener)
	 */
	public void removeListener(ContainerListener listener) {
		int i = findListener(containerListeners, listener);
		if (i > -1) {
			containerListeners.remove(i);
		}
		if (0 == containerListeners.size()) {
			evtMap.uninitialize(this,ContainerEvent.Type.ADD);
			evtMap.uninitialize(this,ContainerEvent.Type.CHECK_RESIZE);
			evtMap.uninitialize(this,ContainerEvent.Type.REMOVE);
			evtMap.uninitialize(this,ContainerEvent.Type.SET_FOCUS_CHILD);
			containerListeners = null;
		}
	}

	protected void fireContainerEvent(ContainerEvent event) {
		if (null == containerListeners) {
			return;
		}
		int size = containerListeners.size();
		int i = 0;
		while (i < size) {
			ContainerListener bl = (ContainerListener)containerListeners.elementAt(i);
			bl.containerEvent(event);
			i++;
		}
	}

	private void handleAdd(Handle childHandle) {
		fireContainerEvent(new ContainerEvent(this, ContainerEvent.Type.ADD));
	}

	private void handleCheckResize() {
		fireContainerEvent(new ContainerEvent(this, ContainerEvent.Type.CHECK_RESIZE));
	}

	private void handleRemove(Handle childHandle) {
		fireContainerEvent(new ContainerEvent(this, ContainerEvent.Type.REMOVE));
	}

	private void handleSetFocusChild(Handle childHandle) {
		fireContainerEvent(new ContainerEvent(this, ContainerEvent.Type.SET_FOCUS_CHILD));
	}

	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("add", "handleAdd", ContainerEvent.Type.ADD, ContainerListener.class);
		anEvtMap.addEvent("check_resize", "handleCheckResize", ContainerEvent.Type.CHECK_RESIZE, ContainerListener.class);
		anEvtMap.addEvent("remove", "handleRemove", ContainerEvent.Type.REMOVE, ContainerListener.class);
		anEvtMap.addEvent("set_focus_child", "handleSetFocusChild", ContainerEvent.Type.SET_FOCUS_CHILD, ContainerListener.class);
	}


	native static final protected int gtk_container_get_type();
	native static final protected void gtk_container_set_border_width(Handle container, int borderWidth);
	native static final protected int gtk_container_get_border_width(Handle container);
	native static final protected void gtk_container_add(Handle container, Handle widget);
	native static final protected void gtk_container_remove(Handle container, Handle widget);
	native static final protected void gtk_container_set_resize_mode(Handle container, int mode);
	native static final protected int gtk_container_get_resize_mode(Handle container);
	native static final protected void gtk_container_check_resize(Handle container);
	native static final protected Handle[] gtk_container_get_children(Handle container);
	native static final protected void gtk_container_propagate_expose(Handle container, Handle child, Handle event);
	native static final protected void gtk_container_set_focus_chain(Handle container, Handle focusableWidgets);
	native static final protected boolean gtk_container_get_focus_chain(Handle container, Handle focusableWidgets);
	native static final protected void gtk_container_unset_focus_chain(Handle container);
	native static final protected void gtk_container_set_reallocate_redraws(Handle container, boolean needsRedraws);
	native static final protected void gtk_container_set_focus_child(Handle container, Handle child);
	native static final protected void gtk_container_set_focus_vadjustment(Handle container, Handle adjustment);
	native static final protected Handle gtk_container_get_focus_vadjustment(Handle container);
	native static final protected void gtk_container_set_focus_hadjustment(Handle container, Handle adjustment);
	native static final protected Handle gtk_container_get_focus_hadjustment(Handle container);
	native static final protected void gtk_container_resize_children(Handle container);
	native static final protected int gtk_container_child_type(Handle container);

    /* Deprecated functions.
    native static final private void gtk_container_foreach_full(Handle container, int callback, int marshal, gpointer callback_data, int notify);
    */
}
