indexing
	namespace: "candidate"
	cluster: "collection"
	description: "Basic element for tree collection."
	original_author: "Justin Finnerty"
	original_date: "July 2005"
	date: "$Date: 2005/09/03 03:08:27 $"
	author: "$Author: finnerty $"
	revision: "$Revision: 2.2 $"
	-- $Log: tree_node.ge,v $
	-- Revision 2.2  2005/09/03 03:08:27  finnerty
	-- Updated to conform to cursors/containers in the GOBO library and
	-- test programs compile with SE and VE.
	--
	-- Revision 2.1  2005/09/03 01:39:54  finnerty
	-- Updated to conform to cursors/containers in the GOBO library
	--
	-- Revision 2.0  2005/09/02 07:10:32  finnerty
	-- Renamed tree_node.e to tree_node.ge
	--
	-- Revision 2.0  2005/08/26 23:19:46  finnerty
	-- == alpha version ==
	--
	-- Revision 1.6  2005/08/21 11:53:14  finnerty
	-- Alpha 1 version
	--
	-- Revision 1.5  2005/08/10 02:27:13  finnerty
	-- Edited documentation
	--
	-- Revision 1.4  2005/08/06 12:31:46  finnerty
	-- Added methods for getting iterator for traversing the tree in preorder.
	--
	-- Revision 1.3  2005/08/05 02:33:57  finnerty
	-- Fiddling to get cvs logging to work
	--
	-- Revision 1.2  2005/08/05 02:30:43  finnerty
	--
	-- Updated documentation and changed access for all methods
	-- to {ANY}. Tweaked inheritance to combine
	-- has_left/has_right into has_sibling.
	--
	-- Revision 1.1  2005/08/04 09:38:35  finnerty
	--
	-- Adaptation of quadlink_node to act as a tree. This
	-- insists on 1-1 arity in the horizontal direction but 1-N
	-- arity when going `down' the vertical direction and 1-1
	-- arity going up. Added features to work with N-arity in
	-- vertical direction (has_child, count, put_parent, remove).
class TREE_NODE
	-- Basic node for a tree COLLECTION.
	
	-- Implementation: The three linkable notions are `parent', child
	-- and previous/`next_sibling'. The tree is implemented in the
	-- `parent'/child direction as a bi-linked list which terminate
	-- with `Void' references. The sibling direction is a bi-linked
	-- list organised as a ring: with `first_child' as the child link
	-- and the `last_child' as `first_child''s `previous_sibling'.
#ifdef SE
insert
#else
inherit
#endif
	QUADLINK_NODE
	-- `put_up' and `remove_vertically' are no
	-- longer meaningful. They are not exported.
		rename
			up as parent,
			down as first_child,
			left as previous_sibling,
			right as next_sibling,
			has_down as has_children,
			has_up as has_parent,
			has_right as has_sibling,
			has_left as has_sibling,
			remove_horizontally as remove
		export {ANY}
			parent,
			first_child,
			previous_sibling,
			next_sibling,
			has_children,
			has_parent;
			{NONE}
			remove_vertically,
			put_down,
			put_left,
			put_right,
			put_up;
			{TREE_NODE}
			set_down,
			set_left,
			set_right,
			set_up
		redefine
			has_sibling,
			remove
		end
creation {ANY}
	-- globally accessible creation methods
	make, make_child_of

feature {ANY}
	-- Status report
	is_empty: BOOLEAN is
        -- Is there any children?
		do
			Result := not has_children
		end

feature {ANY}
	-- Access
	first: like Current is
			-- Support for cursors
		do
			Result := Current
		end

	last: like Current is
			-- Support for cursors
		do
			from
				Result := Current
			until
				not Result.has_children
			loop
				Result := Result.last_child
			end
		end

feature {TREE_NODE}
	-- creation methods are restricted as only valid for creation.
	make is
			-- Node of a tree without a parent---tree base
		do
			previous_sibling := Current
			next_sibling := Current
		end

	make_child_of(a_parent: like Current) is
			-- Node of a tree with parent---tree growth
		require
			a_parent /= Void -- must have a parent
		do
			make
			put_parent( a_parent )
		end

feature {ANY}
	-- Queries about direct family.
	
	count: INTEGER is
			-- Number of direct child nodes.
		local
			l_cursor: like Current
		do
			if has_children then
				from
					Result := 1
					l_cursor := first_child
				until
					l_cursor = last_child
				loop
					Result := Result + 1
					l_cursor := l_cursor.next_sibling
				end
			end
		end

	has_child(a_child: like Current): BOOLEAN is
			-- Is `a_child' one of my children?
		require
			a_child /= Void -- the first_child is not Void
			-- do not check to see if a_child thinks we are its parent.
		local
			l_node: like Current
		do
			-- If
			if not has_children then
				-- we have no first_child link then false.
				Result := False
			elseif first_child = a_child then
				-- If a_child is the first first_child then true
				Result := True
			else
				-- or we need to check the sibling list. Here we must
				-- iterate along the list from `first_child'
				from
					l_node := first_child
				until
					not ( l_node = last_child -- until `last_child' 
							and l_node.next_sibling /= a_child ) -- or found.
				loop
					l_node := l_node.next_sibling
				end
				-- If `l_node' is `last_child' then we did not find this first_child
				Result := not ( l_node = last_child )
			end
		ensure
			Check_constness: Current.is_equal(old Current)
			Check_constness: a_child.is_equal(old a_child)
		end

	has_sibling: BOOLEAN is
			-- Are there any sibling objects?
		do
			Result := (next_sibling /= Void) and then (next_sibling /= Current)
		ensure then
			Result implies next_sibling /= Current
			-- Result implies previous_sibling /= Current
		end

	last_child: like Current is
			-- What was the last child to `put_parent'.
		require
			has_children
		do
			Result := first_child.previous_sibling
		ensure
			-- X.put_parent(Y) ; X = Y.last_child
		end

feature {ANY}
	-- Attribute queries particular to a tree node.

	depth: INTEGER is
			-- Number of up steps to the root node; 0 if at root.
		require
			-- no circular references in ancestory.
		local
			l_cursor: like Current
		do
			from
				l_cursor := Current
			until
				not l_cursor.has_parent
			loop
				l_cursor := l_cursor.parent
				Result := Result + 1
			end
		ensure
			Result = 0 implies not has_parent
		end

	new_cursor: BILINEAR_CURSOR[like Current] is
			-- Get iterator for whole tree.
		do
			!TREE_CURSOR[like Current]!Result.make(Current)
		end

	new_bound_cursor: BILINEAR_CURSOR[like Current] is
			-- Get iterator for sub-tree.
		do
			!BOUNDED_TREE_CURSOR[like Current]!Result.make(Current)
		end

	root: like Current is
			-- Root node of tree
		require
			-- no circular references in ancestory.
		do
			from
				Result := Current
			until
				not Result.has_parent
			loop
				Result := Result.parent
			end
		ensure
			not Result.has_parent
			not Result.has_sibling
		end

feature {ANY}
	-- Procedures that affect child nodes.

	put_parent(a_parent: like Current) is
			-- `remove' from existing (if any) `parent' then become a
			-- child of `a_parent'.
		require
			No_void_parent: a_parent /= Void 
			No_self_ancestor: a_parent /= Current
			-- no circular references in ancestory.
		do
			-- Only do something if a_parent is not already our parent.
			if parent /= a_parent then
				if has_parent then
					-- Unlink from our original parent.
					remove
				end
				-- Set our new parent.
				set_up( a_parent )
				-- If our parent already has children 
				if a_parent.has_children then
					-- put first_child as our next sibling.
					put_right( a_parent.first_child )
				else
					-- Otherwise we make us the only sibling.
					a_parent.set_down( Current )
				end
			end
		ensure
			Parent_is_set: has_parent 
			Parent_is_set: parent = a_parent
			Parent_is_set: parent.has_child(Current)
		end
	
	remove is
			-- Cut from `parent' and `sibling's. `Child'ren are undisturbed.
		require else
			Parent_is_set: has_parent
			Parent_is_set: parent.has_child( Current )
		do
			-- If we have no siblings then we can only be the first
			-- child.
			if not has_sibling then
				-- Only child requires only resetting parent.
				parent.set_down( Void )
			else
				if parent.first_child = Current then
					-- When first_child with siblings, adjust parent.
					parent.set_down( next_sibling )
				end
				-- Cut from sibling links
				previous_sibling.set_right(next_sibling)
				next_sibling.set_left(previous_sibling)
				-- Adjust our links
				next_sibling := Current
				previous_sibling := Current
			end
	   	-- Reset parent reference
		   parent := Void
		ensure then
			Links_rebuilt: old previous_sibling /= Void implies (old previous_sibling).next_sibling = old next_sibling
			Links_rebuilt: old next_sibling /= Void implies old previous_sibling = (old next_sibling).previous_sibling
			Check_family_removed: not has_parent
		end

	unlink is
			-- Recursively `remove' all our descendents and ourself.
		local
			l_stack: DS_LINKED_STACK[like Current]
		do
			-- Unlink this object and all descendents from all other
			-- objects. At the end of this method the object and _all_
			-- its children will have parent, first_child and sibling
			-- references reset.

			-- This is distinct from remove, which unlinks the Current
			-- tree_node node from its parent and siblings but does not 
			-- affect the children.

			-- Use `l_stack' to perform recursive descent
			from
				!!l_stack.make
				l_stack.put(Current)
			until
				l_stack.is_empty
			loop
				-- Walk to bottom of a branch, adding each node to `l_stack'.
				from
				until
					not l_stack.item.has_children
				loop
					l_stack.put(l_stack.item.first_child)
				end
				-- `Item' is leaf node, `remove'.
				if l_stack.item.has_parent then
					l_stack.item.remove
				end
				-- Move up `l_stack'
				l_stack.remove
			end
		ensure
			not has_parent
			not has_sibling
			not has_children
			-- apply to all descendents...
		end
invariant
	No_self_ancestor: Current /= parent
	No_self_ancestor: Current /= first_child
	No_sibling_without_parents: has_sibling implies has_parent
	No_lost_child_link: next_sibling /= Void
	No_lost_child_link: previous_sibling /= Void
	No_lost_child_link: first_child /= Void implies last_child /= Void
end -- class TREE_NODE
