/*****
 NAME
	clist.m - source code for CList class
 VERSION
	$Id$
 CHANGELOG
	$Log$
 */

#include <coconut/clist.h>
#include <coconut/csystem.h>
#include <coconut/cerror.h>
#include <coconut/ptext.h>

static GList * makeNewNode(const void * data){
	GList * newnode ;
	
	newnode = g_list_alloc() ;
	[CSystem checkPtr: newnode] ;
	newnode->data = (gpointer) data ;
	return newnode ;
}

@implementation CList

- init
{
	return [self initList: NULL] ; 
}

- initList: (dealloc_func_t) defunc 
{
	dealloc_func = defunc ; 
	root_node = current_node = NULL ;
	return [super init] ;
}

- (void) dealloc
{
	[self clear] ; 
	return [super dealloc] ;
}

- (u_int) count
{
	return g_list_length(root_node) ;
}

- clear
{
	GList *	node ;
	if(root_node){
		if(dealloc_func)
			for(node = root_node ; node ; node = node->next)
				(*dealloc_func)(node->data) ;
		g_list_free(root_node) ;
	}
	root_node = current_node = NULL ;
	return nil ;
}

- (const void *) foreach: (foreach_func_t) func with: (void *) p1 
    with: (void *) p2
{
	GList *		node ;
	const void *	result ;

	for(node = root_node ; node ; node = node->next){
		result = (*func)(node->data, p1, p2) ;
		if(result)
			return result ;
	}
	return nil ;
}

- append: (const void *) data
{
	GList * newnode ;
	/* this function does not returns last node */
	newnode = g_list_append(current_node, (gpointer) data) ;
	if(current_node == NULL){
		root_node = current_node = newnode ;
	}
	return nil ;
}

- prepend: (const void *) data
{
	/* this function does not returns last node */
	root_node = g_list_prepend(root_node, (gpointer) data) ;
	if(current_node == NULL){
		current_node = root_node ;
	}
	return nil ;
}

- add: (const void *) data
{
	GList * newnode ;
	GList * nextnode ;

	newnode = makeNewNode(data) ;
	if(current_node){
		if((nextnode = current_node->next) != NULL)
			nextnode->prev = newnode ;
		current_node->next = newnode ;
		newnode->next = nextnode ;
		newnode->prev = current_node ;
		current_node = newnode ;
	} else
		root_node = current_node = newnode ;
	return nil ;
}

- insert: (const void *) data
{
	GList * newnode ;
	GList * prevnode ;

	newnode = makeNewNode(data) ;
	if(current_node){
		if((prevnode = current_node->prev) != NULL)
			prevnode->next = newnode ;
		current_node->prev = newnode ;
		newnode->next = current_node ;
		newnode->prev = prevnode ;
		if(prevnode == NULL)
			root_node = newnode ;
	} else
		root_node = current_node = newnode ;
	return nil ;
}

- (const void *) currentItem
{
	return current_node ? current_node->data : NULL ;
}

- (const void *) item: (u_int) no
{
	GList * node ;

	if(root_node){
		if((node = g_list_nth(root_node, no)) != NULL)
			return node->data ;
	}
	return NULL ;
}

- (const void *) moveNext
{
	GList * next ;
	void * result = NULL ;
	if(current_node){
		if((next = current_node->next) != NULL){
			current_node = next ;
			result = current_node->data ;
		}
	}
	return result ;
}

- (const void *) movePrev
{
	GList * prev ;
	void * result = NULL ;
	if(current_node){
		if((prev = current_node->prev) != NULL){
			current_node = prev ;
			result = current_node->data ;
		}
	}
	return result ;
}

- (const void *) moveToHead
{
	current_node = root_node ;
	return current_node ? current_node->data : NULL ;
}

- (const void *) moveToTail
{
	void *	result = NULL ;
	if(current_node){
		current_node = g_list_last(current_node) ;
		result = current_node->data ;
	}
	return result ;
}

- (id <PError>) remove
{
	GList * newnode ;
	if(current_node){
		newnode = current_node->prev ;
		if(newnode == NULL)
			newnode = current_node->next ;
		root_node = g_list_remove_link(root_node, current_node) ;
		if(current_node->data && dealloc_func)
			(*dealloc_func)(current_node->data) ;
		g_list_free_1(current_node) ;
		current_node = newnode ;
		return nil ;
	} else
		return [CError not_exist] ;
}

- print: (id <PIndentStream>) stream
{
	GList *	node ;

	[stream putPtr: "(list\n"] ;
	  for(node = root_node ; node ; node = node->next)
		[((id) node->data) print: stream] ;
	[stream putPtr: ")\n"] ;
	return nil ;
}

@end

