/*
 NAME
	ctree.m - source code for CTree class
 VERSION
 	$Id$
 CHANGELOG
 	$Log$
 */

#include <coconut/ctree.h>
#include <coconut/cnode.h>
#include <coconut/ptext.h>

@implementation CTree

- init
{
	root_node = current_node = nil ;
	return [super init] ;
}

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

- (u_int) count
{
	return [self countSubtree: root_node] ;
}

- (id) rootNode
{
	return root_node ;
}

- (id) currentNode
{
	return current_node ;
}

- addSibling: (id <PNode>) node
{
	if(root_node){
		return [current_node addSibling: node] ;
	} else {
		root_node = current_node = node ;
		[root_node retain] ;
		return nil ;
	}
}

- insertSibling: (id <PNode>) node
{
	id 	result ;
	if(root_node){
		result = [current_node insertSibling: node] ;
		if(result == nil){
			if(current_node == root_node)
				root_node = node ;
		}
		return result ;
	} else {
		root_node = current_node = node ;
		[root_node retain] ;
		return nil ;
	}
}

- appendSibling: (id <PNode>) node
{
	if(root_node){
		return [current_node appendSibling: node] ;
	} else {
		root_node = current_node = node ;
		[root_node retain] ;
		return nil ;
	}
}

- prependSibling: (id <PNode>) node
{
	id 	result ;
	if(root_node){
		result = [current_node prependSibling: node] ;
		if(result == nil){
			if(current_node == root_node)
				root_node = node ;
		}
		return result ;
	} else {
		root_node = current_node = node ;
		[root_node retain] ;
		return nil ;
	}
}

- appendChild: (id <PNode>) node
{
	if(root_node){
		return [current_node appendChild: node] ;
	} else {
		root_node = current_node = node ;
		[root_node retain] ;
		return nil ;
	}
}

- prependChild: (id <PNode>) node
{
	if(root_node){
		return [current_node prependChild: node] ;
	} else {
		root_node = current_node = node ;
		[root_node retain] ;
		return nil ;
	}
}

- (id <PNode>) moveToParent
{
	current_node = [current_node parent] ;
	return current_node ;
}

- (id <PNode>) moveToChild
{
	id <PNode> child ;
	if((child = [current_node child]) != nil){
		current_node = child ;
	}
	return current_node ;
}

- (id <PNode>) moveToPrev
{
	id <PNode> prev ;
	if((prev = [current_node prev]) != nil){
		current_node = prev ;
	}
	return current_node ;
}

- (id <PNode>) moveToNext
{
	id <PNode> next ;
	if((next = [current_node next]) != nil){
		current_node = next ;
	}
	return current_node ;
}

- (id <PNode>) moveToHead
{
	id <PNode> head ;
	if((head = [CNode firstSibling: current_node]) != nil){
		current_node = head ;
	}
	return current_node ;
}

- (id <PNode>) moveToTail
{
	id <PNode> tail ;
	if((tail = [CNode lastSibling: current_node]) != nil){
		current_node = tail ;
	}
	return current_node ;
}

- (id <PNode>) moveToLastChild
{
	if([self moveToChild])
		[self moveToTail] ;
	return current_node ;
}

- removeCurrentNode
{
	id <PNode>	node ;
	id <PNode>	newcurrent ;

	if(current_node == nil)
		return nil ;
	if((node = [current_node next]) != nil){
		[node setPrev: [current_node prev]] ;
		newcurrent = node ;
	} else if((node = [current_node prev]) != nil){
		[node setNext: [current_node next]] ;
		newcurrent = node ;
	} else if((node = [current_node parent]) != nil){
		[node setChild: [current_node child]] ;
		newcurrent = node ;
	} else 
		newcurrent = nil ;
	[current_node release] ;
	if(root_node == current_node)
		root_node = newcurrent ;
	current_node = newcurrent ;
	return nil ;
}

- clear
{
	current_node = root_node ;
	[self removeCurrentNode] ;
	return nil ;
}

#define	STREAM		((id <PIndentStream>) stream)
- print: (id) stream
{
	return [self printSubtree: root_node stream: stream] ;
}

- printSubtree: (id <PNode>) root stream: (id) stream
{
	id <PNode>	child ;
	if(root == nil){
		/* [stream putPtr: "nil\n"] ; */
		return nil ;
	}
	/* print itself */
	[root print: stream] ; [STREAM putChar: '\n'] ;
	/* print children */
	if((child = [root child]) != nil){
		[STREAM incLevel] ;
			[self printSubtree: child stream: stream] ;
		[STREAM decLevel] ;
	}
	[self printSubtree: [root next] stream: stream] ;
	return nil ;
}

- (u_int) countSubtree: (id <PNode>) root
{
	id <PNode>	child ;
	u_int		count ;

	count = 0 ;
	if(root == nil)
		return count ;
	for(child = [root child] ; child ; child = [child next])
		count += [self countSubtree: child] ;
	return 1 + count + [self countSubtree: [root next]] ;
}

@end

