/*
 * 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.EventType;
import org.gnu.glib.GObject;
import org.gnu.glib.Handle;
import org.gnu.gtk.event.UIManagerEvent;
import org.gnu.gtk.event.UIManagerListener;

/**
 */
public class UIManager extends GObject {
	
	public UIManager() {
		super(gtk_ui_manager_new());
	}
	
	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() {
	    Handle[] actions = gtk_ui_manager_get_action_groups(getHandle());
		List objs = new ArrayList();
		for (int i = 0; i < actions.length; i++) {
			GObject obj = getGObjectFromHandle(actions[i]);
			if (null != obj)
				objs.add((ActionGroup)obj);
			else
				objs.add(new ActionGroup(actions[i]));
		}
		return objs;
	}
	
	public AccelGroup getAccelGroup() {
		Handle hndl = gtk_ui_manager_get_accel_group(getHandle());
		GObject obj = getGObjectFromHandle(hndl);
		if (null != obj)
			return (AccelGroup)obj;
		return new AccelGroup(hndl);
	}
	
	public Widget getWidget(String path) {
	    Handle hndl = gtk_ui_manager_get_widget(getHandle(), path);
		if (null == hndl)
			return null;
		GObject obj = getGObjectFromHandle(hndl);
		if (null != obj)
			return (Widget)obj;
		return new Widget(hndl);
	}
	
	public Widget[] getToplevels(UIManagerItemType types) {
	    Handle[] 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 = getGObjectFromHandle(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());
		if (ret == 0)
			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);
		if (ret == 0)
			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;

	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("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) {
				evtMap.initialize(this, UIManagerEvent.Type.ACTIONS_CHANGED);
				evtMap.initialize(this, UIManagerEvent.Type.ADD_WIDGET);
				evtMap.initialize(this, UIManagerEvent.Type.CONNECT_PROXY);
				evtMap.initialize(this, UIManagerEvent.Type.DISCONNECT_PROXY);
				evtMap.initialize(this, UIManagerEvent.Type.POST_ACTIVATE);
				evtMap.initialize(this, UIManagerEvent.Type.PRE_ACTIVATE);
				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()) {
			evtMap.uninitialize(this, UIManagerEvent.Type.ACTIONS_CHANGED);
			evtMap.uninitialize(this, UIManagerEvent.Type.ADD_WIDGET);
			evtMap.uninitialize(this, UIManagerEvent.Type.CONNECT_PROXY);
			evtMap.uninitialize(this, UIManagerEvent.Type.DISCONNECT_PROXY);
			evtMap.uninitialize(this, UIManagerEvent.Type.POST_ACTIVATE);
			evtMap.uninitialize(this, UIManagerEvent.Type.PRE_ACTIVATE);
			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(Handle 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(Handle action, Handle 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(Handle action, Handle 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(Handle action) {
//		UIManagerEvent evt = new UIManagerEvent(this, UIManagerEvent.Type.PRE_ACTIVATE);
//		evt.setAction(new Action(action));
//		fireUIManagerEvent(evt);
	}

	private void handlePostActivate(Handle 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);
	}

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