// ------------------------------------------------------------------------------
//
// Hierarchy browser class definition
//
// ------------------------------------------------------------------------------
// Constructor
function hierScroller(name, parent_id, dataUrl, options) {
	this.scrollerName = name;
	this.dataUrl = dataUrl;
	
	this.moveItem = undefined;
	
	this.levelLists = new Array();
	
	if (!options) { options = {}; }
	this.options = options;
	if(parent_id > 0) {
		this.hierLoadAllLevels(parent_id, dataUrl);
	} else {
		this.hierLoadLevel(parent_id, 0, dataUrl);
	}
}
// ------------------------------------------------------------------------------
hierScroller.prototype.hierLoadAllLevels = function(parent_id, dataUrl) {
	this.setupHierLevel(0);

	var o = this;
	var processLevelList = function(resp) {
		o.hierProcessAllLevels(resp);
	}
	new Ajax.Request(
		dataUrl + parent_id + '&all=1', 
		{onSuccess:processLevelList, onFailure:this.hierHandleError}
	);
}
// ------------------------------------------------------------------------------
hierScroller.prototype.hierProcessAllLevels = function(resp) {
	var i, levels, l;
	for(i=0; i < resp.responseXML.childNodes.length; i++) {
		if (resp.responseXML.childNodes[i].nodeName == 'items') {
			levels = resp.responseXML.childNodes[i];
			break;
		}
	}
	if (!levels) {  return; } // alert('Error: No item list in server response!'); }

	l = 0;
	for(i=0; i < levels.childNodes.length; i++) {
		var levelContainer = levels.childNodes[i];
		switch(levelContainer.nodeType) {
			case 1:			// element
				var level = levelContainer.getAttribute('level');
				this.setupHierLevel(level);
				this.processHierLevel(level, levelContainer, levelContainer.getAttribute('selected_id'), false);
				l++;
				break;
		}
	}
	
	// Scroll hierarchy viewer to current level after short delay
	// (Safari won't scroll without the delay)
	var o = this;
	var f = function(p) {
		$(o.scrollerName).scrollLeft = (250 * l);
		this.stop();
	}
	var pe = new PeriodicalExecuter(f, 0.2);
}
// ------------------------------------------------------------------------------
hierScroller.prototype.hierLoadLevel = function (parent_id, level, dataUrl) {
	if (!level) { level = 0; }
	
	this.setupHierLevel(level);

	var o = this;
	var processCompleteLevel = function(resp) {
		o.processHierLevel(level, resp, undefined, true);
	}
	new Ajax.Request(
		dataUrl + parent_id, 
		{onSuccess:processCompleteLevel, onFailure:this.hierHandleError}
	);
	
}
// ------------------------------------------------------------------------------
hierScroller.prototype.setupHierLevel = function(level) {	
	var levelDiv;
	// Remove any levels *after* the one we're populating
	var l = level;
	while($('hierScroller_' + this.scrollerName + '_' + l)) {
		levelDiv = $('hierScroller_' + this.scrollerName + '_' + l);
		if (levelDiv) { levelDiv.parentNode.removeChild(levelDiv); }
		this.levelLists[l] = undefined;
		l++;
	}
	
	// Create div to enclose new level
	var newLevelDiv = document.createElement('div');
	newLevelDiv.className = 'hierScrollerLevel';
	newLevelDiv.style.top = '0px';
	newLevelDiv.style.left = (250 * level) + "px";
	newLevelDiv.id = 'hierScroller_' + this.scrollerName + '_' + level;
	
	// Create new ul to display list of items
	var newLevelList = document.createElement('ul');
	newLevelDiv.className = 'hierScrollerLevel';
	
	newLevelList.id = 'hierScroller_' + this.scrollerName + '_list_' + level;
	newLevelList.className = 'hierScrollerLevel';
	
	newLevelDiv.appendChild(newLevelList);
	$(this.scrollerName).appendChild(newLevelDiv);
	
	if (this.options.indicator) {
		var indicator = document.createElement('IMG');
		indicator.src = this.options.indicator;
		indicator.style.position = 'absolute';
		indicator.style.left = '50%';
		indicator.style.top = '50%';
		newLevelDiv.appendChild(indicator);
	}

	newLevelDiv.style.display = 'block';
	
	this.levelLists[level] = newLevelDiv;
	return newLevelDiv;
}
// ------------------------------------------------------------------------------
hierScroller.prototype.processHierLevel = function(level, resp, selected_id, isAjax) {	
	if (!level) { level = 0; }

	var levelDiv = $('hierScroller_' + this.scrollerName + '_' + level);
	var levelList = $('hierScroller_' + this.scrollerName + '_list_' + level);
	
	var i, items;
	if (isAjax) {
		for(i=0; i < resp.responseXML.childNodes.length; i++) {
			if (resp.responseXML.childNodes[i].nodeName == 'items') {
				items = resp.responseXML.childNodes[i];
				break;
			}
		}
		if (!items) { return; } //alert('Error: No item list in server response!'); }
	} else {
		items = resp;
	}
	
	var o = this;
	for(i=0; i < items.childNodes.length; i++) {
		var item = items.childNodes[i];
	
		switch(item.nodeType) {
			case 1:			// element
				var name = item.getAttribute('name');
				if (item.getAttribute('childCount') > 0) {
					name += ' (' + item.getAttribute('childCount') + ') >';
				}
				var id = item.getAttribute('id');
				
				var a = document.createElement('A');
				a.href='#';
				
				if (this.options.allowInfoOverlibs) {
				
					if ((item.childNodes.length > 0) && (a.l = item.childNodes[0].nodeValue)) {
						a.onmouseover = function() { overlib(this.l); }
						a.onmouseout = function() { nd(); }
					}
				}
				
				if (this.options.editUrl) {
					var editUrl = this.options.editUrl;
					a.ondblclick= function() { 
						var item_id = this.parentNode.id.split('_').pop();
						document.location = editUrl + item_id;
					};
				}
				
				a.onclick=function() {
					var item_id = this.parentNode.id.split('_').pop();
					o.hierLoadLevel(item_id, (parseInt(level) + 1), o.dataUrl);
					
					var itemList = this.parentNode.parentNode.childNodes;
					var j;
					for (j=0; j < itemList.length; j++) {
						var item = itemList.item(j);
						if (item.nodeType == 1) {
							if (item.nodeName == 'LI') {
								var a_nodes = item.getElementsByTagName('A');
								var k;
								for(k=1; k < a_nodes.length; k++) {		// k=1 to skip the first a tag which is the "move" link
									var a_node = a_nodes[k];
									a_node.className = 'hierScrollerItem';
								}
							}
						}
					}
					this.className = 'hierScrollerSelectedItem';
					return false;
				}
				
				var li = document.createElement('LI');
				
				li.className = 'hierScrollerItem';
				li.id = 'hierScroller_' + this.scrollerName + '_item_'  + id;
				a.appendChild(document.createTextNode(name));
				
				var item_id = id.split('_').pop();
				if (item_id == selected_id) {
					a.className = 'hierScrollerSelectedItem';
				} else {
					a.className = 'hierScrollerItem';
				}
				
				if (this.options.allowMoving && (level > 0)) {
					if (this.moveItem) {
						var move_div = document.createElement('DIV');
						move_div.className = 'hierScrollerMoveItem';
						var move_a = document.createElement('A');
						move_a.className = 'hierScrollerMoveItem';
						move_a.appendChild(document.createTextNode('< put'));
						move_a.href = '#';
						var o = this;
						move_a.item_id = item_id;
						move_a.item_name = item.getAttribute('name');
						move_a.onclick = function() {
							o.doMove(this);
						}
					} else {
						var move_div = document.createElement('DIV');
						move_div.className = 'hierScrollerMoveItem';
						var move_a = document.createElement('A');
						move_a.className = 'hierScrollerMoveItem';
						move_a.appendChild(document.createTextNode('move >'));
						move_a.href = '#';
						var o = this;
						move_a.item_id = item_id;
						move_a.item_name = item.getAttribute('name');
						move_a.onclick = function() {
							o.setMoveMode(this);
						}
					}
					move_div.appendChild(move_a);
					li.appendChild(move_div);
				}
				li.appendChild(a);
				
				levelList.appendChild(li);
				
				break;
			case 3:			//text
				// noop
				break;
		}
	}
	
	// Add 'Add item' button to level
	if (this.options.allowAdding) {
		var a = document.createElement('A');
		if (items.getAttribute('parent_id') > 0) {
			if (this.options.addUrl) {
				a.href= this.options.addUrl + items.getAttribute('parent_id');
			} else {
				a.href = '#';
			}
			a.className = 'hierScrollerItem';
			
			var li = document.createElement('LI');
			li.appendChild(a);
			li.className = 'hierScrollerAddItem';
			li.id = 'hierScroller_' + this.scrollerName + '_add_to_level_' + level;
			a.appendChild(document.createTextNode('Add item'));
			levelList.appendChild(li);
		}
	}
	
	// Hide loading indicator graphic
	if (this.options.indicator) {
		levelDiv.lastChild.style.display = 'none';
	}
	
	
	// Scroll hierarchy viewer to current level
	$(this.scrollerName).scrollLeft = (250 * level);
}

// ------------------------------------------------------------------------------
hierScroller.prototype.setMoveMode = function(moveItem) {
	//alert('moving ' + name);
	if (this.options.status) {
		$(this.options.status).innerHTML = 'Choose an item to move ' + moveItem.item_name + ' under.';
	}
	this.moveItem = moveItem;
	this.setMoveButtons('put');
}
// ------------------------------------------------------------------------------
hierScroller.prototype.setMoveButtons = function(m) {
	var i, j, k;
	for(i=0; i < this.levelLists.length; i++) {
		if (this.levelLists[i] == undefined) { continue; }
		for(j=0; j < this.levelLists[i].childNodes.length; j++) {
			var node = this.levelLists[i].childNodes[j];
			if (node.nodeName == 'UL') {
				var itemList = node;
				for(k=0; k < itemList.childNodes.length; k++) {
					var itemDiv = itemList.childNodes[k].firstChild;
					if (itemDiv.firstChild.nodeName == 'A') {
						var move_a = itemDiv.firstChild;
						if (m == 'put') {
							var o = this;
							move_a.onclick = function() {
								o.doMove(this);
							}
							move_a.firstChild.nodeValue = '< put';
						} else {
							
							var o = this;
							move_a.onclick = function() {
								o.setMoveMode(this);
							}
							move_a.firstChild.nodeValue = '< move';
						}
					}
				}
			}
		}
	}
}
// ------------------------------------------------------------------------------
hierScroller.prototype.clearMoveMode = function() {
	if (this.options.status) {
		$(this.options.status).innerHTML = '';
	}
	this.setMoveButtons('move');
	this.moveItem = undefined;
}
// ------------------------------------------------------------------------------
hierScroller.prototype.doMove = function(destItem) {
	if (destItem.item_id != this.moveItem.item_id) {
		//alert('Put item id='+ this.moveItem.item_id + ' (' + this.moveItem.item_name + ') under ' + destItem.item_id + ' (' + destItem.item_name + ')');
		
		this.setMoveButtons('move');
		// this.moveItem is the move a element itself
		var o = this;
		var item_id = destItem.item_id;
		var processLevelList = function(resp) {
			var i, messages; 
			for(i=0; i < resp.responseXML.childNodes.length; i++) {
				if (resp.responseXML.childNodes[i].nodeName == 'wstransaction') {
					messages = resp.responseXML.childNodes[i].childNodes;
					break;
				}
			}
			if (!messages) { alert('Error: No item list in server response!'); }
			
			var statusMessage = '';
			var success = false;
			
			for(i=0; i < messages.length; i++) {
				if (messages[i].nodeType == 1) {
					if (messages[i].getAttribute('code') == 0) {
						statusMessage = messages[i].getAttribute('message');
						success = true;
						break;
					} else {
						statusMessage += messages[i].getAttribute('message') + '<br/>';
					}
				}
			}
			o.clearMoveMode();
			if (o.options.status) {
				$(o.options.status).innerHTML = statusMessage;
			}
			if (success) {
				o.hierLoadAllLevels(item_id, o.dataUrl);
			}
		}
		
		new Ajax.Request(
			this.dataUrl + this.moveItem.item_id + '&haction=move&move_to_id=' + destItem.item_id, 
			{onSuccess:processLevelList, onFailure:this.hierHandleError}
		);
	}
}
// ------------------------------------------------------------------------------
hierScroller.prototype.hierHandleError = function(req) {
	alert('XMLHTTP Error: ' + req.statusText + ' (' + req.status + ')');
}

// ------------------------------------------------------------------------------
//
// Javascript/CSS dropdown menu; used in administrative screens and for 
// "most recently" edited list
//
// Taken from Plone v2. Thanks guys!
//
// ------------------------------------------------------------------------------
// Code to determine the browser and version.

// ------------------------------------------------------------------------------
function Browser() {
    var ua, s, i;
    
    this.isIE = false; // Internet Explorer
    this.isNS = false; // Netscape
    this.version = null;
    
    ua = navigator.userAgent;
    
    s = "MSIE";
    if ((i = ua.indexOf(s)) >= 0) {
        this.isIE = true;
        this.version = parseFloat(ua.substr(i + s.length));
        return;
    }  
    s = "Netscape6/";
    if ((i = ua.indexOf(s)) >= 0) {
        this.isNS = true;
        this.version = parseFloat(ua.substr(i + s.length));
        return;
    }
    
    // Treat any other "Gecko" browser as NS 6.1.
    
    s = "Gecko";
    if ((i = ua.indexOf(s)) >= 0) {
        this.isNS = true;
        this.version = 6.1;
        return;
    }
}
var browser = new Browser();

// Code for handling the menu bar and active button.
var activeButton = null;

// Capture mouse clicks on the page so any active button can be
// deactivated.

if (browser.isIE){
    document.onmousedown = pageMousedown;
}else{
    document.addEventListener("mousedown", pageMousedown, true);
}

// ------------------------------------------------------------------------------
function pageMousedown(event) {
    
    var el;
    
    // If there is no active button, exit.
    
    if (activeButton == null){
        return;
        }
    
    // Find the element that was clicked on.
    
    if (browser.isIE){
        el = window.event.srcElement;
    }else{
        el = (event.target.tagName ? event.target : event.target.parentNode);
    }
    // If the active button was clicked on, exit.
    
    if (el == activeButton){
        return
        };
    
    // If the element is not part of a menu, reset and clear the active
    // button.
    
    if (getContainerWith(el, "UL", "actionMenu") == null) {
        resetButton(activeButton);
        activeButton = null;
    }
}
// ------------------------------------------------------------------------------
function buttonClick(event, menuId) {
    
    var button;
    
    // Get the target button element.
    
    if (browser.isIE){
        button = window.event.srcElement;
    }else{
        if (event)
          button = event.currentTarget;
        else
          return false;
    }
    // Blur focus from the link to remove that annoying outline.
    
    button.blur();
    
    // Associate the named menu to this button if not already done.
    // Additionally, initialize menu display.
    
    if (button.menu == null) {
        button.menu = document.getElementById(menuId);
        if (button.menu.isInitialized == null) {
            menuInit(button.menu);
        }
    }
    
    // Reset the currently active button, if any.
    
    if (activeButton != null){
        resetButton(activeButton);
        }
    // Activate this button, unless it was the currently active one.
    
    if (button != activeButton) {
        depressButton(button);
        activeButton = button;
    }else{
        activeButton = null;
    }
    return false;
}
// ------------------------------------------------------------------------------
function buttonMouseover(event, menuId) {

    var button;
    
    // Find the target button element.
    
    if (browser.isIE){
        button = window.event.srcElement;
    }else{
        button = event.currentTarget;
    }
    // If any other button menu is active, make this one active instead.
    
    if (activeButton != null && activeButton != button){
        buttonClick(event, menuId);
        }
}
// ------------------------------------------------------------------------------
function depressButton(button) {

    var x, y;
    
    // Update the button's style class to make it look like it's
    // depressed.
    
    button.className += " menuButtonActive";
    
    // Make the associated drop down menu visible
    
    vis = button.menu.style.visibility;
    button.menu.style.visibility = (vis == "hidden" || vis == '') ? "visible" : "hidden";
}
// ------------------------------------------------------------------------------
function resetButton(button) {

    // Restore the button's style class.
    
    removeClassName(button, "menuButtonActive");
    
    // Hide the button's menu, first closing any sub menus.
    
    if (button.menu != null) {
        closeSubMenu(button.menu);
        button.menu.style.visibility = "hidden";
    }
}
// ------------------------------------------------------------------------------
// Code to handle the menus and sub menus.

function menuMouseover(event) {
    
    var menu;
    
    // Find the target menu element.
    
    if (browser.isIE){
        menu = getContainerWith(window.event.srcElement, "UL", "actionMenu");
    }else{
        menu = event.currentTarget;
    }
    
    // Close any active sub menu.
    
    if (menu.activeItem != null){
        closeSubMenu(menu);
        }
}
// ------------------------------------------------------------------------------
function menuItemMouseover(event, menuId) {

    var item, menu, x, y;
    
    // Find the target item element and its parent menu element.
    
    if (browser.isIE){
        item = getContainerWith(window.event.srcElement, "LI", "menuItem");
    }else{
        item = event.currentTarget;
        menu = getContainerWith(item, "UL", "menu");
    }
    // Close any active sub menu and mark this one as active.
    
    if (menu.activeItem != null){
        closeSubMenu(menu);
        menu.activeItem = item;
    }
    
    // Highlight the item element.
    
    item.className += " menuItemHighlight";
    
    // Initialize the sub menu, if not already done.
    
    if (item.subMenu == null) {
        item.subMenu = document.getElementById(menuId);
        if (item.subMenu.isInitialized == null){
            menuInit(item.subMenu);
            }
    }
    
    // Get position for submenu based on the menu item.
    
    x = getPageOffsetLeft(item) + item.offsetWidth;
    y = getPageOffsetTop(item);
    
    // Adjust position to fit in view.
    
    var maxX, maxY;
    
    if (browser.isNS) {
        maxX = window.scrollX + window.innerWidth;
        maxY = window.scrollY + window.innerHeight;
    }
    else if (browser.isIE) {
        maxX = (document.documentElement.scrollLeft != 0 ? document.documentElement.scrollLeft : document.body.scrollLeft)
        + (document.documentElement.clientWidth != 0 ? document.documentElement.clientWidth : document.body.clientWidth);
        maxY = (document.documentElement.scrollTop != 0 ? document.documentElement.scrollTop : document.body.scrollTop)
        + (document.documentElement.clientHeight != 0 ? document.documentElement.clientHeight : document.body.clientHeight);
    }
    maxX -= item.subMenu.offsetWidth;
    maxY -= item.subMenu.offsetHeight;
    
    if (x > maxX){
        x = Math.max(0, x - item.offsetWidth - item.subMenu.offsetWidth  + (menu.offsetWidth - item.offsetWidth));
        y = Math.max(0, Math.min(y, maxY));
    }
    // Position and show it.
    
    item.subMenu.style.left = x + "px";
    item.subMenu.style.top = y + "px";
    item.subMenu.style.visibility = "visible";
    
    // Stop the event from bubbling.
    
    if (browser.isIE){
        window.event.cancelBubble = true;
    }else{
        event.stopPropagation();
    }
}
// ------------------------------------------------------------------------------
function closeSubMenu(menu) {
    
    if (menu == null || menu.activeItem == null)
    return;
    
    // Recursively close any sub menus.
    
    if (menu.activeItem.subMenu != null) {
    closeSubMenu(menu.activeItem.subMenu);
    menu.activeItem.subMenu.style.visibility = "hidden";
    menu.activeItem.subMenu = null;
    }
    removeClassName(menu.activeItem, "menuItemHighlight");
    menu.activeItem = null;
}

// ------------------------------------------------------------------------------
// Code to initialize menus.

function menuInit(menu) {
    
    var itemList, spanList;
    var textEl, arrowEl;
    var itemWidth;
    var w, dw;
    var i, j;
    
    // For IE, replace arrow characters.
    
    if (browser.isIE) {
        menu.style.lineHeight = "2.5ex";
        spanList = menu.getElementsByTagName("SPAN");
        for (i = 0; i < spanList.length; i++)
        if (hasClassName(spanList[i], "menuItemArrow")) {
       	 spanList[i].style.fontFamily = "Webdings";
       	 spanList[i].firstChild.nodeValue = "4";
   		}
	}

	// Find the width of a menu item.
	
	itemList = menu.getElementsByTagName("A");
	if (itemList.length > 0){
		itemWidth = itemList[0].offsetWidth;
	}else{
		return;
	}
	// For items with arrows, add padding to item text to make the
	// arrows flush right.
	
	for (i = 0; i < itemList.length; i++) {
		spanList = itemList[i].getElementsByTagName("A");
		textEl = null;
		arrowEl = null;
		for (j = 0; j < spanList.length; j++) {
		if (hasClassName(spanList[j], "menuItemText")){
			textEl = spanList[j];
			}
		if (hasClassName(spanList[j], "menuItemArrow")){
			arrowEl = spanList[j];
			}
		}
		if (textEl != null && arrowEl != null){
		textEl.style.paddingRight = (itemWidth - (textEl.offsetWidth + arrowEl.offsetWidth)) + "px";
		}
	}
	
	// Fix IE hover problem by setting an explicit width on first item of
	// the menu.
	
	if (browser.isIE) {
		w = itemList[0].offsetWidth;
		itemList[0].style.width = w + "px";
		dw = itemList[0].offsetWidth - w;
		w -= dw;
		itemList[0].style.width = w + "px";
	}
	
	// Mark menu as initialized.
	
	menu.isInitialized = true;
}
// ------------------------------------------------------------------------------
// General utility functions.

    function getContainerWith(node, tagName, className) {
		
		// Starting with the given node, find the nearest containing element
		// with the specified tag name and style class.
		
		while (node != null) {
			if (node.tagName != null && node.tagName == tagName && hasClassName(node, className)){
				return node;
		}
		node = node.parentNode;
		}
		return node;
	}

// ------------------------------------------------------------------------------
    function hasClassName(el, name) {
		
		var i, list;
		
		// Return true if the given element currently has the given class
		// name.
		
		list = el.className.split(" ");
		for (i = 0; i < list.length; i++)
		if (list[i] == name){
			return true;
			}
		return false;
	}
// ------------------------------------------------------------------------------
	function removeClassName(el, name) {
		
		var i, curList, newList;
		
		if (el.className == null){
			return;
			}
		// Remove the given class name from the element's className property.
		
		newList = new Array();
		curList = el.className.split(" ");
		for (i = 0; i < curList.length; i++){
			if (curList[i] != name){
				newList.push(curList[i]);
				el.className = newList.join(" ");
			}
		}
	}
// ------------------------------------------------------------------------------
	function getPageOffsetLeft(el) {
	
	var x;
		
		// Return the x coordinate of an element relative to the page.
		
		x = el.offsetLeft;
		if (el.offsetParent != null)
			x += getPageOffsetLeft(el.offsetParent);
		
		return x;
	}
// ------------------------------------------------------------------------------
	function getPageOffsetTop(el) {
		
		var y;
		
		// Return the x coordinate of an element relative to the page.
		
		y = el.offsetTop;
		if (el.offsetParent != null){
			y += getPageOffsetTop(el.offsetParent);
		}
		return y;
	}

// ------------------------------------------------------------------------------
//
// Utilities
//
// ------------------------------------------------------------------------------
// Simple Javascript pop-up window function
// ------------------------------------------------------------------------------
function OpenWindow(url,name,width,height,style) {
	browsername=navigator.appName;
	
	var styledesc;
	switch(style) {
		case 'minimal':
			styledesc = ',directories=no,location=no,menubar=no,resizable=yes,scrollbars=yes,status=no,toolbar=no';
			break;
		default:
			styledesc = ',directories=no,location=yes,menubar=yes,resizable=yes,scrollbars=yes,status=no,toolbar=no';
			break;
	}
	
	popupWin = window.open(url, name, 'width=' + width + ',height=' + height + styledesc);
	
	if (popupWin.opener==null) popupWin.opener = window;
	
	popupWin.moveTo(0,0);
	popupWin.focus();
}
// ------------------------------------------------------------------------------
function setSplitHierarchicalSelect(oSelect, aTLID) {
	oSelect.options.length = 0;
	for(i=0;i<aTLID.length;i++) {
		oSelect.options[i] = aTLID[i];
	}
}
// ------------------------------------------------------------------------------