/**
 * vim: sw=4 ts=4:
 *
 * Gnome Apt GtkTreeModel implementation
 *
 * 	(C) 2002-2004 Filip Van Raemdonck <mechanix@debian.org>
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 * 	$Id$
 *
 **/

#include <string.h>
#include <gtk/gtktreemodel.h>
#include <gtk/gtkwidget.h>
#include "gapttreemodel.h"
#include "pkgtree.h"

struct _GAptTreeModelPrivate {
	GAptPkgTree* tree;
	gint stamp;
};

static GObjectClass* parent_class = NULL;

/* GObject code */
static void gapt_tree_model_init (GAptTreeModel*);
static void gapt_tree_model_class_init (GAptTreeModelClass*);

/* GtkTreeModel signals */
static void gapt_tree_model_row_changed (GtkTreeModel*, GtkTreePath*, GtkTreeIter*);
static void gapt_tree_model_row_inserted (GtkTreeModel*, GtkTreePath*, GtkTreeIter*);
static void gapt_tree_model_row_has_child_toggled (GtkTreeModel*, GtkTreePath*, GtkTreeIter*);
static void gapt_tree_model_row_deleted (GtkTreeModel*, GtkTreePath*);
static void gapt_tree_model_rows_reordered (GtkTreeModel*, GtkTreePath*, GtkTreeIter*, gint*);

/* GtkTreeModel interface */
static GtkTreeModelFlags gapt_tree_model_get_flags (GtkTreeModel*);
static gint gapt_tree_model_get_n_columns (GtkTreeModel*);
static GType gapt_tree_model_get_column_type (GtkTreeModel*, gint);
static gboolean gapt_tree_model_get_iter (GtkTreeModel*, GtkTreeIter*, GtkTreePath*);
static GtkTreePath* gapt_tree_model_get_path (GtkTreeModel*, GtkTreeIter*);
static void gapt_tree_model_get_value (GtkTreeModel*, GtkTreeIter*, gint, GValue*);
static gboolean gapt_tree_model_iter_next (GtkTreeModel*, GtkTreeIter*);
static gboolean gapt_tree_model_iter_children (GtkTreeModel*, GtkTreeIter*, GtkTreeIter*);
static gboolean gapt_tree_model_iter_has_child (GtkTreeModel*, GtkTreeIter*);
static gint gapt_tree_model_iter_n_children (GtkTreeModel*, GtkTreeIter*);
static gboolean gapt_tree_model_iter_nth_child (GtkTreeModel*, GtkTreeIter*, GtkTreeIter*, gint);
static gboolean gapt_tree_model_iter_parent (GtkTreeModel*, GtkTreeIter*, GtkTreeIter*);
#if 0
static void gapt_tree_model_ref_node (GtkTreeModel*, GtkTreeIter*);
static void gapt_tree_model_unref_node (GtkTreeModel*, GtkTreeIter*);
#endif

static void
gapt_tree_model_model_init (GtkTreeModelIface *iface) {
	iface->get_flags = gapt_tree_model_get_flags;
	iface->get_n_columns = gapt_tree_model_get_n_columns;
	iface->get_column_type = gapt_tree_model_get_column_type;
	iface->get_iter = gapt_tree_model_get_iter;
	iface->get_path = gapt_tree_model_get_path;
	iface->get_value = gapt_tree_model_get_value;
	iface->iter_next = gapt_tree_model_iter_next;
	iface->iter_children = gapt_tree_model_iter_children;
	iface->iter_has_child = gapt_tree_model_iter_has_child;
	iface->iter_n_children = gapt_tree_model_iter_n_children;
	iface->iter_nth_child = gapt_tree_model_iter_nth_child;
	iface->iter_parent = gapt_tree_model_iter_parent;
	iface->ref_node = NULL;/*gapt_tree_model_ref_node;*/
	iface->unref_node = NULL;/*gapt_tree_model_unref_node;*/
}

#ifdef GAPT_DO_SORTABLE_TREE
static void
gapt_tree_model_sortable_init (GtkTreeSortableIface *iface) {
}
#endif

GType
gapt_tree_model_get_type (void)
{
	static GType type = 0;

	if (!type) {
		static const GTypeInfo info = {
			sizeof (GAptTreeModelClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) gapt_tree_model_class_init,
			(GClassFinalizeFunc) NULL,
			NULL, /* class_data */
			sizeof (GAptTreeModel),
			0, /* n_preallocs */
			(GInstanceInitFunc) gapt_tree_model_init,
		};
		static const GInterfaceInfo model_info = {
			(GInterfaceInitFunc) gapt_tree_model_model_init,
			NULL, NULL
		};
#ifdef GAPT_DO_SORTABLE_TREE
		static const GInterfaceInfo sortable_info = {
			(GInterfaceInitFunc) gapt_tree_model_sortable_init,
			NULL, NULL
		};
#endif

		type = g_type_register_static (G_TYPE_OBJECT, "GAptTreeModel", &info, (GTypeFlags) 0);
		g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL, &model_info);
#ifdef GAPT_DO_SORTABLE_TREE
		g_type_add_interface_static (type, GTK_TYPE_TREE_SORTABLE, &sortable_info);
#endif
	}

	return type;
}

static void
gapt_tree_model_init (GAptTreeModel* model) {
}

static void
gapt_tree_model_class_init (GAptTreeModelClass* klass) {
	parent_class = G_OBJECT_CLASS (g_type_class_peek_parent ((GObjectClass*) klass));
}

static GtkTreeModelFlags
gapt_tree_model_get_flags (GtkTreeModel* self) {
	g_return_val_if_fail (self != NULL, (GtkTreeModelFlags) 0);
	g_return_val_if_fail (GTK_IS_TREE_MODEL (self), (GtkTreeModelFlags) 0);

	return (GtkTreeModelFlags) 0;
}

GAptTreeModel*
gapt_tree_model_new (GAptPkgTree* pkgtree) {
	GAptTreeModel* tm = GAPT_TREE_MODEL (g_object_new (GAPT_TYPE_TREE_MODEL, NULL));
	tm->_priv = g_new0 (GAptTreeModelPrivate, 1);
	tm->_priv->tree = pkgtree;

	return tm;
}

static gint
gapt_tree_model_get_n_columns (GtkTreeModel*) {
	/* Returns the number of columns supported by tree_model. */
	return 1;
}

static GType
gapt_tree_model_get_column_type (GtkTreeModel*, gint col) {
	if (col == 0) {
		return G_TYPE_STRING;
	}
	g_warning ("Function called: %s (column: %d)", __PRETTY_FUNCTION__, col);
	/* Returns the type of the column. */
	return G_TYPE_NONE;
};

static gboolean
gapt_tree_model_get_iter (GtkTreeModel* model, GtkTreeIter* iter, GtkTreePath* path) {
	if (!strcmp (gtk_tree_path_to_string (path), "0")) {
		iter->stamp = GAPT_TREE_MODEL (model)->_priv->stamp;
		TreeNode* it = GAPT_TREE_MODEL (model)->_priv->tree->root();
		it->cur = it->begin();
		iter->user_data = it;
		return TRUE;
	}
	g_warning ("Function called: %s (path: %s)", __PRETTY_FUNCTION__, gtk_tree_path_to_string (path));
	/* Sets iter to a valid iterator pointing to path. */
	return FALSE;
};

static GtkTreePath*
gapt_tree_model_get_path (GtkTreeModel*, GtkTreeIter*) {
	g_warning ("Function called: %s", __PRETTY_FUNCTION__);
	/* Returns a newly-created GtkTreePath referenced by iter. */
	return NULL;
};

static void
gapt_tree_model_get_value (GtkTreeModel*, GtkTreeIter*, gint, GValue*) {
	g_warning ("Function called: %s", __PRETTY_FUNCTION__);
};

static gboolean
gapt_tree_model_iter_next (GtkTreeModel*, GtkTreeIter*) {
	g_warning ("Function called: %s", __PRETTY_FUNCTION__);
	/* Sets iter to point to the node following it at the current level. If
	 * there is no next iter, FALSE is returned and iter is set to be invalid.
	 */
	return FALSE;
};

static gboolean
gapt_tree_model_iter_children (GtkTreeModel*, GtkTreeIter*, GtkTreeIter*) {
	g_warning ("Function called: %s", __PRETTY_FUNCTION__);
	/* Sets iter to point to the first child of parent. If parent has no
	 * children, FALSE is returned and iter is set to be invalid. parent will
	 * remain a valid node after this function has been called.
	 * If parent is NULL returns the first node, equivalent to
	 * gtk_tree_model_get_iter_first (tree_model, iter);
	 */
	return FALSE;
};

static gboolean
gapt_tree_model_iter_has_child (GtkTreeModel* model, GtkTreeIter* iter) {
	if (iter->stamp != GAPT_TREE_MODEL (model)->_priv->stamp) {
		return FALSE;
	}

	TreeNode* it = (TreeNode*) iter->user_data;
	if (it->cur == it->end()) {
		return FALSE;
	}

	g_warning ("Function called: %s (node: %s)", __PRETTY_FUNCTION__,
	      ((GAptPkgTree::Item*) *(it->cur))->name());
	/* Returns TRUE if iter has children, FALSE otherwise. */
	return FALSE;
};

static gint
gapt_tree_model_iter_n_children (GtkTreeModel*, GtkTreeIter*) {
	g_warning ("Function called: %s", __PRETTY_FUNCTION__);
	/* Returns the number of children that iter has. As a special case, if
	 * iter is NULL, then the number of toplevel nodes is returned.
	 */
	return 0;
};

static gboolean
gapt_tree_model_iter_nth_child (GtkTreeModel* model, GtkTreeIter*, GtkTreeIter* parent, gint) {
	if (!parent || parent->stamp != GAPT_TREE_MODEL (model)->_priv->stamp) {
		return FALSE;
	}

	g_warning ("Function called: %s", __PRETTY_FUNCTION__);
	/* Sets iter to be the child of parent, using the given index. The first
	 * index is 0. If n is too big, or parent has no children, iter is set to
	 * an invalid iterator and FALSE is returned. parent will remain a valid
	 * node after this function has been called. As a special case, if parent
	 * is NULL, then the nth root node is set.
	 */
	return FALSE;
};

static gboolean
gapt_tree_model_iter_parent (GtkTreeModel*, GtkTreeIter*, GtkTreeIter*) {
	g_warning ("Function called: %s", __PRETTY_FUNCTION__);
	/* Sets iter to be the parent of child. If child is at the toplevel, and
	 * doesn't have a parent, then iter is set to an invalid iterator and
	 * FALSE is returned. child will remain a valid node after this function
	 * has been called.
	 */
	return FALSE;
};

#if 0
static void
gapt_tree_model_ref_node (GtkTreeModel*, GtkTreeIter*) {
	g_warning ("Function called: %s", __PRETTY_FUNCTION__);
};

static void
gapt_tree_model_unref_node (GtkTreeModel*, GtkTreeIter*) {
	g_warning ("Function called: %s", __PRETTY_FUNCTION__);
};
#endif

#include <gtk/gtk.h>
#include <apt-pkg/init.h>
#include <apt-pkg/error.h>

int main (int argc, char* argv[]) {
	GtkWidget* col;

	gtk_init (&argc, &argv);
	GtkWidget* win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_default_size (GTK_WINDOW (win), 800, 600);
	g_signal_connect (G_OBJECT (win), "destroy", G_CALLBACK (gtk_main_quit), NULL);

	if (!pkgInitConfig (*_config) || !pkgInitSystem (*_config, _system)) {
		_error->DumpErrors();
		return FALSE;
	}
	_config->Set ("Debug::NoLocking", true);

	OpTextProgress progress;
	GAptCacheFile* cachefile = gnome_apt_cache_file_init (&progress);
	if (!cachefile) {
		_error->DumpErrors();
		return FALSE;
	}

	GAptPkgTree* pkgtree = new GAptPkgTree;
	cachefile->add_view (pkgtree);

	GAptTreeModel* store = gapt_tree_model_new (pkgtree);

	GtkWidget* tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
	gtk_container_add (GTK_CONTAINER (win), tree);

	gtk_widget_show_all (win);
	gtk_main();
	
	return 0;
}
