// Title: Tigra Tree Menu Ajax v1.0.2 (11/24/2008)
// URL: http://www.softcomplex.com/products/tigra_tree_menu_ajax/
// Notes: Registration needed to use this script legally. Visit official site for details.

// ------------------------------------------------------------------------------------------
// tree constructor
function tree (a_template) {

	// make sure compatible browser is used
	if (!document.body || !document.body.innerHTML)
		throw 'TTMA001';

	this.a_tpl      = a_template;
	this.o_root     = this;
	this.a_index    = []; // all loaded tree items
	this.a_nodes    = []; // all loaded nodes
	this.n_depth    = -1;
	this.n_id       = TREES.length + 1; // Starweb: Add + 1 since no root is displayed
	this.s_contID   = a_template['contID'] ? a_template['contID'] : 'tree_' + this.n_id;
	this.b_multiSel = Boolean(a_template['multiselect']);
	//this.iAmStart_Id = a_template['iAmStart_Id'];

	// methods
	this.f_ajaxRequest = f_treeAjaxRequest;
	this.f_ajaxProcess = f_treeAjaxProcess;
	this.f_createSubmenu = f_createSubmenu;
	this.f_event = f_treeEvent;
	this.f_reload = f_treeReload;

	// assign custom methods
	this.f_getItemTextEx = a_template['itemTextEx'] && typeof(window[a_template['itemTextEx']]) == 'function' ?
		window[a_template['itemTextEx']] : function () { return '' };
	if (a_template['preEvent'] && typeof(window[a_template['preEvent']]) == 'function')
		this.f_preEvent = window[a_template['preEvent']];
	if (a_template['postEvent'] && typeof(window[a_template['postEvent']]) == 'function')
		this.f_postEvent = window[a_template['postEvent']];


	// register in global collection
	TREES[this.n_id] = this;

	// preload icons
	f_treeCacheImage(a_template['icon_e']);
	f_treeCacheImage(a_template['icon_l']);
	for (var i = 0; i < 128; i++)
		f_treeCacheImage(a_template['icon_' + i]);
	
	// create container if doesn't already exist
	var e_container = f_getElement(this.s_contID);
	if (!e_container)
		document.write('<div id="', this.s_contID, '" class="', this.a_tpl['contClass'], '">', this.a_tpl['msgLoading'], '</div>');
	
	// request data
	this.f_ajaxRequest();
}

// ------------------------------------------------------------------------------------------
// tree specific methods
function f_treeEvent (s_event, n_id) {
	var o_item = this.a_index[n_id];
	
	if (this.f_preEvent && !this.f_preEvent(s_event, o_item))
		return false;
	
	if (o_item.b_disabled)
		return false;
	
	if (s_event == 'mouseout')
		return o_item.f_rollover(true);
	if (s_event == 'mouseover')
		return o_item.f_rollover();
	if (s_event == 'toggle')
		return o_item.f_open(o_item.b_open);
	if (s_event = 'select')
		return o_item.f_select(this.b_multiSel && o_item.b_selected);

	if (this.f_postEvent)
		this.f_postEvent(s_event, o_item);
}

// ------------------------------------------------------------------------------------------
function f_treeAjaxRequest (n_id) {

	var o_item, s_param;
	// ajax node (provide custom ID if specified)
	if (n_id != null) {
		o_item = this.a_index[n_id];
		s_param = '&id=' + (o_item.s_cid != null ? o_item.s_cid : n_id);
	}
	// initial request
	else {
		o_item = this;
		s_param = '';
	}

	if (window.ActiveXObject) 
		o_item.o_http = new ActiveXObject("Microsoft.XMLHTTP");
	else if (window.XMLHttpRequest) 
		o_item.o_http = new XMLHttpRequest();
	else
		throw 'TTMA002';
	eval ('o_item.o_http.onreadystatechange = function () { if(TREES && TREES["' + this.n_id + '"]) TREES["' + this.n_id + '"].f_ajaxProcess(' + n_id + '); }');
	
	o_item.o_http.open("GET", this.a_tpl['ajaxURL'] + s_param, true);
	o_item.o_http.send(null);
	o_item.b_loading = true;
	if (o_item.n_depth != -1)
		o_item.f_updateProps();
}

// ------------------------------------------------------------------------------------------
function f_treeAjaxProcess (n_id) {

	o_item = n_id != null ? this.a_index[n_id] : this;
	if (!o_item) return;

	if (o_item.o_http.readyState != 4) return;
	if (o_item.o_http.status != 200 && o_item.o_http.status != 304) throw 'TTMA003';

	o_item.e_xml = o_item.o_http.responseXML;
	o_item.b_loading = false;
	if (o_item.n_depth != -1)
		o_item.f_updateProps();
	o_item.f_createSubmenu();
}

// ------------------------------------------------------------------------------------------
function f_treeReload () {
	this.a_index = [];
	this.a_nodes = [];
	this.a_children = [];
	this.s_contID.innerHTML = '';
	this.b_rendered = false;
	this.f_ajaxRequest();
}

// ------------------------------------------------------------------------------------------
// Methods shared by trees and items
function f_createSubmenu (b_getHTML) {
	var e_block = this.e_xml.getElementsByTagName("block");
	if (!e_block || e_block.length == 0) return false;
	if (e_block.length) e_block = e_block[0];

	// initialize items
	this.a_children = [];
	var e_itemXML, i, a_blockHTML = [];
	for (i = 0; i < e_block.childNodes.length; i++) {
		e_itemXML = e_block.childNodes[i];
		if (e_itemXML.tagName == 'item')
			new tree_item(this, e_itemXML);
	}
	
	// get HTML for items
	var o_item;
	for (i = 0; i < this.a_children.length; i++) {
		o_item = this.a_children[i];
		a_blockHTML[i] = o_item.f_getHTML();
	}

	// insert HTML into the document
	var s_html = a_blockHTML.join('');
	this.b_rendered = true;
	if (b_getHTML) return s_html;

	var e_container = f_getElement(this.s_contID);
	e_container.style.display = 'none';
	if (!s_html) return;
	e_container.innerHTML = s_html;
	e_container.style.display = 'block';
}

// ------------------------------------------------------------------------------------------
// item constructor
function tree_item (o_parent, e_xml) {

	// set properties
	this.o_parent = o_parent;
	this.e_xml    = e_xml;
	this.o_root   = o_parent.o_root;
	this.n_depth  = o_parent.n_depth + 1;
	this.a_styles = [];
	this.a_icons  = [];

	// assign methods
	this.f_updateProps = f_itemUpdateProps;
	this.f_getParam = f_itemGetParam;
	this.f_getHTML = f_itemGetHTML;
	this.f_createSubmenu = f_createSubmenu;
	this.f_event = f_itemEvent;
	this.f_open = f_itemOpen;
	this.f_rollover = f_itemRollover;
	this.f_select = f_itemSelect;
	this.f_delete = f_itemDelete;
	this.f_reload = f_itemReload;

	this.n_order  = o_parent.a_children.length;
	o_parent.a_children[this.n_order] = this;
	
	// register in tree index
	this.n_id = this.o_root.a_index.length;
	this.o_root.a_index[this.n_id] = this;

	// set the type (leaf / node / ajaxnode)
	this.s_type = e_xml.getAttribute('type');
	var e_submenus = e_xml.getElementsByTagName('block');
	if (e_submenus && e_submenus.length) this.s_type = 'node';
	else if (!this.s_type) this.s_type = 'leaf';
	
	// copy attributes
	this.b_selected = e_xml.getAttribute('selected') == 'yes';
	this.b_disabled = e_xml.getAttribute('disabled') == 'yes';
	
	// copy event handlers
	var s_attr, i;
	for (i = 0; i < A_TREVENTS.length; i++)
		if (s_attr = e_xml.getAttribute(A_TREVENTS[i]))
			eval ("this.f_" + A_TREVENTS[i] + " = function() {" + s_attr + "}");

	var e_xmlTag, e_ahref;
	for (i = 0; i < e_xml.childNodes.length; i++) {
		e_xmlTag = e_xml.childNodes[i];
		// get reference to the link element
		if (e_xmlTag.tagName == 'a') {
			e_ahref = e_xmlTag;
			continue;
		}
		if (e_xmlTag.tagName == 'icon') {
			n_state = e_xmlTag.getAttribute('state');
			if (!n_state) n_state = 0;
			this.a_icons[n_state] = e_xmlTag.firstChild.nodeValue;
		}
		if (e_xmlTag.tagName == 'class') {
			n_state = e_xmlTag.getAttribute('state');
			if (!n_state) n_state = 0;
			this.a_styles[n_state] = e_xmlTag.firstChild.nodeValue;
		}
	}

	var e_ahref = this.e_xml.getElementsByTagName('a');
	if (!e_ahref || e_ahref.length == 0) throw 'TTMA003';
	if (e_ahref.length) e_ahref = e_ahref[0];
	this.e_ahref = e_ahref;
	this.s_text = e_ahref.firstChild.nodeValue;
	this.s_link = e_ahref.getAttribute('href');

	if (this.s_type == 'node' || this.s_type == 'ajaxnode') {
		// register in node index
		this.n_nodeID = this.o_root.a_nodes.length;
		this.o_root.a_nodes[this.n_nodeID] = this;

		// set node properties
		this.b_node = true;
		this.b_open = e_xml.getAttribute("open") == 'yes';
	}

	// register in custom id index
	this.s_cid = e_xml.getAttribute("id");
}

// ------------------------------------------------------------------------------------------
// returns HTML of the item and its subitems
function f_itemGetHTML () {

	// define frequently used attributes
	var s_rollover = 'onmouseover="TREES[\'' + this.o_root.n_id + '\'].f_event(\'mouseover\',' + this.n_id
		+ ')" onmouseout="TREES[\'' + this.o_root.n_id + '\'].f_event(\'mouseout\',' + this.n_id + ')"';
	var s_toggle = 'TREES[\'' + this.o_root.n_id + '\'].f_event(\'toggle\',' + this.n_id + ');';
	var s_select = 'return TREES[\'' + this.o_root.n_id + '\'].f_event(\'select\',' + this.n_id + ');';
	var s_link   = this.s_link ? ' href="' + this.s_link + '" onmouseup="this.blur()"' : '';
	var s_target = this.e_ahref.getAttribute('target');
	if (!s_target) s_target = this.o_root.a_tpl['target'];
		s_target = s_target && s_link ? ' target="' + s_target + '"' : '';
	
	var s_title  = this.e_ahref.getAttribute('title');
	var s_alt    = s_title ? ' alt="' + s_title + '"' : '';
		s_title  = s_title ? ' title="' + s_title + '"' : '';

	// get HTML for lines and spacers
	var	a_offset = [],
		o_current_item = this.o_parent;

	var a_props = this.f_updateProps(true);
	for (i = this.n_depth; i > 0; i--) { //(this.iAmStart_Id ? this.n_depth+1 : this.n_depth)
		a_offset[i] = '<img src="' + this.o_root.a_tpl[o_current_item.n_state & 33 ? 'icon_e' : 'icon_l'] + '" />';
		o_current_item = o_current_item.o_parent;
	}

	
	/* STARWEB MODIFIED CODE - 2009-01-03 - START */
	// return HTML
	return '<table cellpadding="0" cellspacing="0" border="0" ' + s_rollover + ' class="' + a_props[2] + '" id="r'
		+ this.o_root.n_id + '_' + this.n_id + '"><tr><td>' + a_offset.join('')

		// junction or +/-
		+ (a_props[1] ? ('<img src="' + a_props[1] + '" ' + (this.b_node ? 'onmousedown="' + s_toggle + '" name="j'
		+ this.o_root.n_id + '_' + this.n_id + '" style="cursor:pointer;cursor:hand;"' : '') + ' />') : '')
		
		// item icon
		/*+ (a_props[0] ? '<a' + s_link + s_target + s_title + ' onclick="' //ondblclick="'
		+ (this.b_node ? s_select : s_toggle) + '"><img src="' + a_props[0] + '" border="0" name="i'
		+ this.o_root.n_id + '_' + this.n_id + '"' + s_alt + ' /></a>' : '')*/

		// item text			
		+ '</td><td width="100%" class="treeTextTD"><a' + s_link
		+ s_target + s_title + (s_link ? '' : ' onclick="' + s_toggle + '" style="cursor:pointer;cursor:hand;"')
		+ ' id="t' + this.o_root.n_id + '_' + this.n_id + '">' + this.s_text + '</a>'
		+ this.o_root.f_getItemTextEx(this) + '</td></tr></table>'
		+ (this.b_node ? '<div class="subdiv" id="c' + this.o_root.n_id + '_' + this.n_id + '" style="display:'
		+ (this.b_open ? 'block">' + this.f_createSubmenu(true)	+ '</div>' : 'none"></div>') : '');
	/* STARWEB MODIFIED CODE - 2009-01-03 - END */
}

// ------------------------------------------------------------------------------------------
// removes item from the tree
function f_itemDelete (b_recursive) {

	// recursively delete children
	if (this.a_children) {
		for (var i = 0; i < this.a_children.length; i++)
			this.a_children[i].f_delete(true);
		this.a_children = null;
	}

	// remove from root's collection and node index (don't reuse IDs)
	this.o_root.a_index[this.n_id] = null;
	if (this.n_nodeID != null)
		this.o_root.a_nodes[this.n_nodeID] = null;
	
	// don't worry about cleaning up HTML and children if in recursion
	if (b_recursive) return;

	// remove from parent's collection (purge)	
	for (var i = this.n_order; i < this.o_parent.a_children.length - 1; i++) {
		this.o_parent.a_children[i] = this.o_parent.a_children[i + 1];
		this.o_parent.a_children[i].n_order = i;
	}
	this.o_parent.a_children.length = this.o_parent.a_children.length - 1;
		
	// cleanup HTML
	e_elem = f_getElement('c' + this.o_root.n_id + '_' + this.n_id);
	if (e_elem) e_elem.parentNode.removeChild(e_elem);
	e_elem = f_getElement('r' + this.o_root.n_id + '_' + this.n_id);
	if (e_elem) e_elem.parentNode.removeChild(e_elem);
}

// ------------------------------------------------------------------------------------------
// reloads subitems of this item
function f_itemReload () {

	if (this.s_type != 'ajaxnode') return;
	if (this.a_children) {
		for (var i = 0; i < this.a_children.length; i++)
			this.a_children[i].f_delete(true);
		this.a_children = null;
	}
	e_elem = f_getElement('c' + this.o_root.n_id + '_' + this.n_id);
	if (e_elem) e_elem.innerHTML = '';

	this.o_root.f_ajaxRequest(this.n_id);
}

// ------------------------------------------------------------------------------------------
function f_itemEvent (s_event) {
	var s_handler = 'f_' + s_event;
	if (this[s_handler])
		return this[s_handler]();
	if (this.o_root[s_handler])
		return this.o_root[s_handler](this);
	return true;
}

// ------------------------------------------------------------------------------------------
function f_itemOpen (b_close) {
	
	// skip if not a node or node in the requested state
	if (!this.b_node || Boolean(this.b_open) != Boolean(b_close)) return;
	
	// run cusom handler
	if (!this.f_event(b_close ? 'onclose' : 'onopen')) return false;

	// update styles and images
	this.b_open = !b_close;
	this.f_updateProps();

	this.s_contID = 'c' + this.o_root.n_id + '_' + this.n_id;
	var o_idiv = f_getElement(this.s_contID);

	if (b_close) {
		o_idiv.style.display = 'none';
		return;
	}
	if (this.b_rendered) {
		o_idiv.style.display = 'block';
		return;
	}
	if (this.s_type == 'node')
		return this.f_createSubmenu();

	if (this.s_type == 'ajaxnode')
		this.o_root.f_ajaxRequest(this.n_id);
}

// ------------------------------------------------------------------------------------------
function f_itemSelect(b_unselect) {
	
	if (b_unselect) {
		if (!this.f_event('onunselect')) return false;
	}
	else {
		// run cusom handler
		if (!this.f_event('onselect')) return false;

		if (!this.o_root.b_multiSel) {
			var i, o_item;
			for (i = 0; i < this.o_root.a_index.length; i++) {
				o_item = this.o_root.a_index[i];
				if (o_item.b_selected && o_item != this)
					o_item.f_select(true);
			}
		}
	}

	this.b_selected = !b_unselect;
	this.f_updateProps();
	return false;
}

// ------------------------------------------------------------------------------------------
function f_itemRollover(b_mouseout) {

	// run cusom handler
	if (!this.f_event(b_mouseout ? 'onmouseout' : 'onmouseover')) return false;

	this.b_mouseover = !b_mouseout;
	this.f_updateProps();
}

// ------------------------------------------------------------------------------------------
// tries to find icon or style first locally then in template
function f_itemGetParam (s_prefix) {

	// first ignore root, node last and junction then mouseover, selected, open
	var a_bits = [51, 64, 4, 8],
		n_bitmap = 0,
		e_xml, s_value, i,
		a_list = this['a_' + s_prefix + 's']; // a_icons or a_styles

	// search locally first
	for (i = 0; i < a_bits.length; i++) {
		n_bitmap += a_bits[i];
		if (s_value = a_list[this.n_state & ~n_bitmap])
			return s_value;
	}
	// first ignore last and junction then selected, open, mouseover, node, root
	a_bits = [3, 4, 8, 64, 16, 32];
	n_bitmap = 0;

	// then search in template
	for (i = 0; i < a_bits.length; i++) {
		n_bitmap += a_bits[i];
		if (s_value = this.o_root.a_tpl[s_prefix + '_' + (this.n_state & ~n_bitmap)])
			return s_value;
	}
}

// ------------------------------------------------------------------------------------------
function f_itemUpdateProps (b_return) {

	// state bitmap
	this.n_state =
		// +128 ajax at work
		(this.b_loading ? 128 : 0) +
		 // +64 mouse over
		(this.b_mouseover ? 64 : 0) +
		 // +32 root
		(this.n_depth ? 0 : 32) +
		 // +16 node
		(this.b_node ? 16 : 0) +
		 // +8 open
		(this.b_open ? 8 : 0) +
		 // +4 selected
		(this.b_selected ?  4 : 0) +
		// +2 junction icon
		// +1 last child
		(this.n_order == this.o_parent.a_children.length - 1 ? 1 : 0);

	var s_junct = this.o_root.a_tpl['icon_' + (this.n_state & ~196 | 2)];
	var s_image = this.f_getParam('icon');
	var s_style = this.f_getParam('style');

	// value return request	
	if (b_return)
		return [s_image, s_junct, s_style];

	// get icon objects and update them accordingly to new state
	var o_obj = document.images['j' + this.o_root.n_id + '_' + this.n_id];
	if (o_obj) {o_obj.src = s_junct; }
		o_obj = document.images['i' + this.o_root.n_id + '_' + this.n_id];
	if (o_obj) {o_obj.src = s_image; }
		o_obj = f_getElement('r' + this.o_root.n_id + '_' + this.n_id);
	if (o_obj) o_obj.className =  s_style;
}

// ------------------------------------------------------------------------------------------
// global variables and functions
var TREES = [],
	A_TREVENTS = ['onmouseover', 'onmouseout', 'onopen', 'onclose', 'onselect', 'onunselect'];

// preload image if not already cached
function f_treeCacheImage (s_path) {
	var s_ref = 'cached_' + s_path; 
	if (!s_path || window[s_ref]) return;
	window[s_ref] = new Image();
	window[s_ref].src = s_path;
}

f_getElement = document.all ?
	function (s_id) { return document.all[s_id] } :
	(document.getElementById ?
		function (s_id) { return document.getElementById(s_id) } :
		function (s_id) { return null });

// ------------------------------------------------------------------------------------------
// fin.
