var element ;
var defaultHTML = '<img src="tree/images/loading.gif">' ;
var hiddenHTML = '<img src="tree/images/loading.gif" style="display:none">' ;
var defaultText = 'Loading...' ;
var INIT_BASIC = 1 ;
var INIT_GUI = 2 ;
var INIT_XSL = 4 ;
var INIT_XML = 8 ;
var INIT_HTML = 16 ;
var INIT_VALUE = 32 ;
var INIT_PARENT = 64 ;
var INIT_XML_ONLOAD = 512 ;
var INIT_ERROR = 1024 ;
var INIT_READY = 2048 ;

var INIT_ALL = INIT_BASIC|INIT_GUI|INIT_XSL|INIT_XML ;

function onXslLoaded()
{
	try	{	if ( (element.htcState & INIT_XSL) == 0 && window.cbXslTree.getStatus() == 'ok' )
		{
			onAfterInit(INIT_XSL) ;
			if ( window.cbXslTree.owner == element ) xslEvent.fire(createEventObject());
		}
	}
	catch(xxx) {} ;
}

function onXmlLoaded()
{
	switch (element.cbXmlDoc.getStatus())
	{
		case 'ok':
			element.htcState &= ~INIT_ERROR ;
			// Synchronize
			if ( !mozilla && !element.cbXmlDoc.badProperty && element.cbXmlDoc.getProperty ( "ForcedResync" ) == false )
			{
				// XML got possibly from cache
				var valid = (cbXmlDoc.xmlDoc.documentElement ? true : false ) ;
				if ( valid && element.time &&
						element.time != cbXmlDoc.xmlDoc.documentElement.getAttribute('time')) valid = false ;
				if ( !valid )
				{
					element.log += 'Got from server because cache was not updated\r\n' ;
					element.cbXmlDoc.setProperty ( "ForcedResync", true ) ;
					element.cbXmlDoc.xmlDoc.load( cbXmlDoc.xmlDoc.url ) ;
					return ;
				}
				element.log += 'Got from cache\r\n' ;
			}
			element.cbXmlDoc.setProperty("SelectionLanguage", "XPath");
			element.xml = element.cbXmlDoc.xmlDoc.documentElement ;
			element.htcState &= ~INIT_XML_ONLOAD ;
			onAfterInit(INIT_XML) ;
			onXslLoaded() ; // Ensure XSL is also existing
			return ;

		case 'error':
			if ( !mozilla && !element.cbXmlDoc.badProperty && element.cbXmlDoc.getProperty ( "ForcedResync" ) == false )
			{
					element.log += 'Got from server after an error\r\n' ;
					element.cbXmlDoc.setProperty ( "ForcedResync", true ) ;
					element.cbXmlDoc.load( element.cbXmlDoc.xmlDoc.url ) ;
					return ;
			}

			element.htcState &= ~INIT_XML_ONLOAD ;
			element.htcState |= INIT_ERROR ;
			if ( element.edit )
			{
				element.edit.title = element.cbXmlDoc.errorMessage + element.cbXmlDoc.xmlDoc.url ;
				element.edit.value = 'XML Error' ;
			}
			else if (element.div)
			{
				element.div.innerHTML = element.cbXmlDoc.errorMessage + element.cbXmlDoc.xmlDoc.url ;
			}
			return ;
	}
}


function onAfterInit(newstate)
{
//	element.log += 'State changed: ' + newstate + ' (' + htcState + ')\r\n' ;
	switch(newstate)
	{
		case INIT_GUI: element.log += 'Gui initialized\r\n' ;break;
		case INIT_XSL: element.log += 'XSL initialized\r\n' ;break;
		case INIT_XML: element.log += 'XML initialized\r\n' ;break;
	}

	if ( element.htcState & INIT_READY ) return ;
	element.htcState |= newstate ;

	if ( (element.htcState & INIT_ALL)==INIT_ALL )
	{
		element.htcState |= INIT_READY ;
		if ( element.div && element.div.style.display != 'none' )
		{
			rebuildNode(element.xml) ;
			//if ( element.value) scroll() ;
		}
	}
}

function initializeDiv()
{
	if ( element.div ) return ;

	element.div = window.document.createElement("div") ;
	element.style.display = 'none' ; // In case of an open list hide it just before inserting the div
	if ( element.size > 0 )
		element.parentNode.insertBefore(element.div, element);
	else
		window.document.body.insertBefore ( element.div,window.document.body.firstChild ) ; // Insert in the begining of the document


	// Set the DIV properties
	element.div.className = 'tree' ;
	element.div.align="left" ;
	element.div.innerHTML = (element.xmlSrc != 'null' && !element.parent ) ? defaultHTML : hiddenHTML ;
  // element.div.isOverlapped = isOverlapped ;
	element.div.align = 'right' ;

	element.div.onclick = onDivClick ;
	element.div.oncontextmenu = onDivRightClick ;
	element.div.onmousedown = onDivMouseDown ;
	element.div.onmouseover = onDivMouseOver ;
	element.div.onmouseout = onDivMouseOut ;
	element.div.style.width = element.width ;
	element.div.style.height= element.height ;

	if ( element.size > 0 )
		element.div.style.border = mozilla ? '1pt inset' : '2pt window-inset' ;
}

function initXml()
{
	// Build the URL
	url = element.xmlSrc ;
	element.log += 'Loading: ' + url + '\r\n' ;
	element.htcState &= ~(INIT_READY | INIT_ERROR | INIT_XML | INIT_HTML ) ;
	element.xml = null ;
	if ( element.edit ) element.edit.disabled = true ;
	if ( url && url != 'null' ) // 'null' is a string, not null!
	{
		if ( element.div ) element.div.innerHTML = defaultHTML ;
		if ( element.edit )
		{
			if ( !element.text ) element.edit.value = defaultText ;
			element.edit.disabled = true ;
		}
		element.htcState |= INIT_XML_ONLOAD ;

		// Create the xml object
		if ( !element.cbXmlDoc )
		{
			element.cbXmlDoc = new CrossBrowserXml ;
			element.cbXmlDoc.setHandler(  onXmlLoaded ) ;
			// Load it
			if ( element.time ) cbXmlDoc.setProperty ( "ForcedResync", false ) ;
			if ( element.cbXmlDoc.badProperty ) element.log += 'DOES NOT SUPPORT "ForcedResync"!!!!\r\n' ;
		}
		element.cbXmlDoc.load(url) ;
	}
	else
		if ( element.div ) element.div.innerHTML = hiddenHTML ;
}

function initializeTree(select)
{
	element = select ;
	element.htcState = INIT_BASIC ;
	element.xmlSrc = element.getAttribute('xmlSrc') ; // for compatibility


	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Pre Load images to prevent the browser loading every image again
	if ( !window.document.plusImg )
	{
		window.document.plusImg = new Image; window.document.plusImg.src = "tree/images/plus.gif";
		window.document.minusImg = new Image; window.document.minusImg.src = "tree/images/minus.gif";
		window.document.browseImg = new Image; window.document.browseImg.src = "tree/images/browse.gif" ;
		window.document.eraseImg = new Image; window.document.eraseImg.src = "tree/images/btn_erase.gif" ;
		window.document.loadingImg = new Image; window.document.loadingImg.src = "tree/images/loading.gif" ;
	}

	// Compute dimentions
	element.width = element.offsetWidth ? parseInt(element.offsetWidth) : parseInt(element.style.width) ;
	if ( isNaN( element.width ) || element.width < 50 ) element.width = 200 ;
	element.height = 300 ;
	if ( element.size > 0 && element.offsetHeight ) element.height = element.offsetHeight ;
	if ( element.style.height ) element.height = element.style.height ;

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Do once for all tree controls in document
	if ( !window.tree_exist )
	{
		window.tree_exist = 1 ;
		element.log += 'First Tree, XSL Creator\r\n' ;
		window.mozilla = (window.document.implementation && window.document.implementation.createDocument ) ? true : false ;

		if ( window.mozilla )
		{
			element.cursorHand = 'pointer' ;

			var s = window.document.styleSheets[0] ;
			s.insertRule('DIV.tree{	font-family: sans-serif; font-weight: normal; font-size: 8pt;	background-color: white;	overflow: auto ;}',0) ;
			s.insertRule('DIV.tree .plain{text-decoration : none;}',0) ;
			s.insertRule('DIV.tree .hover{text-decoration : none;	font-color : #FFFFFF;	background-color : #FF9900;	cursor: pointer ;}',0) ;
			s.insertRule('DIV.tree .disabled{	font-family: sans-serif;			cursor: default; color: navy; font-weight: bold;	text-decoration : none;}',0) ;
			s.insertRule('DIV.tree .selected{	color:white ;	background-color:darkblue ;	text-decoration : none;}',0) ;
			s.insertRule('DIR	{ margin-top: 0 ; margin-bottom: 0 ; }',0) ;
//			s.insertRule('DIV.tree SPAN.indent{	position:relative; left: 10 ;	display: block ;}',0) ;
			// Define browser based functions
			Object.prototype.attachEvent = function(e,h) {this.addEventListener(e.slice(2),h,0) ; }
			Object.prototype.detachEvent = function(e,h) {this.removeEventListener(e.slice(2),h,0) ; }
			window.xsltProcessor = new XSLTProcessor();
			window.htmlDoc = document.implementation.createDocument("", "", null);
		}
		else
		{
			element.cursorHand = 'hand' ;
	  	window.document.createStyleSheet( 'tree/tree.css' ) ;
		}

		// Build the XSL file common to all trees in this window
		window.cbXslTree = new CrossBrowserXml ;
		window.cbXslTree.setHandler( onXslLoaded ) ;
		window.cbXslTree.setProperty ("ForcedResync", false) ; // load it from cache
		cbXslTree.load('tree/maketree.xml') ;
	}
	else
	{
			// All windows except the xsl creator, will get the xsl when it finish loading.
			window.cbXslTree.owner.attachEvent('onxslloaded',onXslLoaded) ;
	}

	if ( element.size > 0 ) initializeDiv() ; // Make the div area only in case of an open list

	//element.attachEvent( 'onpropertychange', onPropertyChanged ) ;

	/////////////////////////////////////////////////////////////////////////////
	// Initialize the XML
	/////////////////////////////////////////////////////////////////////////////

	initXml() ;

	/////////////////////////////////////////////////////////////////////////////
	// Initialize other parts
	/////////////////////////////////////////////////////////////////////////////

	// Give a name to the text input control so that it can be submitted
	if ( element.textName ) element.edit.name=element.textName ;
	// Create a hidden input to submit the base level of a multipart tree
	if ( element.baseLevelName )
	{
		element.base_level_input = window.document.createElement("input") ;
		element.base_level_input.type="hidden" ;
		element.base_level_input.name=element.baseLevelName ;
		element.parentNode.insertBefore(element.base_level_input, element);
	}
	//element.focus = setFocus ;
	if ( element.form )
	element.form.attachEvent('onreset', function(){
		if ( element.value != element.defaultValue ){ element.htcState &= ~INIT_HTML ; element.value = element.defaultValue ;}
				} ) ;

	element.log += 'Name: ' + element.name + '\r\n' ;
	element.log += 'Source: ' + element.xmlSrc + '\r\n' ;
	element.log += 'Default Value:' + element.defaultValue + '\r\n' ;
	element.log += 'Popup: ' + (element.usePopup  ? 'yes\r\n' : 'no\r\n') ;
	element.log += 'Parent: ' + (element.parent  ? element.parent : 'none' ) + '\r\n' ;

	if ( element.parent ) 	setParent() ;
	onAfterInit (INIT_GUI) ;
}

function CrossBrowserXml(doc)
{
	this.xmlDoc = doc ;
	if ( window.mozilla )
	{
		if ( !doc )	this.xmlDoc = window.document.implementation.createDocument("", "", null);
		this.transform = function(node,img) {
				xsltProcessor.transformDocument(node, cbXslTree.xmlDoc, window.htmlDoc, null);
				img.parentNode.insertBefore(  window.htmlDoc.documentElement, img ) ;		}
		this.findNode = function(xpath)	{	return this.xmlDoc.evaluate(xpath, this.xmlDoc.documentElement, null, XPathResult.ANY_TYPE,null).iterateNext() }
		this.getStatus = function() { return 'ok' ; }
		this.setHandler = function(func) { this.xmlDoc.onload=func ; }
		this.setProperty = function(n,v) {}
	}
	else
	{
		if ( !doc )	this.xmlDoc = new ActiveXObject("Msxml2.DOMDocument");
		this.transform = function(node,img) {
			var strHTML = node.transformNode ( cbXslTree.xmlDoc ).replace( /\&amp;/mg, '&' )  ;
			try {img.insertAdjacentHTML('beforeBegin', strHTML ) ;} catch(xxx){element.div.innerText = strHTML ; }
		}
		this.findNode = function(xpath){	 return element.xml.selectSingleNode( xpath ) ; }
//		this.findNode = function(xpath){	 return this.xmlDoc.documentElement.selectSingleNode( xpath ) ; }
		this.getStatus = function()
			{
				if ( this.xmlDoc.readyState < 4 ) return 'loading' ;
				if ( this.xmlDoc.parseError.errorCode == 0) return 'ok' ;
				if ( this.xmlDoc.parseError.errorCode == -1072897514) return 'loading' ;
				this.errorMessage = this.xmlDoc.parseError.reason + ' (' + this.xmlDoc.parseError.errorCode + ') ' + this.xmlDoc.xml ;
				return 'error' ;
			}
		this.badProperty = '' ;
		this.setHandler = function(func) { this.xmlDoc.onreadystatechange=func ; }
		this.setProperty = function(n,v) { try {this.xmlDoc.setProperty(n,v) ;}catch(xxx){this.badProperty=n;} }
		this.getProperty = function(n) { try { return this.xmlDoc.getProperty(n) ;}catch(xxx){return true ;} }
	}
	this.load = function (u) {this.xmlDoc.load(u) ; }
	this.owner = element ;
}

function onDivClick(e)
{
	var ev = new CrossBrowserEvent(e) ;
	var changed = false ;
	status = '' ;
	if ( element.disabled || element.readonly ) return ;
	if ( ev.className == 'disabled' || ev.className == 'parentSelected' ) return ;
	var img = ev.srcElement.previousSibling ;
	if ( !img ) return ;
	if ( img.nodeName.toUpperCase() != 'IMG' ) return ;
	// Find the node object in HTML
	var node = getNode( img.name ) ;

	// Go to the URL
	if ( element.href > '' )
	{
		window.location.href = element.href + img.name;
	}
	else
	if ( node.getAttribute( 'href' ) )
	{
		window.location.href = node.getAttribute( 'href' ) ;
	}
}

function onDivMouseOver(e)
{
	var ev = new CrossBrowserEvent(e) ;
	switch ( ev.className )
	{
		case 'plain':
		case 'selected':
		{
			ev.srcElement.classSave = ev.srcElement.className ;
			ev.srcElement.className = 'hover' ;
			status = ev.srcElement.innerText + ' [' +  ev.srcElement.previousSibling.name + ']' ;
		}
	}
}

function onDivMouseOut(e)
{
		var ev = new CrossBrowserEvent(e) ;
		if ( ev.className == 'hover' )
			ev.srcElement.className = ev.srcElement.classSave ;
		status = '' ;
}

function onDivRightClick(e)
{
		var ev = new CrossBrowserEvent(e) ;
		var img = ev.srcElement.previousSibling ;
		if ( !img ) return ;
		if ( img.nodeName == 'IMG' )
		{
			ev.stop() ; 	ev.abort() ;
//			showLongDescription(img.name) ;
		}
//		else // display log...
//			if (!mozilla && event.ctrlKey && event.shiftKey ) showLongDescription() ;
}

function onDivMouseDown(e)
{
	var ev = new CrossBrowserEvent(e) ;
	ev.stop() ; // Dont pass it to body

	window.activeTree = element ;
	var img = ( ev.className == 'disabled' ) ? ev.srcElement.previousSibling : ev.srcElement ;
	if ( img.nodeName.toUpperCase() == 'IMG' )
	{
		var node = getNode(img.name) ;
		if ( node )
		{
			var op = node.getAttribute("open") ;
			node.setAttribute ( "open", ( op == 'yes' )?  'no' : 'yes' ) ;
			rebuildNode(node, img) ;
		}
		ev.abort() ;
	}
}

function CrossBrowserEvent(e)
{
	this.event = window.mozilla ? e : event ;
	if ( !this.event && element.pop )
		this.event = element.pop.document.parentWindow.event ;
	this.srcElement = window.mozilla ? this.event.target : this.event.srcElement ;
	this.className = ( this.srcElement&&this.srcElement.className ) ? this.srcElement.className : '' ;
	this.stop = function() {window.mozilla? this.event.stopPropagation() : this.event.cancelBubble = true ;}
	this.abort = function() { window.mozilla? this.event.preventDefault() : this.event.returnValue=false ; }
}

// Convert the node to HTML and update it in the DIV.
// If the node passed is the root node then all the HTML is rebuilded, else,
// only the specified node and it's children
function rebuildNode(node)
{
	if ( !(element.htcState & INIT_READY) ) { alert ('NOT READY' ) ; return ; }
	if ( !element.div )  return ;
	node = getNode(node) ;
	if ( !node )  { alert ('NO NODE' ) ; return ; }
	var img ;
	if ( node.nodeName == 'node' )
		img = findHTMLNode( node.getAttribute('id' )) ;
	else // Build all
	{
		img=element.div.firstChild ;
		element.htcState |= INIT_HTML ;
	}
	if ( !img ) { /*alert ('NO IMG' ) ;*/ return ; }

	if ( element.emptyMessage && element.xml.childNodes.length == 0 )
	{
		element.div.innerHTML = emptyMessage ;
		return ;
	}

	element.cbXmlDoc.transform(node,img) ;

	while (img.nextSibling && img.nextSibling.nodeName.toUpperCase() != 'IMG' )
		img.nextSibling.parentNode.removeChild(img.nextSibling) ;
	img.parentNode.removeChild(img) ;
}

// Every img in HTML has a 'name' attribute that can identify it.
// The reason name used instead of ID is that the name is not alwais unique in
// document scope. (but it defenetly unique in the elemen's scope).
function findHTMLNode(id)
{
	try
	{
		return element.div.all.namedItem(id) ;
	}
	catch(xxx)
	{
		var items = window.document.getElementsByName(id) ;
		if (!items) return null ;
		var i, o ;
		for ( i = 0 ; i < items.length ; i++ )
		{
			for ( o = items[i] ; o ; o = o.parentNode )
			{
				if ( o == element.div ) 	return(items[i] );
			}
		}
	}
}

// return the XML node that has the ID specified or the node itself if it is
// already a node, or the root node if id is null
function getNode(id)
{
	if ( !element.xml ) return null ;
	if ( id == null ) return element.xml ;
	if ( id.nodeName ) return id ;
	return element.cbXmlDoc.findNode ( '//node[@id="'+id+'"]' ) ;
//	return xml.selectSingleNode ('//node[@id="'+id+'"]' ) ;
}

