/*
 * 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.ArrayList;
import java.util.List;
import java.util.Vector;

import org.gnu.glib.EventMap;
import org.gnu.glib.GObject;
import org.gnu.gtk.event.GtkEventType;
import org.gnu.gtk.event.UIManagerEvent;
import org.gnu.gtk.event.UIManagerListener;

/**
 */
public class UIManager extends GObject {
	
	public UIManager() {
		super(gtk_ui_manager_new());
		initializeEventHandlers();
	}
	
	public void setAddTearoffs(boolean addTearoffs) {
		gtk_ui_manager_set_add_tearoffs(getHandle(), addTearoffs);
	}
	
	public boolean getAddTearoffs() {
		return gtk_ui_manager_get_add_tearoffs(getHandle());
	}
	
	public void insertActionGroup(ActionGroup group, int position) {
		gtk_ui_manager_insert_action_group(getHandle(), group.getHandle(), position);
	}
	
	public void removeActionGroup(ActionGroup group) {
		gtk_ui_manager_remove_action_group(getHandle(), group.getHandle());
	}
	
	public List getActionGroups() {
		int[] actions = gtk_ui_manager_get_action_groups(getHandle());
		List objs = new ArrayList();
		for (int i = 0; i < actions.length; i++) {
			GObject obj = retrieveGObject(actions[i]);
			if (null != obj)
				objs.add((ActionGroup)obj);
			else
				objs.add(new ActionGroup(actions[i]));
		}
		return objs;
	}
	
	public AccelGroup getAccelGroup() {
		int hndl = gtk_ui_manager_get_accel_group(getHandle());
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (AccelGroup)obj;
		return new AccelGroup(hndl);
	}
	
	public Widget getWidget(String path) {
		int hndl = gtk_ui_manager_get_widget(getHandle(), path);
		if (0 == hndl)
			return null;
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Widget)obj;
		return new Widget(hndl);
	}
	
	public Widget[] getToplevels(UIManagerItemType types) {
		int[] hndls = gtk_ui_manager_get_toplevels(getHandle(), types.getValue());
		Widget[] widgets = new Widget[hndls.length];
		for (int i = 0; i < hndls.length; i++) {
			GObject obj = retrieveGObject(hndls[i]);
			if (null != obj)
				widgets[i] = (Widget)obj;
			else
				widgets[i] = new Widget(hndls[i]);
		}
		return widgets;
	}
	
	public Action getAction(String path) {
		return new Action(gtk_ui_manager_get_action(getHandle(), path));
	}
	
	public int addUIFromString(String ui) {
		int err = 0;
		int ret = gtk_ui_manager_add_ui_from_string(getHandle(), ui, ui.length(), new int[] {err});
		if (0 < err)
			throw new RuntimeException("An error occurred adding UI from String");
		return ret;
	}
	
	public int addUIFromFile(String filename) {
		int err = 0;
		int ret = gtk_ui_manager_add_ui_from_file(getHandle(), filename, new int[] {err});
		if (0 < err)
			throw new RuntimeException("An error occurred adding UI from file");
		return ret;
	}
	
	public void addUI(int mergeId, String path, String name, String action, UIManagerItemType type, boolean top) {
		gtk_ui_manager_add_ui(getHandle(), mergeId, path, name, action, type.getValue(), top);
	}
	
	public void removeUI(int mergeId) {
		gtk_ui_manager_remove_ui(getHandle(), mergeId);
	}
	
	public String getUI() {
		return gtk_ui_manager_get_ui(getHandle());
	}
	
	public void ensureUpdate() {
		gtk_ui_manager_ensure_update(getHandle());
	}
	
	public int newMergeId() {
		return gtk_ui_manager_new_merge_id(getHandle());
	}

	/* **************************************
	 * Event Handling
	 ****************************************/
	private Vector listeners;

	/**
	 * Initialize this widget to receive its' own events so it can
	 * propogate them to the listeners.
	 */
	protected void initializeEventHandlers() {
		if (!eventsInitialized) {
			evtMap.initialize(this);
			eventsInitialized = true;
		}
	}

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

	public GtkEventType getEventType(String signal) {
		GtkEventType 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("add_widget", "handleAddWidget", UIManagerEvent.Type.ADD_WIDGET, UIManagerListener.class);
		anEvtMap.addEvent("actions_changed", "handleActionsChanged", UIManagerEvent.Type.ACTIONS_CHANGED, UIManagerListener.class);
		anEvtMap.addEvent("connect_proxy", "handleConnectProxy", UIManagerEvent.Type.CONNECT_PROXY, UIManagerListener.class);
		anEvtMap.addEvent("disconnect_proxy", "handleDisconnectProxy", UIManagerEvent.Type.DISCONNECT_PROXY, UIManagerListener.class);
		anEvtMap.addEvent("pre_activate", "handlePreActivate", UIManagerEvent.Type.PRE_ACTIVATE, UIManagerListener.class);
		anEvtMap.addEvent("post_activate", "handlePostActivate", UIManagerEvent.Type.POST_ACTIVATE, UIManagerListener.class);
	}

	/**
	 * Register an object to handle spin events.
	 * @see org.gnu.gtk.event.SpinListener
	 */
	public void addListener(UIManagerListener 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)
				listeners = new Vector();
			listeners.addElement(listener);
		}
	}
	/**
	 * Removes a listener
	 * @see #addListener(UIManagerListener)
	 */
	public void removeListener(UIManagerListener listener) {
		int i = findListener(listeners, listener);
		if (i > -1)
			listeners.remove(i);
		if (0 == listeners.size())
			listeners = null;
	}

	protected void fireUIManagerEvent(UIManagerEvent event) {
		if (null == listeners)
			return;
		int size = listeners.size();
		int i = 0;
		while (i < size) {
			UIManagerListener l = (UIManagerListener)listeners.elementAt(i);
			l.uiManagerEvent(event);
			i++;
		}
	}

	private void handleAddWidget(int widget) {
//		UIManagerEvent evt = new UIManagerEvent(this, UIManagerEvent.Type.ADD_WIDGET);
//		evt.setWidget(new Widget(widget));
//		fireUIManagerEvent(evt);
	}
	
	private void handleActionsChanged() {
//		fireUIManagerEvent(new UIManagerEvent(this, UIManagerEvent.Type.ACTIONS_CHANGED));
	}

	private void handleConnectProxy(int action, int proxy) {
//		UIManagerEvent evt = new UIManagerEvent(this, UIManagerEvent.Type.CONNECT_PROXY);
//		evt.setAction(new Action(action));
//		evt.setWidget(new Widget(proxy));
//		fireUIManagerEvent(evt);
	}

	private void handleDisconnectProxy(int action, int proxy) {
//		UIManagerEvent evt = new UIManagerEvent(this, UIManagerEvent.Type.DISCONNECT_PROXY);
//		evt.setAction(new Action(action));
//		evt.setWidget(new Widget(proxy));
//		fireUIManagerEvent(evt);
	}

	private void handlePreActivate(int action) {
//		UIManagerEvent evt = new UIManagerEvent(this, UIManagerEvent.Type.PRE_ACTIVATE);
//		evt.setAction(new Action(action));
//		fireUIManagerEvent(evt);
	}

	private void handlePostActivate(int action) {
//		UIManagerEvent evt = new UIManagerEvent(this, UIManagerEvent.Type.POST_ACTIVATE);
//		evt.setAction(new Action(action));
//		fireUIManagerEvent(evt);
	}

	/**
	 * Give us a way to locate a specific listener in a Vector.
	 * @param list The Vector of listeners to search.
	 * @param listener The object that is to be located in the Vector.
	 * @return Returns the index of the listener in the Vector, or -1 if
	 *                 the listener is not contained in the Vector.
	 */
	protected static int findListener(Vector list, Object listener) {
		if (null == list || null == listener)
			return -1;
		return list.indexOf(listener);
	}

	/****************************************
	 * BEGINNING OF JNI CODE
	 ****************************************/
	native static final protected int gtk_ui_manager_get_type ();
	native static final protected int gtk_ui_manager_new();
	native static final protected void gtk_ui_manager_set_add_tearoffs(int uim, boolean value);
	native static final protected boolean gtk_ui_manager_get_add_tearoffs(int uim);
	native static final protected void gtk_ui_manager_insert_action_group(int uim, int actionGroup, int pos);
	native static final protected void gtk_ui_manager_remove_action_group(int uim, int actionGroup);
	native static final protected int[] gtk_ui_manager_get_action_groups(int uim);
	native static final protected int gtk_ui_manager_get_accel_group(int uim);
	native static final protected int gtk_ui_manager_get_widget(int uim, String path);
	native static final protected int[] gtk_ui_manager_get_toplevels(int manager, int types);
	native static final protected int gtk_ui_manager_get_action(int uim, String path);
	native static final protected int gtk_ui_manager_add_ui_from_string(int uim, String buffer, int length, int[] error);
	native static final protected int gtk_ui_manager_add_ui_from_file(int uim, String filename, int[] error);
	native static final protected void gtk_ui_manager_add_ui(int uim, int mergeId, String path, String name, String action, int type, boolean top);
	native static final protected void gtk_ui_manager_remove_ui(int uim, int mergeId);
	native static final protected String gtk_ui_manager_get_ui(int uim);
	native static final protected void gtk_ui_manager_ensure_update(int uim);
	native static final protected int gtk_ui_manager_new_merge_id(int uim);
	/****************************************
	 * END OF JNI CODE
	 ****************************************/
}
