// Browse Tree Object JavaScript Functions
// File:    browseTree.js
// Author:  Clinton Farleigh
// WEBCAT:  3.0
// Version: 1.0
// History:
//    26 Jun 2002  V1.0: Created.
//    28 May 2004  Added one more check to the traverseTree method to fix a bug I found when
//                 attempting a single frame browse...RMG
//
// Constructor
// tree()
//
// PROPERTIES
// .$data  = the contents of the represented record.
// .$depth = the depth of the current node in the tree (costs less to store than to determine each time).
// .$next  = the immediate sibling of the current node. 
// .$child = the immediate child of the current node.
//
// METHOD SUMMARY
// .getDepth = returns the depth of each node in the tree (for indentation).
// .getNext = returns the immediate sibling node of the current node.
// .getChild = returns the immediate child node of the current node.
// .setNext = sets the immediate sibling node of the current node.
// .setChild = sets the immediate child node of the current node.
// .sort = sorts all nodes from the current node down and right. (intended to be called on head node.)
// .setData = sets the contents of the node.
// .toArray = returns the data of the node in array format.
// .toString = returns the data of the node in string format.
// .setDepth = sets the depth of the node within the tree.
// .getDepth = returns the depth of the node within the tree.
// .isDisplay = returns value indicating if node is to be displayed on browse or is cached for later.
// .setDisplay = sets all siblings further in the list than node to be displayed in browse or not.
// .traverseTree = Traverses tree in order and calls top.BrowseData.buildNode( ) for node.
 
//
// GLOBAL FUNCTIONS
// buildTree = builds the entire tree based on the data parameter.
// findEqualNode = Given data and a nodelist, finds a node with the given data among siblings.
//				   Helper function for buildTree.  

function node( data ) {
	// Set attributes of object.
	//this.$next = next ;
	//this.$child = child ;
	this.$data = data 		 ;
	this.$depth = 0 		 ;
	this.$display = true 	 ;
	// Set methods that can be performed on object.
	this.getNext = getNext   ;
	this.setNext = setNext   ;
	this.getChild = getChild ;
	this.setChild = setChild ;
	this.getDepth = getDepth ;
	this.setDepth = setDepth ;
	this.toArray = toArray   ;
	this.toString = toString ;
	this.setData = setData   ;
	this.sort = sort 		 ;
	this.traverseTree = traverseTree ;
	this.isDisplay = isDisplay   ;
	this.setDisplay = setDisplay     ;
}

function getDepth( ) {
	return this.$depth ;
}

function setDepth( depth ) {
	this.$depth = depth ;
}

function getNext( ) {
	return this.$next ;
}

function getChild( ) {
	return this.$child ;
}

function isDisplay( ) {
	return this.$display ;
}

function setDisplay( isDisplay ) {
	var next = this ;
	while( next ) {
		next.$display = isDisplay ;
		if ( next.getChild( ) ) {
			// Force children not to be displayed under any circumstance.
			// If want all records currently obtained in hierarcy to be displayed, 
			// must set child display to parameter isDisplay.
			next.getChild( ).setDisplay( false ) ;
		}
		next = next.getNext( ) ;
	}
}

function setNext( next ) {
	this.$next = next ;
	if ( next ) {
		next.$depth = this.$depth ;
	}
}

function setChild( child ) {
	this.$child = child ;
	child.$depth = this.$depth + 1 ;
}

function toArray( ) {
	return this.$data ;
}

function toString( delim ) {
	if ( top.isBlank(delim) ) {
		delim = ' ' ;
	}
	return this.$data.join( delim ) ;
}

function setData( data ) {
	this.$data = data ;
}

function sort( sortFunc ) {
	var node = this ;
	// Build array for parent.
	var sortArray = new Array( ) ;
	var i = 0 ;
	while( node ) {
		var child = node.getChild( ) ;
		// Recursively call sorting for children nodes.
		if( child ) {
			var newchild = child.sort( sortFunc ) ;
			node.setChild( newchild ) ;
//			alert( "Parent: " + node.toArray()[3] + " Child: " + newchild.toArray()[3] ) ;
		}
		sortArray[i] = node ;
		node = node.getNext( ) ;
		i++ ;
	}
	// TODO: Implement O(nlogn) sorting algorithm that uses list.
	// WARNING: Efficiency of this function is terrible. 
	sortArray.sort( sortFunc ) ;
	// Rebuild links.
	for( i = 0 ; i < sortArray.length ; i++ ) {
		node = sortArray[ i ] ;
		var next = sortArray[ i + 1 ] ;
		node.setNext( next ) ;
	}
	return sortArray[ 0 ] ;
}

//-----------------------------------------------------------------------------
// Builds the tree based on data parameter.
function buildTree( data, delim, isAncestor, depth, nodelist ) {
	if( top.isBlank( delim ) ) {
		delim = ' ' ;
	}
	var head = findEqualNode( data[0].split( delim ), nodelist ) ;
	if ( !head ) {
		head = new node( data[0].split( delim ) ) ;	
	}
	head.setDepth( depth ) ;
	var prevNode = head ;
	// Build list on same level as parent node. 
	for( var i = 1 ; i < data.length ; i++ ) {
		var n = findEqualNode( data[i].split( delim ), nodelist ) ;
		if ( !n ) {
			n = new node( data[i].split( delim ) ) ;		
		}
		if ( isAncestor == false ) {
			prevNode.setNext( n ) ;
		} else {
			prevNode.setChild( n ) ;
		}
		prevNode = n ;
	}
	return head ;
}

function findEqualNode( data, node ) {
	if( node ) {
		node.setDisplay( true ) ;
		var next = node ;
		while( next )  {
			// Check for equal nodes based on key as unique identifier.
			// * Note: Comparing contents of node crashes Netscape 4.7 *
			if( data[3] == next.toArray()[3] ) {
				return node ;
			}
			next = next.getNext( ) ;
		}
	}
	return null ;
}

//-----------------------------------------------------------------------------
// Traverse tree from current node (normally the head).  
// Call buildRow( ) for each node to provide output.
function traverseTree( headLength ) {
	var frame = top.BrowseData ; 
	var node = this ;
	var content = "" ;
	// Check for public browse.
	if ( !frame ) {
		frame = top.BrowseDisplay ;
	}
	if ( !frame )
	{
		frame = window;
	}
	while( node ) {
		content += frame.buildNode( node, headLength ) ;
		var child = node.getChild( ) ;
		if ( child && child.isDisplay( ) ) {
			// Make recursive call to traverseTree.
			content += child.traverseTree( headLength ) ;
		}
		node = node.getNext( ) ;
	}
	return content ;
}

