/*
 * 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 org.gnu.glib.Type;
import org.gnu.glib.Value;

/**
 * The ListStore is the gtk Model used for constructing Lists and tables to be
 * displayed within {@link TreeView} widgets. For full details of what objects
 * are needed to construct lists and tables, please see the {@link TreeView}
 * description.
 *
 * <p>The list store has a number of {@link DataColumn}s, or data 'columns' associated
 * with it. These do <em>not</em> correspond to the organisation of the output
 * into columns. The data store can in fact be used with any number of treeView
 * widgets, each displaying a different part of the data. In these Java
 * bindings, we will try to use the term dataBlock for the data in the ListStore
 * and Column to refer to the columns to be displayed. The data to be displayed
 * is set in the {@link TreeViewColumn} objects, by associating properties of
 * {@link CellRenderer}'s with the data block used in this object.
 *
 * @author Mark Howard &lt;mh@debian.org&gt;
 */
public class ListStore extends TreeModel implements TreeSortable, TreeDragSource, TreeDragDest
{
	/**
	 * Constructs a new ListStore object for storing data in a list style
	 * manner. The data is stored in a set of numbered data blocks, each one of
	 * which can then be displayed in a column by setting the appropriate
	 * attribute mapping of the CellRenderers.
	 * @param dataColumns a list of dataColumns for the store. These should be
	 * created as private variables of the required type - they will be needed
	 * later.
	 */
	public ListStore(DataColumn[] dataColumns){
		super(init(dataColumns));
	}
	
	private static int init(DataColumn[] dataColumns) { 
		int[] intTypes = new int[ dataColumns.length ];
		for (int i=0; i<intTypes.length; i++){
			intTypes[i] = dataColumns[i].getType().getHandle();
			dataColumns[i].setColumn(i);
		}
		return gtk_list_store_newv(dataColumns.length, intTypes);
	}

	public void setColumnTypes(DataColumn[] dataColumns) {
		int[] intTypes = new int[ dataColumns.length ];
		for (int i=0; i<intTypes.length; i++){
			intTypes[i] = dataColumns[i].getType().getHandle();
			dataColumns[i].setColumn(i);
		}
		gtk_list_store_set_column_types(getHandle(), dataColumns.length, intTypes);
	}

	/**
	 * Sets a value in the data store. To display the data in the widget, you
	 * need to associate the datablock with the renderer, using methods of the
	 * {@link TreeViewColumn}.
	 * @param iter A valid iterator which specifies the row in which the data
	 * should be set.  Iterators can be gained by using methods such as 
	 * {@link #appendRow()}.
	 * @param dataBlock The data block to store the value in.
	 * @param value The value to store. This <em>must</em> be of the same type
	 * for the column as that set in the constructor to the ListStore.
	 */
	public void setValue( TreeIter iter, DataColumnString dataBlock, String value){
		Value val = new Value( Type.STRING() );
		val.setString( value );
		gtk_list_store_set_value(getHandle(), iter.getHandle(), dataBlock.getColumn(), val.getHandle() );
	}

	/**
	 * Sets a value in the dataStore. The type of the value <em>must</em> match
	 * the type set for that dataBlock in the constructor.  <p>This does not
	 * make the data visible in any of the widgets which use the class - to do
	 * that, you have to construct a {@link TreeViewColumn} and add it to the
	 * {@link TreeView}; construct and add a {@link CellRenderer} to that; and
	 * finally associate the properties of the CellRenderer with the dataBlocks,
	 * using the {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
	 * int)} method.  @param dataBlock The datablock in which the data should be
	 * stored.
	 * @param dataBlock The data block in which to store the data
	 * @param iter Valid iterator for the data row in which the value is to be
	 * set. These can be gotten using methods such as {@link #appendRow(TreeIter)}.
	 * @param value The value to be set. 
	 */
	public void setValue(TreeIter iter, DataColumnStockItem dataBlock, GtkStockItem value) {
		Value val = new Value(Type.STRING());
		val.setString( value.getString() );
		gtk_list_store_set_value(getHandle(), iter.getHandle(), dataBlock.getColumn(), val.getHandle());
	}
	
	/**
	 * Sets a value in the dataStore. The type of the value <em>must</em> match
	 * the type set for that dataBlock in the constructor.  <p>This does not
	 * make the data visible in any of the widgets which use the class - to do
	 * that, you have to construct a {@link TreeViewColumn} and add it to the
	 * {@link TreeView}; construct and add a {@link CellRenderer} to that; and
	 * finally associate the properties of the CellRenderer with the dataBlocks,
	 * using the {@link TreeViewColumn#addAttributeMapping(CellRenderer, CellRendererAttribute,
	 * int)} method.  @param dataBlock The datablock in which the data should be
	 * stored.
	 * @param dataBlock The data block in which to store the data
	 * @param iter Valid iterator for the data row in which the value is to be
	 * set. These can be gotten using methods such as {@link #appendRow(TreeIter)}.
	 * @param value The value to be set.
	 */
	public void setValue(TreeIter iter, DataColumnIconSize dataBlock, IconSize value) {
		Value val = new Value(Type.INT());
		val.setInteger(value.getValue());
		gtk_list_store_set_value(getHandle(), iter.getHandle(), dataBlock.getColumn(), val.getHandle());
	}

	
	/**
	 * Sets a value in the data store. To display the data in the widget, you
	 * need to associate the datablock with the renderer, using methods of the
	 * {@link TreeViewColumn}.
	 * @param iter A valid iterator which specifies the row in which the data
	 * should be set.  Iterators can be gained by using methods such as 
	 * {@link #appendRow()}.
	 * @param dataBlock The data block to store the value in. 
	 * @param value The value to store. This <em>must</em> be of the same type
	 * for the column as that set in the constructor to the ListStore.
	 */
	public void setValue( TreeIter iter, DataColumnInt dataBlock, int value){
		Value val = new Value( Type.INT() );
		val.setInteger( value );
		gtk_list_store_set_value(getHandle(), iter.getHandle(), dataBlock.getColumn(), val.getHandle() );
	}
	
	/**
	 * Sets a value in the data store. To display the data in the widget, you
	 * need to associate the datablock with the renderer, using methods of the
	 * {@link TreeViewColumn}.
	 * @param iter A valid iterator which specifies the row in which the data
	 * should be set.  Iterators can be gained by using methods such as 
	 * {@link #appendRow()}.
	 * @param dataBlock The data block to store the value in.
	 * @param value The value to store. This <em>must</em> be of the same type
	 * for the column as that set in the constructor to the ListStore.
	 */
	public void setValue( TreeIter iter, DataColumnBoolean dataBlock, boolean value){
		Value val = new Value( Type.BOOLEAN() );
		val.setBoolean( value );
		gtk_list_store_set_value(getHandle(), iter.getHandle(), dataBlock.getColumn(), val.getHandle() );
	}
	
	/**
	 * Sets a value in the data store. To display the data in the widget, you
	 * need to associate the datablock with the renderer, using methods of the
	 * {@link TreeViewColumn}.
	 * @param iter A valid iterator which specifies the row in which the data
	 * should be set.  Iterators can be gained by using methods such as 
	 * {@link #appendRow()}.
	 * @param dataBlock The data block to store the value in. 
	 * @param value The value to store. 
	 */
	public void setValue( TreeIter iter, DataColumnDouble dataBlock, double value){
		Value val = new Value( Type.DOUBLE() );
		val.setDouble( value );
		gtk_list_store_set_value(getHandle(), iter.getHandle(), dataBlock.getColumn(), val.getHandle() );
	}

		/**
	 * Sets a value in the dataStore. The type of the value <em>must</em> match
	 * the type set for that dataBlock in the constructor.  
	 * @param dataBlock The datablock in which the data should be
	 * stored.
	 * @param dataBlock The data block in which to store the data
	 * @param iter Valid iterator for the data row in which the value is to be
	 * set. These can be gotten using methods such as {@link #appendRow(TreeIter)}.
	 * @param value The value to be set.
	 */
	public void setValue(TreeIter iter, DataColumnObject dataBlock, Object value) {
		Value val = new Value(Type.JAVA_OBJECT());
		val.setJavaObject(value);
		gtk_list_store_set_value(getHandle(), iter.getHandle(), dataBlock.getColumn(), val.getHandle());
	}

	/**
	 * Sets a value in the dataStore. The type of the value <em>must</em> match
	 * the type set for that dataBlock in the constructor.  <p>This does not
	 * make the data visible in any of the widgets which use the class 
	 * @param dataBlock The datablock in which the data should be
	 * stored.
	 * @param dataBlock The data block in which to store the data, starting at
	 * 0.
	 * @param iter Valid iterator for the data row in which the value is to be
	 * set. These can be gotten using methods such as {@link #appendRow(TreeIter)}.
	 * @param value The value to be set. This <em>must</em> match the type for
	 * that dataBlock, as set in the constructor.
	 */
	public void setValue(TreeIter iter, DataColumnPixbuf dataBlock, org.gnu.gdk.Pixbuf value) {
          Value val = new Value(Type.PIXBUF());
          val.setPixbuf(value);
          gtk_list_store_set_value(getHandle(), iter.getHandle(), dataBlock.getColumn(), val.getHandle());
 	}


	/**
	 * Removes the given row from the list store. After being removed, 
	 * <code>iter</code> is set to be the next valid row, or invalidated if it 
	 * pointed to the last row in this store.
	 * @paramTreeIter iterator for the row to be removed.
	 * @return TRUE if iter is valid, FALSE if not.
	 */
	public boolean removeRow(TreeIter iter){
		return gtk_list_store_remove(getHandle(), iter.getHandle());
	}

	/**
	 * Creates a new row at <code>position</code>. If position is larger than the 
	 * number of rows on the list, then the new row will be appended to the list. 
	 * @param position The position to place the new row, starting at 0.
	 * @return Iterator for the new row
	 */
	public TreeIter insertRow(int position){
		return new TreeIter( gtk_list_store_insert(getHandle(), position), (TreeModel) this );
	}
	
	/**
	 * Inserts a new row before sibling. If sibling is NULL, then the row will
	 * be appended to the end of the list. iter will be changed to point to this
	 * new row.
	 * @param sibling 
	 * @return Iterator for the new row
	 */
	public TreeIter insertRowBefore(TreeIter sibling){
		return new TreeIter( gtk_list_store_insert_before(getHandle(), sibling.getHandle()), (TreeModel) this  );
	}

	/**
	 * Inserts a new row after sibling. If sibling is NULL, then the row will be 
	 * prepended to the beginning of the list. iter will be changed to point 
	 * to this new row.
	 * @param sibling
	 * @return Iterator for the new row.
	 */
	public TreeIter insertRowAfter(TreeIter sibling){
		return new TreeIter( gtk_list_store_insert_after(getHandle(), sibling.getHandle()), (TreeModel) this  );
	}

	/**
	 * Prepends a new row to list_store. iter will be changed to point to this 
	 * new row. The row will be empty after this function is called. 
	 * @return Iterator for the new row
	 */
	public TreeIter prependRow(){
		return new TreeIter( gtk_list_store_prepend(getHandle()), (TreeModel) this  );
	}

	/**
	 * Appends a new row to the store
	 * @return Iterator for the new row
	 */
	public TreeIter appendRow(){
		return new TreeIter( gtk_list_store_append(getHandle()), (TreeModel) this  );
	}

	/**
	 * Removes all rows from the list store.
	 */
	public void clear(){
		gtk_list_store_clear(getHandle());
	}

	/**
	 * Retrieve the runtime type used by the GLib library.
	 */
	public static Type getType() {
		return new Type(gtk_list_store_get_type());
	}
	public void setSortColumn( DataColumn column, SortType order ){
		// TODO
		throw new RuntimeException("Not yet implemented");
	}
	public void setSortMethod( TreeIterComparison method, DataColumn column ){	
		// TODO
		throw new RuntimeException("Not yet implemented");
	}

	public void setDragDestListener( TreeDragDestListener listener ){
		// TODO
		throw new RuntimeException("Not yet implemented");
	}

	public void setDragSourceListener( TreeDragSourceListener listener ){
		// TODO
		throw new RuntimeException("Not yet implemented");
	}

	/**
	 * Swaps a and b in the same level of tree_store. Note that this function
	 * only works with unsorted stores.
	 *
	 * @since 2.2
	 */
	public void swapRows( TreeIter a, TreeIter b ){
		gtk_list_store_swap(getHandle(), a.getHandle(), b.getHandle());
	}

	/**
	 * Moves iter to the end of the model
	 *
	 * @since 2.2
	 */
	public void moveRowToEnd(TreeIter iter ){
		gtk_list_store_move_before(getHandle(), iter.getHandle(), 0);
	}

	/**
	 * Moves iter in this store to the position after position. iter and
	 * position should be in the same level. Note that this function only works
	 * with unsorted stores.
	 *
	 * @since 2.2
	 */
	public void moveRowAfter(TreeIter iter, TreeIter position ){
		gtk_list_store_move_after(getHandle(), iter.getHandle(), position.getHandle());
	}

	/**
	 * Moves iter in this store to the start of the store.
	 *
	 * @since 2.2
	 */
	public void moveRowToStart(TreeIter iter ){
		gtk_list_store_move_after(getHandle(), iter.getHandle(), 0);
	}

	/**
	 * Moves iter in store to the position before position. iter and
	 * position should be in the same level. Note that this function only works
	 * with unsorted stores.
	 *
	 * @since 2.2
	 */
	public void moveRowBefore(TreeIter iter, TreeIter position ){
		gtk_list_store_move_before(getHandle(), iter.getHandle(), position.getHandle());
	}

	public boolean isIterValid(TreeIter iter) {
		return gtk_list_store_iter_is_valid(getHandle(), iter.getHandle());
	}
	
	public void reorder(int[] newOrder) {
		gtk_list_store_reorder(getHandle(), newOrder);
	}

    /****************************************
     * BEGINNING OF JNI CODE
     ****************************************/
//    native static final protected int getRoot (int cptr);
//    native final protected void setRoot (int cptr, int root);
//    native static final protected int getTail (int cptr);
//    native final protected void setTail (int cptr, int tail);
//    native static final protected int getNColumns (int cptr);
//    native final protected void setNColumns (int cptr, int n_columns);
    native static final protected int getSortColumnId (int cptr);
    native final protected void setSortColumnId (int cptr, int sort_column_id);
    native static final protected int getOrder (int cptr);
    native final protected void setOrder (int cptr, int order);
//    native static final protected int getColumnHeaders (int cptr);
//    native final protected void setColumnHeaders (int cptr, int column_headers);
//    native static final protected int getLength (int cptr);
//    native final protected void setLength (int cptr, int length);
//    native static final protected boolean getColumnsDirty (int cptr);
//    native final protected void setColumnsDirty (int cptr, boolean columns_dirty);
    native static final protected int gtk_list_store_get_type ();
    native static final protected int gtk_list_store_newv (int numColumns, int [] types);
    native static final protected void gtk_list_store_set_column_types (int listStore, int numColumns, int [] types);
    native static final protected void gtk_list_store_set_value (int listStore, int iter, int column, int value);
    native static final protected boolean gtk_list_store_remove (int listStore, int iter);
    native static final protected int gtk_list_store_insert (int listStore, int position);
    native static final protected int gtk_list_store_insert_before (int listStore, int sibling);
    native static final protected int gtk_list_store_insert_after (int listStore, int sibling);
    native static final protected int gtk_list_store_prepend (int listStore);
    native static final protected int gtk_list_store_append (int listStore);
    native static final protected void gtk_list_store_clear (int listStore);
    native static final protected boolean gtk_list_store_iter_is_valid(int listStore, int iter);
    native static final protected void gtk_list_store_reorder(int listStore, int[] newOrder);
    native static final protected void gtk_list_store_swap(int listStore, int iterA, int iterB);
    native static final protected void gtk_list_store_move_after(int listStore, int iter, int position);
    native static final protected void gtk_list_store_move_before(int listStore, int iter, int position);
    /****************************************
     * END OF JNI CODE
     ****************************************/
}

