/*
   Copyright (C) 2001-2006, William Joseph.
   All Rights Reserved.

   This file is part of GtkRadiant.

   GtkRadiant 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.

   GtkRadiant 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 GtkRadiant; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "treemodel.h"
#include "globaldefs.h"

#include "debugging/debugging.h"

#include <map>
#include <gtk/gtk.h>
#include <uilib/uilib.h>

#include "iscenegraph.h"
#include "nameable.h"

#include "generic/callback.h"
#include "scenelib.h"
#include "string/string.h"
#include "generic/reference.h"

inline Nameable* Node_getNameable( scene::Node& node ){
	return NodeTypeCast<Nameable>::cast( node );
}

#if 0

#include "gtkutil/gtktreestore.h"

template<typename value_type>
inline void gtk_tree_model_get_pointer( ui::TreeModel model, GtkTreeIter* iter, gint column, value_type** pointer ){
	GValue value = GValue_default();
	gtk_tree_model_get_value( model, iter, column, &value );
	*pointer = (value_type*)g_value_get_pointer( &value );
}


typedef GtkTreeStore GraphTreeModel;

ui::TreeStore graph_tree_model_new( graph_type* graph ){
	return gtk_tree_store_new( 2, G_TYPE_POINTER, G_TYPE_POINTER );
}

void graph_tree_model_delete( GraphTreeModel* model ){
	g_object_unref( G_OBJECT( model ) );
}


bool graph_tree_model_subtree_find_node( GraphTreeModel* model, GtkTreeIter* parent, const scene::Node& node, GtkTreeIter* iter ){
	for ( gboolean success = gtk_tree_model_iter_children( model, iter, parent );
		  success != FALSE;
		  success = gtk_tree_model_iter_next( model, iter ) )
	{
		scene::Node* current;
		gtk_tree_model_get_pointer( model, iter, 0, &current );
		if ( current == node ) {
			return true;
		}
	}
	return false;
}

typedef GtkTreeIter DoubleGtkTreeIter[2];

bool graph_tree_model_find_top( GraphTreeModel* model, const scene::Path& path, GtkTreeIter& iter ){
	int swap = 0;
	GtkTreeIter* parent_pointer = NULL;
	GtkTreeIter parent;
	for ( scene::Path::const_iterator i = path.begin(); i != path.end(); ++i )
	{
		if ( !graph_tree_model_subtree_find_node( model, parent_pointer, *i, &iter ) ) {
			return false;
		}
		parent = iter;
		parent_pointer = &parent;
	}
	return true;
}

bool graph_tree_model_find_parent( GraphTreeModel* model, const scene::Path& path, GtkTreeIter& iter ){
	int swap = 0;
	GtkTreeIter* parent_pointer = NULL;
	ASSERT_MESSAGE( path.size() > 1, "path too short" );
	for ( scene::Path::const_iterator i = path.begin(); i != path.end() - 1; ++i )
	{
		GtkTreeIter child;
		if ( !graph_tree_model_subtree_find_node( model, parent_pointer, *i, &child ) ) {
			return false;
		}
		iter = child;
		parent_pointer = &iter;
	}
	return true;
}

void node_attach_name_changed_callback( scene::Node& node, const Callback<void()>& callback ){
	if ( node != 0 ) {
		Nameable* nameable = Node_getNameable( node );
		if ( nameable != 0 ) {
			nameable->attach( callback );
		}
	}
}
void node_detach_name_changed_callback( scene::Node& node, const Callback<void()>& callback ){
	if ( node != 0 ) {
		Nameable* nameable = Node_getNameable( node );
		if ( nameable != 0 ) {
			nameable->detach( callback );
		}
	}
}

GraphTreeModel* scene_graph_get_tree_model(); // temp hack

void graph_tree_model_row_changed( const scene::Instance& instance ){
	GraphTreeModel* model = scene_graph_get_tree_model();

	GtkTreeIter child;
	ASSERT_MESSAGE( graph_tree_model_find_top( model, instance.path(), child ), "RUNTIME ERROR" );

	gtk_tree_store_set( GTK_TREE_STORE( model ), &child, 0, instance.path().top(), -1 );
}

void graph_tree_model_row_inserted( GraphTreeModel* model, const scene::Instance& instance ){
	GtkTreeIter parent;
	GtkTreeIter* parent_pointer = NULL;
	if ( instance.path().size() != 1 ) {
		ASSERT_MESSAGE( graph_tree_model_find_parent( model, instance.path(), parent ), "RUNTIME ERROR" );
		parent_pointer = &parent;
	}

	gpointer node = instance.path().top();
	gconstpointer selectable = Instance_getSelectable( instance );

	GtkTreeIter child;
	gtk_tree_store_append( GTK_TREE_STORE( model ), &child, parent_pointer );
	gtk_tree_store_set( GTK_TREE_STORE( model ), &child, 0, node, 1, selectable, -1 );

	node_attach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(), graph_tree_model_row_changed>( instance ) );
}

void graph_tree_model_row_deleted( GraphTreeModel* model, const scene::Instance& instance ){
	GtkTreeIter child;
	ASSERT_MESSAGE( graph_tree_model_find_top( model, instance.path(), child ), "RUNTIME ERROR" );

	node_detach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(), graph_tree_model_row_changed>( instance ) );

	gtk_tree_store_remove( GTK_TREE_STORE( model ), &child );
}

#elif 0

const char* node_get_name( scene::Node& node );

typedef scene::Node* NodePointer;

class NodeNameLess
{
public:
bool operator()( const NodePointer& self, const NodePointer& other ) const {
	if ( self == 0 ) {
		return true;
	}
	if ( other == 0 ) {
		return false;
	}
	int result = string_compare( node_get_name( self ), node_get_name( other ) );
	if ( result == 0 ) {
		return self < other;
	}
	return result < 0;
}
};

class PathNameLess
{
public:
bool operator()( const PathConstReference& self, const PathConstReference& other ) const {
	return std::lexicographical_compare( self.get().begin(), self.get().end(), other.get().begin(), other.get().end(), NodeNameLess() );
}
};

typedef std::map<PathConstReference, scene::Instance*, PathNameLess> graph_type;

struct GraphTreeModel
{
	GObject parent;

	graph_type* graph;
};

struct GraphTreeModelClass
{
	GObjectClass parent_class;
};

#define GRAPH_TREE_MODEL( p ) ( reinterpret_cast<GraphTreeModel*>( p ) )

static GtkTreeModelFlags graph_tree_model_get_flags( GtkTreeModel* tree_model ){
	return GTK_TREE_MODEL_ITERS_PERSIST;
}

static gint graph_tree_model_get_n_columns( ui::TreeModel tree_model ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	GraphTreeModel* graph_tree_model = (GraphTreeModel*) tree_model;

	return 2;
}

static const gint c_stamp = 0xabcdef;

inline graph_type::iterator graph_iterator_read_tree_iter( GtkTreeIter* iter ){
	ASSERT_MESSAGE( iter != 0,  "tree model error" );
	ASSERT_MESSAGE( iter->user_data != 0,  "tree model error" );
	ASSERT_MESSAGE( iter->stamp == c_stamp,  "tree model error" );
	return *reinterpret_cast<graph_type::iterator*>( &iter->user_data );
}

inline void graph_iterator_write_tree_iter( graph_type::iterator i, GtkTreeIter* iter ){
	ASSERT_MESSAGE( iter != 0,  "tree model error" );
	iter->stamp = c_stamp;
	*reinterpret_cast<graph_type::iterator*>( &iter->user_data ) = i;
	ASSERT_MESSAGE( iter->user_data != 0,  "tree model error" );
}

static GType graph_tree_model_get_column_type( ui::TreeModel tree_model, gint index ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	GraphTreeModel *graph_tree_model = (GraphTreeModel *) tree_model;

	return G_TYPE_POINTER;
}

static gboolean graph_tree_model_get_iter( ui::TreeModel tree_model, GtkTreeIter* iter, ui::TreePath path ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	gint* indices = gtk_tree_path_get_indices( path );
	gint depth = gtk_tree_path_get_depth( path );

	g_return_val_if_fail( depth > 0, FALSE );

	graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;

	if ( graph.empty() ) {
		return FALSE;
	}

	GtkTreeIter tmp;
	GtkTreeIter* parent = 0;

	for ( gint i = 0; i < depth; i++ )
	{
		if ( !gtk_tree_model_iter_nth_child( tree_model, iter, parent, indices[i] ) ) {
			return FALSE;
		}
		tmp = *iter;
		parent = &tmp;
	}

	return TRUE;
}

static ui::TreePath graph_tree_model_get_path( ui::TreeModel tree_model, GtkTreeIter* iter ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
	graph_type::iterator i = graph_iterator_read_tree_iter( iter );

	auto path = ui::TreePath();

	for ( std::size_t depth = ( *i ).first.get().size(); depth != 0; --depth )
	{
		std::size_t index = 0;

		while ( i != graph.begin() && ( *i ).first.get().size() >= depth )
		{
			--i;
			if ( ( *i ).first.get().size() == depth ) {
				++index;
			}
		}

		gtk_tree_path_prepend_index( path, index );
	}

	return path;
}


static void graph_tree_model_get_value( ui::TreeModel tree_model, GtkTreeIter  *iter, gint column, GValue *value ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	ASSERT_MESSAGE( column == 0 || column == 1, "tree model error" );

	graph_type::iterator i = graph_iterator_read_tree_iter( iter );

	g_value_init( value, G_TYPE_POINTER );

	if ( column == 0 ) {
		g_value_set_pointer( value, reinterpret_cast<gpointer>( ( *i ).first.get().top() ) );
	}
	else{
		g_value_set_pointer( value, reinterpret_cast<gpointer>( Instance_getSelectable( *( *i ).second ) ) );
	}
}

static gboolean graph_tree_model_iter_next( ui::TreeModel  tree_model, GtkTreeIter   *iter ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
	graph_type::iterator i = graph_iterator_read_tree_iter( iter );
	std::size_t depth = ( *i ).first.get().size();

	++i;

	while ( i != graph.end() && ( *i ).first.get().size() > depth )
	{
		++i;
	}

	if ( i == graph.end() || ( *i ).first.get().size() != depth ) {
		return FALSE;
	}

	graph_iterator_write_tree_iter( i, iter );

	return TRUE;
}

static gboolean graph_tree_model_iter_children( ui::TreeModel tree_model, GtkTreeIter  *iter, GtkTreeIter  *parent ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
	graph_type::iterator i = ( parent == 0 ) ? graph.begin() : graph_iterator_read_tree_iter( parent );
	std::size_t depth = ( parent == 0 ) ? 1 : ( *i ).first.get().size() + 1;

	if ( parent != 0 ) {
		++i;
	}

	if ( i != graph.end() && ( *i ).first.get().size() == depth ) {
		graph_iterator_write_tree_iter( i, iter );
		return TRUE;
	}

	return FALSE;
}

static gboolean graph_tree_model_iter_has_child( ui::TreeModel tree_model, GtkTreeIter  *iter ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
	graph_type::iterator i = graph_iterator_read_tree_iter( iter );
	std::size_t depth = ( *i ).first.get().size() + 1;

	return ++i != graph.end() && ( *i ).first.get().size() == depth;
}

static gint graph_tree_model_iter_n_children( ui::TreeModel tree_model, GtkTreeIter *parent ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
	graph_type::iterator i = ( parent == 0 ) ? graph.begin() : graph_iterator_read_tree_iter( parent );
	std::size_t depth = ( parent == 0 ) ? 1 : ( *i ).first.get().size() + 1;

	if ( parent != 0 ) {
		++i;
	}

	gint count = 0;
	while ( i != graph.end() && ( *i ).first.get().size() >= depth )
	{
		++count;
		++i;
	}

	return count;
}

static gboolean graph_tree_model_iter_nth_child( ui::TreeModel tree_model, GtkTreeIter  *iter, GtkTreeIter  *parent, gint n ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
	graph_type::iterator i = ( parent == 0 ) ? graph.begin() : graph_iterator_read_tree_iter( parent );
	std::size_t depth = ( parent == 0 ) ? 1 : ( *i ).first.get().size() + 1;

	if ( parent != 0 ) {
		++i;
	}

	while ( i != graph.end() && ( *i ).first.get().size() >= depth )
	{
		if ( ( *i ).first.get().size() == depth && n-- == 0 ) {
			graph_iterator_write_tree_iter( i, iter );
			return TRUE;
		}
		++i;
	}

	return FALSE;
}

static gboolean graph_tree_model_iter_parent( ui::TreeModel tree_model, GtkTreeIter  *iter, GtkTreeIter  *child ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	graph_type& graph = *GRAPH_TREE_MODEL( tree_model )->graph;
	graph_type::iterator i = graph_iterator_read_tree_iter( child );
	std::size_t depth = ( *i ).first.get().size();
	if ( depth == 1 ) {
		return FALSE;
	}
	else
	{
		do
		{
			--i;
		}
		while ( ( *i ).first.get().size() >= depth );
		graph_iterator_write_tree_iter( i, iter );
		return TRUE;
	}
}

static GObjectClass *g_parent_class = 0;

static void graph_tree_model_init( GraphTreeModel *graph_tree_model ){
	graph_tree_model->graph = 0;
}

static void graph_tree_model_finalize( GObject* object ){
	GraphTreeModel* graph_tree_model = GRAPH_TREE_MODEL( object );

	/* must chain up */
	( *g_parent_class->finalize )( object );
}

static void graph_tree_model_class_init( GraphTreeModelClass *class_ ){
	GObjectClass *object_class;

	g_parent_class = (GObjectClass*)g_type_class_peek_parent( class_ );
	object_class = (GObjectClass *) class_;

	object_class->finalize = graph_tree_model_finalize;
}

static void graph_tree_model_tree_model_init( GtkTreeModelIface *iface ){
	iface->get_flags = graph_tree_model_get_flags;
	iface->get_n_columns = graph_tree_model_get_n_columns;
	iface->get_column_type = graph_tree_model_get_column_type;
	iface->get_iter = graph_tree_model_get_iter;
	iface->get_path = graph_tree_model_get_path;
	iface->get_value = graph_tree_model_get_value;
	iface->iter_next = graph_tree_model_iter_next;
	iface->iter_children = graph_tree_model_iter_children;
	iface->iter_has_child = graph_tree_model_iter_has_child;
	iface->iter_n_children = graph_tree_model_iter_n_children;
	iface->iter_nth_child = graph_tree_model_iter_nth_child;
	iface->iter_parent = graph_tree_model_iter_parent;
}

static gboolean graph_tree_model_row_draggable( GtkTreeDragSource *drag_source, ui::TreePath path ){
#if GDEF_DEBUG
	gint depth = gtk_tree_path_get_depth( path );
#endif
	return gtk_tree_path_get_depth( path ) > 1;
}

static gboolean graph_tree_model_drag_data_delete( GtkTreeDragSource *drag_source, ui::TreePath path ){
	GtkTreeIter iter;

	if ( gtk_tree_model_get_iter( drag_source, &iter, path ) ) {
		graph_type::iterator i = graph_iterator_read_tree_iter( &iter );
		Path_deleteTop( ( *i ).first );
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

static gboolean graph_tree_model_drag_data_get( GtkTreeDragSource *drag_source, ui::TreePath path, GtkSelectionData *selection_data ){
	if ( gtk_tree_set_row_drag_data( selection_data, drag_source, path ) ) {
		return TRUE;
	}
	else
	{
		/* FIXME handle text targets at least. */
	}

	return FALSE;
}

static void graph_tree_model_drag_source_init( GtkTreeDragSourceIface *iface ){
	iface->row_draggable = graph_tree_model_row_draggable;
	iface->drag_data_delete = graph_tree_model_drag_data_delete;
	iface->drag_data_get = graph_tree_model_drag_data_get;
}

static gboolean graph_tree_model_drag_data_received( GtkTreeDragDest *drag_dest, ui::TreePath dest, GtkSelectionData *selection_data ){
	auto tree_model = drag_dest;

	GtkTreeModel *src_model = 0;
	GtkTreePath *src_path = 0;
	if ( gtk_tree_get_row_drag_data( selection_data, &src_model, &src_path )
		 && src_model == tree_model ) {
		/* Copy the given row to a new position */
		GtkTreeIter iter;

		if ( gtk_tree_model_get_iter( src_model, &iter, src_path ) ) {
			int bleh = 0;
		}
	}
	else
	{
		/* FIXME maybe add some data targets eventually, or handle text
		 * targets in the simple case.
		 */
	}

	return FALSE;
}

static gboolean graph_tree_model_row_drop_possible( GtkTreeDragDest *drag_dest, ui::TreePath dest_path, GtkSelectionData *selection_data ){
	gboolean retval = FALSE;

	GtkTreeModel *src_model = 0;
	GtkTreePath *src_path = 0;
	if ( gtk_tree_get_row_drag_data( selection_data, &src_model, &src_path ) != FALSE ) {
		/* can only drag to ourselves */
		if ( src_model == drag_dest ) {
			/* Can't drop into ourself. */
			if ( !gtk_tree_path_is_ancestor( src_path, dest_path ) ) {
				/* Can't drop if dest_path's parent doesn't exist */
				if ( gtk_tree_path_get_depth( dest_path ) > 1 ) {
					auto tmp = gtk_tree_path_copy( dest_path );
					gtk_tree_path_up( tmp );

					GtkTreeIter iter;
					retval = gtk_tree_model_get_iter( drag_dest, &iter, tmp );

					gtk_tree_path_free( tmp );
				}
			}
		}

		gtk_tree_path_free( src_path );
	}

	return retval;
}

static void graph_tree_model_drag_dest_init( GtkTreeDragDestIface *iface ){
	iface->drag_data_received = graph_tree_model_drag_data_received;
	iface->row_drop_possible = graph_tree_model_row_drop_possible;
}

GType graph_tree_model_get_type( void ){
	static GType graph_tree_model_type = 0;

	if ( !graph_tree_model_type ) {
		static const GTypeInfo graph_tree_model_info =
		{
			sizeof( GraphTreeModelClass ),
			0, /* base_init */
			0, /* base_finalize */
			(GClassInitFunc) graph_tree_model_class_init,
			0, /* class_finalize */
			0, /* class_data */
			sizeof( GraphTreeModel ),
			0,        /* n_preallocs */
			(GInstanceInitFunc) graph_tree_model_init
		};

		static const GInterfaceInfo tree_model_info =
		{
			(GInterfaceInitFunc) graph_tree_model_tree_model_init,
			0,
			0
		};

		static const GInterfaceInfo drag_source_info =
		{
			(GInterfaceInitFunc) graph_tree_model_drag_source_init,
			0,
			0
		};

		static const GInterfaceInfo drag_dest_info =
		{
			(GInterfaceInitFunc) graph_tree_model_drag_dest_init,
			0,
			0
		};

		graph_tree_model_type = g_type_register_static( G_TYPE_OBJECT, "GraphTreeModel",
														&graph_tree_model_info, (GTypeFlags)0 );

		g_type_add_interface_static( graph_tree_model_type,
									 GTK_TYPE_TREE_MODEL,
									 &tree_model_info );
		g_type_add_interface_static( graph_tree_model_type,
									 GTK_TYPE_TREE_DRAG_SOURCE,
									 &drag_source_info );
		g_type_add_interface_static( graph_tree_model_type,
									 GTK_TYPE_TREE_DRAG_DEST,
									 &drag_dest_info );
	}

	return graph_tree_model_type;
}

GraphTreeModel* graph_tree_model_new(){
	GraphTreeModel* graph_tree_model = GRAPH_TREE_MODEL( g_object_new( graph_tree_model_get_type(), 0 ) );

	graph_tree_model->graph = new graph_type;

	return graph_tree_model;
}

void graph_tree_model_delete( GraphTreeModel* model ){
	delete model->graph;
	g_object_unref( G_OBJECT( model ) );
}


class TempNameable : public Nameable
{
const char* m_name;
public:
TempNameable( const char* name ) : m_name( name ){
}
const char* name() const {
	return m_name;
}
void attach( const NameCallback& callback ){
}
void detach( const NameCallback& callback ){
}
};

void node_attach_name_changed_callback( scene::Node& node, const NameCallback& callback ){
	// Reference cannot be bound to dereferenced null pointer in well-defined
	// C++ code, and Clang will assume that comparison below always evaluates
	// to true, resulting in a segmentation fault.  Use a dirty hack to force
	// Clang to check those "bad" references for null nonetheless.
	volatile intptr_t n = (intptr_t)&node;

	if ( n != 0 ) {
		Nameable* nameable = Node_getNameable( node );
		if ( nameable != 0 ) {
			nameable->attach( callback );
		}
	}
}
void node_detach_name_changed_callback( scene::Node& node, const NameCallback& callback ){
	volatile intptr_t n = (intptr_t)&node;  // see the comment on line 650

	if ( n != 0 ) {
		Nameable* nameable = Node_getNameable( node );
		if ( nameable != 0 ) {
			nameable->detach( callback );
		}
	}
}

GraphTreeModel* scene_graph_get_tree_model(); // temp hack

void graph_tree_model_row_inserted( GraphTreeModel* model, graph_type::iterator i ){
	GtkTreeIter iter;
	graph_iterator_write_tree_iter( i, &iter );

	auto tree_path = graph_tree_model_get_path( model, &iter );

	gint depth = gtk_tree_path_get_depth( tree_path );
	gint* indices = gtk_tree_path_get_indices( tree_path );

	gtk_tree_model_row_inserted( model, tree_path, &iter );

	gtk_tree_path_free( tree_path );
}

void graph_tree_model_row_deleted( GraphTreeModel* model, graph_type::iterator i ){
	GtkTreeIter iter;
	graph_iterator_write_tree_iter( i, &iter );

	auto tree_path = graph_tree_model_get_path( model, &iter );

	gtk_tree_model_row_deleted( model, tree_path );

	gtk_tree_path_free( tree_path );
}

#include "generic/referencecounted.h"

void graph_tree_model_set_name( const scene::Instance& instance, const char* name ){
	GraphTreeModel* model = scene_graph_get_tree_model();

	if ( string_empty( name ) ) { // hack!
		graph_type::iterator i = model->graph->find( PathConstReference( instance.path() ) );
		ASSERT_MESSAGE( i != model->graph->end(), "ERROR" );

		graph_tree_model_row_deleted( model, i );

		model->graph->erase( i );
	}
	else
	{
		graph_type::iterator i = model->graph->insert( graph_type::value_type( PathConstReference( instance.path() ), &const_cast<scene::Instance&>( instance ) ) ).first;

		graph_tree_model_row_inserted( model, i );
	}
}

void graph_tree_model_insert( GraphTreeModel* model, const scene::Instance& instance ){
	graph_type::iterator i = model->graph->insert( graph_type::value_type( PathConstReference( instance.path() ), &const_cast<scene::Instance&>( instance ) ) ).first;

	graph_tree_model_row_inserted( model, i );

	node_attach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(const char*), graph_tree_model_set_name>( instance ) );
}

void graph_tree_model_erase( GraphTreeModel* model, const scene::Instance& instance ){
	node_detach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(const char*), graph_tree_model_set_name>( instance ) );

	graph_type::iterator i = model->graph->find( PathConstReference( instance.path() ) );
	ASSERT_MESSAGE( i != model->graph->end(), "ERROR" );

	graph_tree_model_row_deleted( model, i );

	model->graph->erase( i );
}

#elif 1

class GraphTreeNode;
void graph_tree_model_row_changed( GraphTreeNode& node );

class GraphTreeNode
{
typedef std::map<std::pair<CopiedString, scene::Node*>, GraphTreeNode*> ChildNodes;
ChildNodes m_childnodes;
public:
Reference<scene::Instance> m_instance;
GraphTreeNode* m_parent;

typedef ChildNodes::iterator iterator;
typedef ChildNodes::key_type key_type;
typedef ChildNodes::value_type value_type;
typedef ChildNodes::size_type size_type;

GraphTreeNode( scene::Instance& instance ) : m_instance( instance ), m_parent( 0 ){
	m_instance.get().setChildSelectedChangedCallback( RowChangedCaller( *this ) );
}
~GraphTreeNode(){
	m_instance.get().setChildSelectedChangedCallback( Callback<void()>() );
	ASSERT_MESSAGE( empty(), "GraphTreeNode::~GraphTreeNode: memory leak" );
}

iterator begin(){
	return m_childnodes.begin();
}
iterator end(){
	return m_childnodes.end();
}

size_type size() const {
	return m_childnodes.size();
}
bool empty() const {
	return m_childnodes.empty();
}

iterator insert( const value_type& value ){
	iterator i = m_childnodes.insert( value ).first;
	( *i ).second->m_parent = this;
	return i;
}
void erase( iterator i ){
	m_childnodes.erase( i );
}
iterator find( const key_type& key ){
	return m_childnodes.find( key );
}

void swap( GraphTreeNode& other ){
	std::swap( m_parent, other.m_parent );
	std::swap( m_childnodes, other.m_childnodes );
	std::swap( m_instance, other.m_instance );
}

void rowChanged(){
	graph_tree_model_row_changed( *this );
}
typedef MemberCaller<GraphTreeNode, void(), &GraphTreeNode::rowChanged> RowChangedCaller;
};

struct GraphTreeModel
{
	GObject parent;

	GraphTreeNode* m_graph;
};

struct GraphTreeModelClass
{
	GObjectClass parent_class;
};

static GtkTreeModelFlags graph_tree_model_get_flags( ui::TreeModel tree_model ){
	return GTK_TREE_MODEL_ITERS_PERSIST;
}

static gint graph_tree_model_get_n_columns( ui::TreeModel tree_model ){
	ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
	//GraphTreeModel* graph_tree_model = (GraphTreeModel*) tree_model;

	return 2;
}

static const gint c_stamp = 0xabcdef;

inline GraphTreeNode::iterator graph_iterator_read_tree_iter( GtkTreeIter* iter ){
	ASSERT_MESSAGE( iter != 0,  "tree model error" );
	ASSERT_MESSAGE( iter->user_data != 0,  "tree model error" );
	ASSERT_MESSAGE( iter->stamp == c_stamp,  "tree model error" );
	return *reinterpret_cast<GraphTreeNode::iterator*>( &iter->user_data );
}

inline void graph_iterator_write_tree_iter( GraphTreeNode::iterator i, GtkTreeIter* iter ){
	ASSERT_MESSAGE( iter != 0,  "tree model error" );
	iter->stamp = c_stamp;
	*reinterpret_cast<GraphTreeNode::iterator*>( &iter->user_data ) = i;
	ASSERT_MESSAGE( iter->user_data != 0,  "tree model error" );
}

static GType graph_tree_model_get_column_type( ui::TreeModel tree_model, gint index ){
	ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
	//GraphTreeModel *graph_tree_model = (GraphTreeModel *) tree_model;

	return G_TYPE_POINTER;
}

static gboolean graph_tree_model_get_iter( GraphTreeModel* tree_model, GtkTreeIter* iter, ui::TreePath path ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	gint* indices = gtk_tree_path_get_indices( path );
	gint depth = gtk_tree_path_get_depth( path );

	g_return_val_if_fail( depth > 0, FALSE );

	GraphTreeNode *graph = tree_model->m_graph;

	if ( graph->empty() ) {
		return FALSE;
	}

	GtkTreeIter tmp;
	GtkTreeIter* parent = 0;

	for ( gint i = 0; i < depth; i++ )
	{
		if ( !gtk_tree_model_iter_nth_child( GTK_TREE_MODEL(tree_model), iter, parent, indices[i] ) ) {
			return FALSE;
		}
		tmp = *iter;
		parent = &tmp;
	}

	return TRUE;
}

static ui::TreePath graph_tree_model_get_path( GraphTreeModel *tree_model, GtkTreeIter* iter ){
	ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
	GraphTreeNode* graph = tree_model->m_graph;

    auto path = ui::TreePath(ui::New);

	for ( GraphTreeNode* node = ( *graph_iterator_read_tree_iter( iter ) ).second; node != graph; node = node->m_parent )
	{
		std::size_t index = 0;
		for ( GraphTreeNode::iterator i = node->m_parent->begin(); i != node->m_parent->end(); ++i, ++index )
		{
			if ( ( *i ).second == node ) {
				gtk_tree_path_prepend_index( path, gint( index ) );
				break;
			}
		}
		ASSERT_MESSAGE( index != node->m_parent->size(), "error resolving tree path" );
	}

	return path;
}


static void graph_tree_model_get_value( ui::TreeModel tree_model, GtkTreeIter  *iter, gint column, GValue *value ){
	ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
	ASSERT_MESSAGE( column == 0 || column == 1, "tree model error" );

	GraphTreeNode::iterator i = graph_iterator_read_tree_iter( iter );

	g_value_init( value, G_TYPE_POINTER );

	if ( column == 0 ) {
		g_value_set_pointer( value, reinterpret_cast<gpointer>( ( *i ).first.second ) );
	}
	else
	{
		g_value_set_pointer( value, reinterpret_cast<gpointer>( &( *i ).second->m_instance.get() ) );
	}
}

static gboolean graph_tree_model_iter_next( ui::TreeModel  tree_model, GtkTreeIter   *iter ){
	ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
	GraphTreeNode::iterator i = graph_iterator_read_tree_iter( iter );
	GraphTreeNode& parent = *( *i ).second->m_parent;

	ASSERT_MESSAGE( i != parent.end(), "RUNTIME ERROR" );

	if ( ++i == parent.end() ) {
		return FALSE;
	}

	graph_iterator_write_tree_iter( i, iter );

	return TRUE;
}

static gboolean graph_tree_model_iter_children( GraphTreeModel *tree_model, GtkTreeIter  *iter, GtkTreeIter  *parent ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	GraphTreeNode& node = ( parent == 0 ) ? *tree_model->m_graph : *( *graph_iterator_read_tree_iter( parent ) ).second;
	if ( !node.empty() ) {
		graph_iterator_write_tree_iter( node.begin(), iter );
		return TRUE;
	}

	return FALSE;
}

static gboolean graph_tree_model_iter_has_child( ui::TreeModel tree_model, GtkTreeIter  *iter ){
	ASSERT_MESSAGE( tree_model, "RUNTIME ERROR" );
	GraphTreeNode& node = *( *graph_iterator_read_tree_iter( iter ) ).second;
	return !node.empty();
}

static gint graph_tree_model_iter_n_children( GraphTreeModel *tree_model, GtkTreeIter *parent ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	GraphTreeNode& node = ( parent == 0 ) ? *tree_model->m_graph : *( *graph_iterator_read_tree_iter( parent ) ).second;
	return static_cast<gint>( node.size() );
}

static gboolean graph_tree_model_iter_nth_child( GraphTreeModel *tree_model, GtkTreeIter  *iter, GtkTreeIter  *parent, gint n ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	GraphTreeNode& node = ( parent == 0 ) ? *tree_model->m_graph : *( *graph_iterator_read_tree_iter( parent ) ).second;
	if ( static_cast<std::size_t>( n ) < node.size() ) {
		GraphTreeNode::iterator i = node.begin();
		std::advance( i, n );
		graph_iterator_write_tree_iter( i, iter );
		return TRUE;
	}

	return FALSE;
}

static gboolean graph_tree_model_iter_parent( GraphTreeModel *tree_model, GtkTreeIter  *iter, GtkTreeIter  *child ){
	ASSERT_MESSAGE( tree_model != 0, "RUNTIME ERROR" );
	GraphTreeNode& node = *( *graph_iterator_read_tree_iter( child ) ).second;
	if ( node.m_parent != tree_model->m_graph ) {
		GraphTreeNode& parentParent = *node.m_parent->m_parent;
		for ( GraphTreeNode::iterator i = parentParent.begin(); i != parentParent.end(); ++i )
		{
			if ( ( *i ).second == node.m_parent ) {
				graph_iterator_write_tree_iter( i, iter );
				return TRUE;
			}
		}
	}
	return FALSE;
}

static GObjectClass *g_parent_class = nullptr;

namespace
{
scene::Node* g_null_node = 0;
}

class NullInstance : public scene::Instance
{
public:
NullInstance() : scene::Instance( scene::Path( makeReference( *g_null_node ) ), 0, 0, Static<InstanceTypeCastTable>::instance() ){
}
};

namespace
{
NullInstance g_null_instance;
}

static void graph_tree_model_init( GraphTreeModel *graph_tree_model ){
	graph_tree_model->m_graph = new GraphTreeNode( g_null_instance );
}

static void graph_tree_model_finalize( GObject* object ){
	auto graph_tree_model = reinterpret_cast<GraphTreeModel*>(object);

	delete graph_tree_model->m_graph;

	/* must chain up */
	( *g_parent_class->finalize )( object );
}

static void graph_tree_model_class_init( GraphTreeModelClass *class_ ){
	GObjectClass *object_class;

	g_parent_class = (GObjectClass*)g_type_class_peek_parent( class_ );
	object_class = (GObjectClass *) class_;

	object_class->finalize = graph_tree_model_finalize;
}

static void graph_tree_model_tree_model_init( GtkTreeModelIface *iface ){
	iface->get_flags = reinterpret_cast<GtkTreeModelFlags (*)(GtkTreeModel *)>(graph_tree_model_get_flags);
	iface->get_n_columns = reinterpret_cast<gint (*)(GtkTreeModel *)>(graph_tree_model_get_n_columns);
	iface->get_column_type = reinterpret_cast<GType (*)(GtkTreeModel *, gint)>(graph_tree_model_get_column_type);
	iface->get_iter = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *, GtkTreePath *)>(graph_tree_model_get_iter);
	iface->get_path = reinterpret_cast<GtkTreePath *(*)(GtkTreeModel *, GtkTreeIter *)>(graph_tree_model_get_path);
	iface->get_value = reinterpret_cast<void (*)(GtkTreeModel *, GtkTreeIter *, gint, GValue *)>(graph_tree_model_get_value);
	iface->iter_next = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *)>(graph_tree_model_iter_next);
	iface->iter_children = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *)>(graph_tree_model_iter_children);
	iface->iter_has_child = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *)>(graph_tree_model_iter_has_child);
	iface->iter_n_children = reinterpret_cast<gint (*)(GtkTreeModel *, GtkTreeIter *)>(graph_tree_model_iter_n_children);
	iface->iter_nth_child = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *, gint)>(graph_tree_model_iter_nth_child);
	iface->iter_parent = reinterpret_cast<gboolean (*)(GtkTreeModel *, GtkTreeIter *, GtkTreeIter *)>(graph_tree_model_iter_parent);
}

GType graph_tree_model_get_type( void ){
	static GType graph_tree_model_type = 0;

	if ( !graph_tree_model_type ) {
		static const GTypeInfo graph_tree_model_info =
		{
			sizeof( GraphTreeModelClass ),
			0, /* base_init */
			0, /* base_finalize */
			(GClassInitFunc) graph_tree_model_class_init,
			0, /* class_finalize */
			0, /* class_data */
			sizeof( GraphTreeModel ),
			0,        /* n_preallocs */
			(GInstanceInitFunc) graph_tree_model_init,
			0
		};

		static const GInterfaceInfo tree_model_info =
		{
			(GInterfaceInitFunc) graph_tree_model_tree_model_init,
			0,
			0
		};

		graph_tree_model_type = g_type_register_static( G_TYPE_OBJECT, "GraphTreeModel",
														&graph_tree_model_info, (GTypeFlags)0 );

		g_type_add_interface_static( graph_tree_model_type,
									 GTK_TYPE_TREE_MODEL,
									 &tree_model_info );
	}

	return graph_tree_model_type;
}

GraphTreeModel* graph_tree_model_new(){
	auto graph_tree_model = reinterpret_cast<GraphTreeModel*>(g_object_new( graph_tree_model_get_type(), 0 ));

	return graph_tree_model;
}

void graph_tree_model_delete( GraphTreeModel* model ){
	g_object_unref( G_OBJECT( model ) );
}

void graph_tree_model_row_changed( GraphTreeModel* model, GraphTreeNode::iterator i ){
	GtkTreeIter iter;
	graph_iterator_write_tree_iter( i, &iter );

    auto tree_path = graph_tree_model_get_path(model, &iter );

	gtk_tree_model_row_changed( GTK_TREE_MODEL( model ), tree_path, &iter );

	gtk_tree_path_free( tree_path );
}

void graph_tree_model_row_inserted( GraphTreeModel* model, GraphTreeNode::iterator i ){
	GtkTreeIter iter;
	graph_iterator_write_tree_iter( i, &iter );

    auto tree_path = graph_tree_model_get_path(model, &iter );

	gtk_tree_model_row_inserted( GTK_TREE_MODEL( model ), tree_path, &iter );

	gtk_tree_path_free( tree_path );
}

void graph_tree_model_row_deleted( GraphTreeModel* model, GraphTreeNode::iterator i ){
	GtkTreeIter iter;
	graph_iterator_write_tree_iter( i, &iter );

    auto tree_path = graph_tree_model_get_path(model, &iter );

	gtk_tree_model_row_deleted( GTK_TREE_MODEL( model ), tree_path );

	gtk_tree_path_free( tree_path );
}

void graph_tree_model_row_inserted( GraphTreeModel& model, GraphTreeNode::iterator i ){
	graph_tree_model_row_inserted( &model, i );
}

void graph_tree_model_row_deleted( GraphTreeModel& model, GraphTreeNode::iterator i ){
	graph_tree_model_row_deleted( &model, i );
}

const char* node_get_name( scene::Node& node );

const char* node_get_name_safe( scene::Node& node ){
	volatile intptr_t n = (intptr_t)&node;  // see the comment on line 650
	if ( n == 0 ) {
		return "";
	}
	return node_get_name( node );
}

GraphTreeNode* graph_tree_model_find_parent( GraphTreeModel* model, const scene::Path& path ){
	GraphTreeNode* parent = model->m_graph;
	for ( scene::Path::const_iterator i = path.begin(); i != path.end() - 1; ++i )
	{
		GraphTreeNode::iterator child = parent->find( GraphTreeNode::key_type( node_get_name_safe( ( *i ).get() ), ( *i ).get_pointer() ) );
		ASSERT_MESSAGE( child != parent->end(), "ERROR" );
		parent = ( *child ).second;
	}
	return parent;
}

void node_attach_name_changed_callback( scene::Node& node, const NameCallback& callback ){
	volatile intptr_t n = (intptr_t)&node;  // see the comment on line 650
	if ( n != 0 ) {
		Nameable* nameable = Node_getNameable( node );
		if ( nameable != 0 ) {
			nameable->attach( callback );
		}
	}
}
void node_detach_name_changed_callback( scene::Node& node, const NameCallback& callback ){
	volatile intptr_t n = (intptr_t)&node;  // see the comment on line 650
	if ( n != 0 ) {
		Nameable* nameable = Node_getNameable( node );
		if ( nameable != 0 ) {
			nameable->detach( callback );
		}
	}
}

GraphTreeModel* scene_graph_get_tree_model(); // temp hack

void graph_tree_node_foreach_pre( GraphTreeNode::iterator root, const Callback<void(GraphTreeNode::iterator)>& callback ){
	callback( root );
	for ( GraphTreeNode::iterator i = ( *root ).second->begin(); i != ( *root ).second->end(); ++i )
	{
		graph_tree_node_foreach_pre( i, callback );
	}
}

void graph_tree_node_foreach_post( GraphTreeNode::iterator root, const Callback<void(GraphTreeNode::iterator)>& callback ){
	for ( GraphTreeNode::iterator i = ( *root ).second->begin(); i != ( *root ).second->end(); ++i )
	{
		graph_tree_node_foreach_post( i, callback );
	}
	callback( root );
}

void graph_tree_model_row_changed( GraphTreeNode& node ){
	GraphTreeModel* model = scene_graph_get_tree_model();
	const scene::Instance& instance = node.m_instance.get();

	GraphTreeNode::iterator i = node.m_parent->find( GraphTreeNode::key_type( node_get_name_safe( instance.path().top().get() ), instance.path().top().get_pointer() ) );

	graph_tree_model_row_changed( model, i );
}

void graph_tree_model_set_name( const scene::Instance& instance, const char* name ){
	GraphTreeModel* model = scene_graph_get_tree_model();
	GraphTreeNode* parent = graph_tree_model_find_parent( model, instance.path() );

	GraphTreeNode::iterator oldNode = parent->find( GraphTreeNode::key_type( node_get_name_safe( instance.path().top().get() ), instance.path().top().get_pointer() ) );
	graph_tree_node_foreach_post( oldNode, ReferenceCaller<GraphTreeModel, void(GraphTreeNode::iterator), graph_tree_model_row_deleted>( *model ) );
	GraphTreeNode* node( ( *oldNode ).second );
	parent->erase( oldNode );

	GraphTreeNode::iterator newNode = parent->insert( GraphTreeNode::value_type( GraphTreeNode::key_type( name, &instance.path().top().get() ), node ) );
	graph_tree_node_foreach_pre( newNode, ReferenceCaller<GraphTreeModel, void(GraphTreeNode::iterator), graph_tree_model_row_inserted>( *model ) );
}

void graph_tree_model_insert( GraphTreeModel* model, const scene::Instance& instance ){
	GraphTreeNode* parent = graph_tree_model_find_parent( model, instance.path() );

	GraphTreeNode::iterator i = parent->insert( GraphTreeNode::value_type( GraphTreeNode::key_type( node_get_name_safe( instance.path().top().get() ), instance.path().top().get_pointer() ), new GraphTreeNode( const_cast<scene::Instance&>( instance ) ) ) );

	graph_tree_model_row_inserted( model, i );

	node_attach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(const char*), graph_tree_model_set_name>( instance ) );
}

void graph_tree_model_erase( GraphTreeModel* model, const scene::Instance& instance ){
	node_detach_name_changed_callback( instance.path().top(), ConstReferenceCaller<scene::Instance, void(const char*), graph_tree_model_set_name>( instance ) );

	GraphTreeNode* parent = graph_tree_model_find_parent( model, instance.path() );

	GraphTreeNode::iterator i = parent->find( GraphTreeNode::key_type( node_get_name_safe( instance.path().top().get() ), instance.path().top().get_pointer() ) );

	graph_tree_model_row_deleted( model, i );

	GraphTreeNode* node( ( *i ).second );
	parent->erase( i );
	delete node;
}



#endif




#if 0
class TestGraphTreeModel
{
public:
TestGraphTreeModel(){
	gtk_init( 0, 0 );

	graph_type graph;

	scene::Node* root = *(scene::Node*)0xa0000000;
	scene::Node* node1 = (scene::Node*)0xa0000001;
	scene::Node* node2 = (scene::Node*)0xa0000002;
	scene::Node* node3 = (scene::Node*)0xa0000003;
	scene::Node* node4 = (scene::Node*)0xa0000004;
	scene::Instance* instance = (scene::Instance*)0xaaaaaaaa;

	scene::Path rootpath( root );

	graph.insert( graph_type::value_type( rootpath, instance ) );

	rootpath.push( node1 );
	graph.insert( graph_type::value_type( rootpath, instance ) );
	rootpath.pop();

	rootpath.push( node2 );
	graph.insert( graph_type::value_type( rootpath, instance ) );
	rootpath.push( node3 );
	graph.insert( graph_type::value_type( rootpath, instance ) );
	rootpath.pop();
	rootpath.push( node4 );
	graph.insert( graph_type::value_type( rootpath, instance ) );
	rootpath.pop();
	rootpath.pop();

	auto model = graph_tree_model_new( &graph );

	{
		gint n_columns = gtk_tree_model_get_n_columns( model );
		ASSERT_MESSAGE( n_columns == 2, "test failed!" );
	}

	{
		GType type = gtk_tree_model_get_column_type( model, 0 );
		ASSERT_MESSAGE( type == G_TYPE_POINTER, "test failed!" );
	}

	{
		GType type = gtk_tree_model_get_column_type( model, 1 );
		ASSERT_MESSAGE( type == G_TYPE_POINTER, "test failed!" );
	}


	{
		GtkTreeIter iter;
		gtk_tree_model_get_iter_first( model, &iter );

		graph_type::iterator i = graph_iterator_read_tree_iter( &iter );
		ASSERT_MESSAGE( ( *i ).first.get().size() == 2 && ( *i ).first.get().top() == node1, "test failed!" );
	}

	{
		GtkTreeIter iter;
		gtk_tree_model_get_iter_first( model, &iter );

		ASSERT_MESSAGE( gtk_tree_model_iter_has_child( model, &iter ) == FALSE, "test failed!" );

		ASSERT_MESSAGE( gtk_tree_model_iter_n_children( model, &iter ) == 0, "test failed!" );

		gtk_tree_model_iter_next( model, &iter );

		ASSERT_MESSAGE( gtk_tree_model_iter_has_child( model, &iter ) != FALSE, "test failed!" );

		ASSERT_MESSAGE( gtk_tree_model_iter_n_children( model, &iter ) == 2, "test failed!" );

		{
			GtkTreeIter child;
			gtk_tree_model_iter_nth_child( model, &child, &iter, 0 );

			scene::Node* test;
			gtk_tree_model_get_value( model, &child, 0, (GValue*)&test );
			ASSERT_MESSAGE( test == node3, "test failed!" );

			{
				GtkTreeIter parent;
				gtk_tree_model_iter_parent( model, &parent, &child );

				scene::Node* test;
				gtk_tree_model_get_value( model, &parent, 0, (GValue*)&test );
				ASSERT_MESSAGE( test == node2, "test failed!" );
			}
		}

		{
			GtkTreeIter child;
			gtk_tree_model_iter_nth_child( model, &child, &iter, 1 );

			scene::Node* test;
			gtk_tree_model_get_value( model, &child, 0, (GValue*)&test );
			ASSERT_MESSAGE( test == node4, "test failed!" );
		}
	}

	{
		GtkTreeIter iter;
		std::size_t count = 0;
		for ( gboolean good = gtk_tree_model_get_iter_first( model, &iter ); good; good = gtk_tree_model_iter_next( model, &iter ) )
		{
			scene::Node* test;
			gtk_tree_model_get_value( model, &iter, 0, (GValue*)&test );

			ASSERT_MESSAGE( ( count == 0 && test == node1 ) || ( count == 1 && test == node2 ), "test failed!" );
			++count;
		}

		ASSERT_MESSAGE( count == 2, "test failed!" );

	}

	{
		GtkTreeIter iter;
		gtk_tree_model_get_iter_first( model, &iter );

		scene::Node* test;
		gtk_tree_model_get_value( model, &iter, 0, (GValue*)&test );
		ASSERT_MESSAGE( test == node1, "test failed!" );
	}

	{
		GtkTreeIter iter;
		auto path = ui::TreePath( "0" );
		gtk_tree_model_get_iter( model, &iter, path );
		gtk_tree_path_free( path );

		graph_type::iterator i = graph_iterator_read_tree_iter( &iter );
		ASSERT_MESSAGE( ( *i ).first.get().size() == 2 && ( *i ).first.get().top() == node1, "test failed!" );
	}

	{
		GtkTreeIter iter;
		auto path = ui::TreePath( "1" );
		gtk_tree_model_get_iter( model, &iter, path );
		gtk_tree_path_free( path );

		graph_type::iterator i = graph_iterator_read_tree_iter( &iter );
		ASSERT_MESSAGE( ( *i ).first.get().size() == 2 && ( *i ).first.get().top() == node2, "test failed!" );
	}

	{
		GtkTreeIter iter;
		graph_type::iterator i = graph.begin();
		++i;
		graph_iterator_write_tree_iter( i, &iter );

		auto path = gtk_tree_model_get_path( model, &iter );

		gint depth = gtk_tree_path_get_depth( path );
		gint* indices = gtk_tree_path_get_indices( path );

		ASSERT_MESSAGE( depth == 1 && indices[0] == 0, "test failed!" );

		gtk_tree_path_free( path );
	}

	{
		GtkTreeIter iter;
		graph_type::iterator i = graph.begin();
		++i;
		++i;
		graph_iterator_write_tree_iter( i, &iter );

		auto path = gtk_tree_model_get_path( model, &iter );

		gint depth = gtk_tree_path_get_depth( path );
		gint* indices = gtk_tree_path_get_indices( path );

		ASSERT_MESSAGE( depth == 1 && indices[0] == 1, "test failed!" );

		gtk_tree_path_free( path );
	}
}
};


TestGraphTreeModel g_TestGraphTreeModel;

#endif
