/*****
 NAME
 	cnode.m - source code for CNode class
 VERSION
 	$Id$
 CHANGELOG
 	$Log$
 */

#include <coconut/cnode.h>
#include <coconut/cmessage.h>
#include <coconut/cindtstream.h>

@implementation CNode

+ (id) lastSibling: (id <PNode>) node ;
{
	id <PNode>	next ;

	while((next = [node next]) != nil){
		node = next ;
	}
	return node ;
}

+ (id) firstSibling: (id <PNode>) node ;
{
	id <PNode>	prev ;

	while((prev = [node prev]) != nil){
		node = prev ;
	}
	return node ;
}

- init
{
	parent_node = child_node = next_node = prev_node = nil ;
	return [super init] ;
}

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

- (id) parent
{
	return parent_node ;
}

- (id) child
{
	return child_node ;
}

- (id) next
{
	return next_node ;
}

- (id) prev
{
	return prev_node ;
}

/* (this_node) -> (src list) -> (next_node) */
- addSibling: (id <PNode>) src
{
	id <PNode>	node ;
	id <PNode>	last ;

	/* connect node with parent */
	for(node = last = src ; node ; node = [node next]){
		[node setParent: parent_node] ;
		last = node ; 
	}
	/* connect last of src and next */
	[next_node setPrev: last] ;
	[last setNext: next_node] ;
	/* connect this and src */
	next_node = src ;
	[src setPrev: self] ;
	[src retain] ;
	return nil ;
}

/* (prev_node) -> (src list) -> (this_node) */
- insertSibling: (id <PNode>) src
{
	id <PNode>	node ;
	id <PNode>	last ;

	/* connect node with parent */
	for(node = last = src ; node ; node = [node next]){
		[node setParent: parent_node] ;
		last = node ;
	}
	/* connect src and prev */
	if(prev_node){
		[prev_node setNext: src] ;
	} else {
		[parent_node setChild: src] ;
	}
	[src setPrev: prev_node] ;
	/* connect last of src and this */
	prev_node = last ;
	[last setNext: self] ;
	[src retain] ;
	return nil ;
}

- appendSibling: (id <PNode>) node
{
	id <PNode>	last ;
	last = [CNode lastSibling: self] ;
	return [last addSibling: node] ;
}

- prependSibling: (id <PNode>) node
{
	id <PNode>	first ;
	first = [CNode firstSibling: self] ;
	return [first insertSibling: node] ;
}

- appendChild: (id <PNode>) node
{
	if(child_node){
		return [child_node appendSibling: node] ;
	} else {
		child_node = node ;
		for( ; node ; node = [node next])
			[node setParent: self] ;
		[child_node retain] ;
		return nil ;
	}
}

- prependChild: (id <PNode>) node
{
	if(child_node){
		return [child_node prependSibling: node] ;
	} else {
		child_node = node ;
		for( ; node ; node = [node next])
			[node setParent: self] ;
		[child_node retain] ;
		return nil ;
	}
}

-foreach: (SEL) msg with: p1 with: p2
{
	id		result ;

	/* execute on myself */
	if((result = [self perform: msg with: p1 with: p2]) != nil)
		return result ;
	/* execute children */
	if((result = [child_node foreach: msg with: p1 with: p2]) != nil)
		return result ;
	/* execute follower */
	return [next_node foreach: msg with: p1 with: p2] ;
}

-foreach: (id) obj message: (SEL) msg with: p1 
{
	id		result ;

	/* execute on myself */
	if((result = [obj perform: msg with: self with: p1]) != nil)
		return result ;
	/* execute children */
	if((result = [child_node foreach: obj message: msg with: p1]) != nil)
		return result ;
	/* execute follower */
	return [next_node foreach: obj message: msg with: p1] ;
}

-foreachFromChildren: (SEL) msg with: p1 with: p2
{
	id		result ;

	/* execute children */
	if((result = [child_node foreach: msg with: p1 with: p2]) != nil)
		return result ;
	/* execute on myself */
	if((result = [self perform: msg with: p1 with: p2]) != nil)
		return result ;
	/* execute follower */
	return [next_node foreach: msg with: p1 with: p2] ;
}

-foreachFromChildren: (id) obj message: (SEL) msg with: p1 
{
	id		result ;

	/* execute children */
	if((result = [child_node foreach: obj message: msg with: p1]) != nil)
		return result ;
	/* execute on myself */
	if((result = [obj perform: msg with: self with: p1]) != nil)
		return result ;
	/* execute follower */
	return [next_node foreach: obj message: msg with: p1] ;
}

- isolate
{
	id <PNode>	childlast ;

	/* connect child with prev and next */
	if(child_node){
		childlast = [CNode lastSibling: child_node] ;
		[prev_node setNext: child_node] ;
		[next_node setPrev: childlast] ;
	} else {
		if(prev_node == nil){
			/* the parent points this one */
			[parent_node setChild: next_node] ;
		} else {
			[prev_node setNext: next_node] ;
		}
		[next_node setPrev: prev_node] ;
	}
	return nil ;
}

- removeAllChildren
{
	id <PNode>	next ;

	for( ; child_node ; child_node = next){
		next = [child_node next] ;
		[child_node release] ;
	}
	child_node = nil ;
	return nil ;
}

/* this method does not print the data. this method calls "print"
   method for the children and followers */
#define	STREAM	((id <PIndentStream>) stream)
- print: (id) stream
{
	[STREAM incLevel] ;
		[child_node print: stream] ;
	[STREAM decLevel] ;
	return [next_node print: stream] ;
}

- setParent: (id <PNode>) node
{
	parent_node = node ;
	return nil ;
}

- setChild: (id <PNode>) node
{
	child_node = node ;
	return nil ;
}

- setNext: (id <PNode>) node
{
	next_node = node ;
	return nil ;
}

- setPrev: (id <PNode>) node
{
	prev_node = node ;
	return nil ;
}

@end

