/*
 * 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.GObject;
import org.gnu.gtk.event.EntryCompletionEvent;
import org.gnu.gtk.event.EntryCompletionListener;
import org.gnu.gtk.event.GtkEventType;

/**
 * EntryCompletion is an auxiliary object to be used in conjunction 
 * with Entry to provide the completion functionality. To add 
 * completion functionality to an Entry, use setCompletion(). In 
 * addition to regular completion matches, which will be inserted 
 * into the entry when they are selected, EntryCompletion also allows 
 * to display "actions" in the popup window. Their appearance is 
 * similar to menuitems, to differentiate them clearly from completion 
 * strings. When an action is selected, the ::action-activated signal 
 * is emitted. 
 */
public class EntryCompletion extends GObject {

	/**
	 * Creates a new EntryCompletion object.
	 *
	 */
	public EntryCompletion() {
		super(gtk_entry_completion_new());
		initializeEventHandlers();
	}
	
	public EntryCompletion(int nativeHandle) {
		super(nativeHandle);
		initializeEventHandlers();
	}
	
	/**
	 * Returns the Entry this completion is attached to.
	 * @return
	 */
	public Entry getEntry() {
		int hndl = gtk_entry_completion_get_entry(getHandle());
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Entry)obj;
		return new Entry(hndl);
	}
	
	/**
	 * Sets the model for this EntryCompletion.  If there is already
	 * a model set it will remove it before setting the new mode.
	 * @param model
	 */
	public void setModel(TreeModel model) {
		gtk_entry_completion_set_model(getHandle(), model.getHandle());
	}
	
	/**
	 * Returns the model that the EntryCompletion is using as a data
	 * source.
	 * @return
	 */
	public TreeModel getModel() {
		int hndl = gtk_entry_completion_get_model(getHandle());
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (TreeModel)obj;
		return new TreeModel(hndl);
	}
	
	/**
	 * Requires the length of the search key for the EntryCompletion to be
	 * at least <i>length</i>.  This is useful for long lists where completing
	 * using a small key takes a lot of time and will come up with meaningless
	 * results.
	 * @param length
	 */
	public void setMinimumKeyLength(int length) {
		gtk_entry_completion_set_minimum_key_length(getHandle(), length);
	}
	
	/**
	 * Returns the minimum key length as set for completion.
	 * @return
	 */
	public int getMinimumKeyLength() {
		return gtk_entry_completion_get_minimum_key_length(getHandle());
	}
	
	/**
	 * Requests a completion operation, or in other words a refiltering
	 * of the current list with completions, using the current key. 
	 */
	public void complete() {
		gtk_entry_completion_complete(getHandle());
	}
	
	/**
	 * Inserts an action in the EntryCompletion's action list with the
	 * position and text provided.  If this item is selected an event
	 * will be triggered of type ACTION_ACTIVATED.  You can get the
	 * index value from the EntryCompletionEvent object.
	 * @param index
	 * @param text
	 */
	public void insertActionText(int index, String text) {
		gtk_entry_completion_insert_action_text(getHandle(), index, text);
	}
	
	/**
	 * Inserts an action in the EntryCompletion's action list with the
	 * position and text provided.  If this item is selected an event
	 * will be triggered of type ACTION_ACTIVATED.  You can get the
	 * index value from the EntryCompletionEvent object.
	 * @param index
	 * @param markup
	 */
	public void insertActionMarkup(int index, String markup) {
		gtk_entry_completion_insert_action_markup(getHandle(), index, markup);
	}
	
	/**
	 * Remove an action for the EntryCompletions action list.
	 * @param index
	 */
	public void deleteAction(int index) {
		gtk_entry_completion_delete_action(getHandle(), index);
	}
	
	/**
	 * Specify which column in the model to use to display the strings.
	 * @param column
	 */
	public void setTextColumn(int column) {
		gtk_entry_completion_set_text_column(getHandle(), column);
	}
	
	/* **************************************
	 * EVENT LISTENERS
	 ****************************************/

	/**
	 * Listeners for handling dialog events
	 */
	private Vector ecListeners = null;

	/**
	 * Register an object to handle dialog events.
	 * @see EntryCompletionListener
	 */
	public void addListener(EntryCompletionListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(ecListeners, listener);
		if (i == -1) {
			if (null == ecListeners) {
				ecListeners = new Vector();
			}
			ecListeners.addElement(listener);
		}
	}
	
	/**
	 * Removes a listener
	 * @see #addListener(EntryCompletionListener)
	 */
	public void removeListener(EntryCompletionListener listener) {
		int i = findListener(ecListeners, listener);
		if (i > -1) {
			ecListeners.remove(i);
		}
		if (0 == ecListeners.size()) {
			ecListeners = null;
		}
	}

	protected void fireEntrySelectionEvent(EntryCompletionEvent event) {
		if (null == ecListeners) {
			return;
		}
		int size = ecListeners.size();
		int i = 0;
		while (i < size) {
			EntryCompletionListener ecl = (EntryCompletionListener)ecListeners.elementAt(i);
			ecl.entryCompletionEvent(event);
			i++;
		}
	}

	private boolean handleMatchSelected(int model, int iter) {
		EntryCompletionEvent evt = new EntryCompletionEvent(this, EntryCompletionEvent.Type.MATCH_SELECTED);
		TreeModel tm;
		GObject obj = retrieveGObject(model);
		if (null != obj)
			tm = (TreeModel)obj;
		else
			tm = new TreeModel(model);
		evt.setModel(tm);
		evt.setIter(new TreeIter(iter, tm));
		fireEntrySelectionEvent(evt);
		return true;
	}

	private void handleActionActivated(int index) {
		EntryCompletionEvent evt = new EntryCompletionEvent(this, EntryCompletionEvent.Type.ACTION_ACTIVATED);
		evt.setIndex(index);
		fireEntrySelectionEvent(evt);
	}

	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);
	}

	/**
	 * 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("match_selected", "handleMatchSelected", EntryCompletionEvent.Type.MATCH_SELECTED, EntryCompletionListener.class);
		anEvtMap.addEvent("action_activated", "handleActionActivated", EntryCompletionEvent.Type.ACTION_ACTIVATED, EntryCompletionListener.class);
	}

	/**
	 * 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 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_entry_completion_get_type ();
	native static final protected int gtk_entry_completion_new();
	native static final protected int gtk_entry_completion_get_entry(int completion);
	native static final protected void gtk_entry_completion_set_model(int completion, int model);
	native static final protected int gtk_entry_completion_get_model(int completion);
	native static final protected void gtk_entry_completion_set_minimum_key_length(int completion, int length);
	native static final protected int gtk_entry_completion_get_minimum_key_length(int completion);
	native static final protected void gtk_entry_completion_complete(int completion);
	native static final protected void gtk_entry_completion_insert_action_text(int completion, int index, String text);
	native static final protected void gtk_entry_completion_insert_action_markup(int completion, int index, String markup);
	native static final protected void gtk_entry_completion_delete_action(int completion, int index);
	native static final protected void gtk_entry_completion_set_text_column(int completion,  int column);
	/****************************************
	 * END OF JNI CODE
	 ****************************************/
}
