/* 
 * TREEVIEW ASSET MANAGER
 */
hXUL.AssetManager.treeViews = [];

hXUL.AssetManager.createTreeView = function(id, columnTitles, data, placeholder) {		
	var r = this.createTreeViewRenderer();
	var t = new hXUL.TreeView(id, columnTitles, this.dataTransformer(data), placeholder, r);			
	hXUL.AssetManager.treeViews.push(t);
	t.assetIndex = hXUL.AssetManager.treeViews.length - 1;
	r.assetIndex = hXUL.AssetManager.treeViews.length - 1;
	return t;	
}

hXUL.AssetManager.dataTransformer = function(data) {
	// You may override this function with a custom data transformation routine
	return data;
}

hXUL.AssetManager.createTreeViewRenderer = function() {
	if (hXUL.hasSupportForXUL()) {
		return new hXUL.TreeView.Renderer.XULRenderer();
	} else {
		return new hXUL.TreeView.Renderer.XHTMLRenderer();
	}
}

/* 
 * TREEVIEW CLASS
 */

hXUL.TreeView = function(id, columnTitles, data, placeholder, renderer) {	
	this.id        = id;
	this.element   = null;
	this.data	   = data;	
	this.columnTitles = columnTitles; 
	this._renderer = renderer;			
	this.setPlaceholder(placeholder);	
	this.onselect   = null;   // tree item selection event handler
	this.ondeselect = null;   // tree item de-selection event handler 
	this.onreorder  = null;   // post drag&drop event handler
	this.onexpand   = null;   // post open container event handler
	this.oncollapse = null;   // post close container event handler	
}

hXUL.TreeView.prototype.setPlaceholder = function(placeholder) {
	if(typeof placeholder == "string") 
		this.placeholder  = document.getElementById(placeholder); 
	else 
		this.placeholder  = placeholder;	
}

hXUL.TreeView.prototype.render = function(placeholder) {	
	
	// Placeholder can be set here, or whith the hXUL.AssetManager.createTreeView method
	if(placeholder)
		this.setPlaceholder(placeholder);
					
	// Render treeview
	this._renderer.render(this);
}

hXUL.TreeView.prototype.refresh = function(data) {
	if(data)
		this.data = hXUL.AssetManager.dataTransformer(data);	
	this.placeholder.innerHTML = "";
	this._renderer.render(this);
}

hXUL.TreeView.prototype.select = function(id, preventOnSelectEvent) {	
	return this._renderer.selectRow(id, preventOnSelectEvent);
}
hXUL.TreeView.prototype.getSelected = function() {	
	return this._renderer.getSelected();
}


/* 
 * TREEVIEW RENDERER 
 */

hXUL.TreeView.Renderer = function() {}

/* 
 * XUL TREEVIEW RENDERER
 */
  
hXUL.TreeView.Renderer.XULRenderer = function() {
	this.tree = null;	
	this.primaryColumnIndex = 0; /* Column with hierarchical data */	
}

hXUL.Class.extend(hXUL.TreeView.Renderer.XULRenderer, hXUL.TreeView.Renderer);

hXUL.TreeView.Renderer.XULRenderer.prototype.render = function(treeView) {
	if(!treeView.data || !treeView.data[0])
		throw new Error("Tree data not provided");

	var tree = this.createTreeElement(treeView.id);
	var treeCols = tree.appendChild(this.createTreeColsElement(treeView.id));
	for(var i=0;i < treeView.data[0].content.length; i++) {
		if(i>0)
			treeCols.appendChild(this.createTreeSplitterElement());
		treeCols.appendChild(this.createTreeColElement(treeView.id,i,treeView.columnTitles[i]));
	}
	var treeChildren = tree.appendChild(this.createTreeChildrenElement(treeView.id));	
	
	tree.setAttribute("rows",this.renderDataNodes(treeView.id, treeView.data, treeChildren));	
	tree.setAttribute("ondraggesture", "hXUL.AssetManager.treeViews["+this.assetIndex+"]._renderer.startDrag(event)");
	
	treeView.element = treeView.placeholder.appendChild(tree); 
	this.tree = treeView.element;
	
}

hXUL.TreeView.Renderer.XULRenderer.prototype.renderDataNodes = function(idPrefix, data, treeChildren, rowCount) {

	if(!rowCount) rowCount = 0;

	for(var i=0; i<data.length; i++) {
		var treeItem = treeChildren.appendChild(this.createTreeItemElement());
		var treeRow  = treeItem.appendChild(this.createTreeRowElement(rowCount));
		
		rowCount++;
		
		for(var j=0;j<data[i].content.length;j++) {
			treeRow.appendChild(this.createTreeCellElement(data[i].content[j],j));			
		}
		if(data[i].children) {
			treeItem.setAttribute("container","true");
			treeItem.setAttribute("open","true");
			var subTreeChildren = treeItem.appendChild(this.createTreeChildrenElement());
			rowCount = this.renderDataNodes(idPrefix, data[i].children, subTreeChildren, rowCount);
		} 
	}
	return rowCount;
}

hXUL.TreeView.Renderer.XULRenderer.prototype.createTreeElement = function(idPrefix) {	
	var tree = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","tree");	
	tree.id = idPrefix + "-tree";	
	tree.setAttribute("flex","1");	
	tree.setAttribute("hidecolumnpicker","true");	
	tree.setAttribute("seltype","single");		
	tree.className = "tree";
	return tree;
}

hXUL.TreeView.Renderer.XULRenderer.prototype.createTreeColsElement = function(idPrefix) {	
	var treeCols = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","treecols");	
	treeCols.id = idPrefix + "-treeCols";		
	return treeCols;
}

hXUL.TreeView.Renderer.XULRenderer.prototype.createTreeColElement = function(idPrefix, index, title) {	
	var treeCol = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","treecol");	
	treeCol.id = idPrefix + "-treeCol"+index;
	if(index==this.primaryColumnIndex) {
		treeCol.setAttribute("primary","true");	
		treeCol.setAttribute("flex","2");	
	} else
		treeCol.setAttribute("flex","1");
	if(title)
		treeCol.setAttribute("label",title);	
	treeCol.setAttribute("persist","width");	
	
	return treeCol;
}

hXUL.TreeView.Renderer.XULRenderer.prototype.createTreeSplitterElement = function() {	
	var splitter = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","splitter");	
	splitter.className = "tree-splitter";
	return splitter;
}	

hXUL.TreeView.Renderer.XULRenderer.prototype.createTreeChildrenElement = function(idPrefix) {	
	var treeChildren = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","treechildren");	
	if(idPrefix)
		treeChildren.id = idPrefix + "-treeChildren";		
	return treeChildren;
}

hXUL.TreeView.Renderer.XULRenderer.prototype.createTreeItemElement = function() {	
	var treeItem = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","treeitem");	
	return treeItem;
}

hXUL.TreeView.Renderer.XULRenderer.prototype.createTreeRowElement = function() {	
	var treeRow = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","treerow");	
	return treeRow;
}

hXUL.TreeView.Renderer.XULRenderer.prototype.createTreeCellElement = function(text) {	
	var treeCell = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","treecell");	
	treeCell.setAttribute("label",text);
	return treeCell;
}
/* 
 * XUL DRAG&DROP 
 */
hXUL.TreeView.Renderer.XULRenderer.prototype.startDrag = function(e) {
	this.dragPaused = false;
	
	var tree = e.target.parentNode; // e.target = treechildren node	
	if(!tree.boxObject.getRowAt)
		tree.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);
	var rowIndex = tree.boxObject.getRowAt(e.clientX, e.clientY);
	var item = this.getTreeItemElement(rowIndex);
	item.firstChild.setAttribute("properties","dragged");
	
	tree.style.cursor = "pointer";	
	tree.onmousemove = hXUL._aux.bind("drag",this);
	tree.onmouseup   = hXUL._aux.bind("dropDrag",this);
	tree.onmouseout  = hXUL._aux.bind(function(e){ 												
												var tg = e.target;
												if (tg.tagName != 'tree') return;
												var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
												while (reltg && reltg != tg && reltg.nodeName != 'BODY')
													reltg = reltg.parentNode
												if (reltg == tg) return;
												this.dropDrag();
												}
											 ,this);
	e.stopPropagation();
}

hXUL.TreeView.Renderer.XULRenderer.prototype.dropDrag = function(e) {
	this.dragPaused = false;
	if(this.tree.currentIndex != -1) {
		var item = this.getTreeItemElement(this.tree.currentIndex);
		item.firstChild.setAttribute("properties","");
		this.tree.onmousemove = null;
	}
}

hXUL.TreeView.Renderer.XULRenderer.prototype.drag = function(e) {

//	hoveredRow.style.backgroundColor = "#F00";
	if(!this.dragPaused) {
		var currentRow = this.tree.currentIndex;	
		if(currentRow==-1 && this.draggedToRowIndex) {
			this.tree.contentView.selection.select(this.draggedToRowIndex);
			currentRow = this.draggedToRowIndex;
		}
			
		var boxObject = this.tree.boxObject;
		//boxobject.QueryInterface(Components.interfaces.nsITreeBoxObject);
		if(!boxObject.getRowAt)
			boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);
		var rowIndex = boxObject.getRowAt(e.clientX, e.clientY);
		var row = this.getTreeItemElement(rowIndex);
		if(rowIndex!=-1 && rowIndex < currentRow) {
			this.moveSelectedUp();
		}
		else if(rowIndex > currentRow) {
			this.moveSelectedDown();
		}
	}
}

hXUL.TreeView.Renderer.XULRenderer.prototype.moveSelectedUp = function() {
	var rowIndex = this.tree.currentIndex;	
	if(rowIndex==-1)  
		return;

	var item = this.getTreeItemElement(rowIndex);	
	var targetItem = item.previousSibling;
	if(targetItem) {		
		if(targetItem.getAttribute("container")=="true" && targetItem.getAttribute("open")=="true") {	
			this.draggedToRowIndex = rowIndex;
			targetItem.getElementsByTagName("treechildren")[0].appendChild(item);
		} else {		
			this.draggedToRowIndex = rowIndex-1;	
			item.parentNode.insertBefore(item, targetItem);
		}
	} else {
		var p = item.parentNode.parentNode;
		if(p.getAttribute("container")=="true") {
			this.draggedToRowIndex = rowIndex-1;	
			p.parentNode.insertBefore(item, p);
			this.dragPaused = true;
			setTimeout( hXUL._aux.bind(function() { this.dragPaused = false },this),300)				
		}
	}
}

hXUL.TreeView.Renderer.XULRenderer.prototype.moveSelectedDown = function() {
	var rowIndex = this.tree.currentIndex;	
	if(rowIndex==-1)  
		return;
	
	var item = this.getTreeItemElement(rowIndex);		
	var targetItem = item.nextSibling;
	if(targetItem) {	
		if(targetItem.getAttribute("container")=="true" && targetItem.getAttribute("open")=="true" ) {	
			this.draggedToRowIndex = rowIndex+1;
			var childrenElement = targetItem.getElementsByTagName("treechildren")[0];
			childrenElement.insertBefore(item,childrenElement.firstChild);
		} else {	
			this.draggedToRowIndex = rowIndex+1;
			item.parentNode.insertBefore(targetItem, item);
		}
	} else {
		var p = item.parentNode.parentNode;
		if(p.getAttribute("container")=="true") {
			this.draggedToRowIndex = rowIndex;	
			p.parentNode.insertBefore(item, p.nextSibling);
			this.dragPaused = true;
			setTimeout( hXUL._aux.bind(function() { this.dragPaused = false },this),300)	
		}
	}
}

hXUL.TreeView.Renderer.XULRenderer.prototype.getTreeItemElement = function(index) {
	
	var items = this.tree.getElementsByTagName('treeitem');
	 for (var i=0; i<items.length; i++) {
        if (this.tree.contentView.getIndexOfItem(items[i]) == index) {
            return items[i];
        }
    }
	return null;
	
	// return treeView.element.view.getItemAtIndex(index); // would not work because of collapsed branches
}

hXUL.TreeView.Renderer.XULRenderer.prototype.getSelected = function() {
	return this.getTreeItemElement(this.tree.currentIndex);
}

/* 
 * XHTML RENDERER
 */

hXUL.TreeView.Renderer.XHTMLRenderer = function() {
	this.primaryColumnIndex = 0;     /* Column with hierarchical data */	
	this.setClassLevel      = false; /* set to true to add a class indicating the hierachical level for each row */
}

hXUL.Class.extend(hXUL.TreeView.Renderer.XHTMLRenderer, hXUL.TreeView.Renderer);

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.render = function(treeView) {

	this.selectedRow        = null;
	
	// Create tree element			
	var tree  = this.createTreeElement(treeView.id);
	var tbody = tree.firstChild; 
	
	// Add column headers (if any)
	if(treeView.columnTitles.length>0) {
		var treeCols = tbody.appendChild(this.createTreeColsElement(treeView.id));
		for(var i=0;i < treeView.data[0].content.length; i++) {
			treeCols.appendChild(this.createTreeColElement(treeView.id,i,treeView.columnTitles[i]));
		}		
	}
		
	// Add tree content (recursive loop)
	this.renderTreeElements(treeView.id, treeView.data, tbody);
		
	// Add tree footer	
	tbody.appendChild(this.createTreeFooterElement(treeView));
	
	// Insert tree in document
	treeView.element = treeView.placeholder.appendChild(tree); 	
	this.tree = treeView.element;	
	
	// Adjust indentation, alternate row class
	this.resetTreeLayout();
	
	// Get the top coordinate of the tree (used to determine the insert point in drag&drop)
	this._treeOffsetTop = hXUL._aux.getScreenCoordinates(this.tree).y;
	
	// Add event handler
	treeView.element.onmousedown = hXUL._aux.bind("mousedownHandler",this);
	treeView.element.onmouseup = hXUL._aux.bind("mouseupHandler",this);
	
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.renderTreeElements = function(idPrefix, data, container, rowCount, level) {

	if(!rowCount) rowCount = 0;
	if(!level) level = 0;
	
	for(var i=0; i<data.length; i++) {
		
		var isContainer = data[i].children?true:false;
		var treeRow = container.appendChild(this.createTreeRowElement(isContainer, data[i].rowClass, data[i].id));
		rowCount++;
		
		for(var j=0;j<data[i].content.length;j++) {
			treeRow.appendChild(this.createTreeCellElement(data[i].content[j], j, isContainer));					
		} 

		this.setLevel(treeRow,level);

		if(isContainer) {						
			rowCount = this.renderTreeElements(idPrefix, data[i].children, container, rowCount, level+1);
			// check if the initial state of the container is collapsed.
			if(data[i].collapse=="collapse") {
				// close container without a layout reset and firing the oncollapse event
				this.closeContainer(treeRow, true, true); 
			}
		} 
	}
	return rowCount;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.createTreeElement = function(idPrefix) {	
	var tree = document.createElement("table");	
	tree.id = idPrefix + "-tree";	
	tree.className = "tree";	
	var tbody = document.createElement("tbody");
	tree.appendChild(tbody);
	return tree;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.createTreeColsElement = function(idPrefix) {	
	var treeCols = document.createElement("tr");	
	treeCols.id = idPrefix + "-treeCols";		
	treeCols.className = "treecols";
	return treeCols;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.createTreeColElement = function(idPrefix, index, title) {	
	var treeCol = document.createElement("th");	
	treeCol.id = idPrefix + "-treeCol"+index;
	treeCol.className = "treecol";
	if(title)
		treeCol.appendChild(document.createTextNode(title));	
	return treeCol;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.createTreeRowElement = function(isContainer, rowClass ,rowId) {	
	var treeRow = document.createElement("tr");		
	treeRow.className = "treerow";	
	if(isContainer)
		treeRow.className += " container open";		
	if(rowClass) 
		treeRow.className += " " + rowClass;	
	if(rowId)
		treeRow.id = rowId;
	return treeRow;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.createTreeCellElement = function(text, colIndex, isContainer, idPrefix, rowIndex) {	
	var treeCell = document.createElement("td");	
	if(idPrefix && rowIndex && colIndex)
		treeCell.id = idPrefix + "-treeCell"+rowIndex+"-"+colIndex;	
	treeCell.className = "treecell";	
	
	treeCell.innerHTML = "<div class=\"content\">"+text+"</div>";
	
	if(colIndex == this.primaryColumnIndex) {
		treeCell.className += " primary";	
		
		var icon = document.createElement("div");
		icon.className = "icon";		
		treeCell.insertBefore(icon,treeCell.firstChild);
		
		if(isContainer) {			
			treeCell.insertBefore(this.createTwistieElement(),treeCell.firstChild);
		}		
		treeCell.insertBefore(this.createSpacersElement(),treeCell.firstChild);
	}
	//treeCell.appendChild(document.createTextNode(text));	
	
	return treeCell;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.createTwistieElement = function() {
	var twistie = document.createElement("div");
	twistie.className = "twistie";
	twistie.onmousedown = hXUL._aux.bind(this.toggleOpenState, this);
	twistie.onmouseup = function(e) { hXUL._aux.stopPropagation(e); };
	twistie.style.cursor = "pointer";
	return twistie;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.createTreeFooterElement = function(treeView) {
	var footer = document.createElement("tr");
	footer.className = "treefooter";
	for(var i=0;i < treeView.data[0].content.length; i++) {
		footer.appendChild(document.createElement("td"));
	}
	return footer;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.createSpacersElement = function() {
	var spacers = document.createElement("div");
	spacers.className = "spacers";
	return spacers;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.createSpacerElement = function(type) {
	var spacer = document.createElement("div");
	spacer.className = "spacer "+type;
	return spacer;
}

/*
 * XHTML OPEN/CLOSE TREE 
 */
 
hXUL.TreeView.Renderer.XHTMLRenderer.prototype.toggleOpenState = function(e) {	
	var twistie = hXUL._aux.getEventSource(e);	
	var rowElement = twistie.parentNode.parentNode;
	if(this.isContainerOpen(rowElement)) {
		this.closeContainer(rowElement);
	} else {
		this.openContainer(rowElement);
	}	
	this.preventSelectEvent   = true;
	this.preventDeselectEvent = true;
		
	hXUL._aux.stopPropagation(e); 
	return hXUL._aux.preventEvent(e);	
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.openContainer = function(container, preventLayoutReset, preventEventFiring) {
	if(!container) return;
		
	var rows = this.getChildrenRows(container); // rows is inversed
	for(var i=rows.length-1;i>=0;i--) {		
		this.showRow(rows[i]);
		if(this.isContainerClosed(rows[i])) {
			i-=this.getChildrenRows(rows[i]).length;
		}
	}
	container.className = container.className.replace(" closed", " open");	
	
	if(!preventLayoutReset)
		this.resetTreeLayout({alternateRows:true, startRow: container});
	
	if(!preventEventFiring)	{
		var treeview = hXUL.AssetManager.treeViews[this.assetIndex];
		if(treeview.onexpand) 
			treeview.onexpand(container);
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.closeContainer = function(container, preventLayoutReset, preventEventFiring) {	
	if(!container) return;
	
	var rows = this.getChildrenRows(container);
	for(var i=0;i<rows.length;i++)
		this.hideRow(rows[i]);
		
	container.className = container.className.replace(" open", " closed");
	
	if(!preventLayoutReset)
		this.resetTreeLayout({alternateRows:true, startRow: container});	
	
	if(!preventEventFiring)	{
		var treeview = hXUL.AssetManager.treeViews[this.assetIndex];
		if(treeview.oncollapse) 
			treeview.oncollapse(container);
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.isContainerOpen = function(container) {
	return hXUL._aux.hasClass(container,"open") && this.isContainer(container);
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.isContainerClosed = function(container) {
	return hXUL._aux.hasClass(container,"closed") && this.isContainer(container);
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.isContainer = function(row) {
	return hXUL._aux.hasClass(row,"container");
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.showRow = function(row) {
	try {
		row.style.display = "table-row";
	} catch(x) {
		row.style.display = "block";
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.hideRow = function(row) {
	row.style.display = "none";
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.getLevel = function(row) {
	if(!row || !row._level)
		return 0;
	return row._level;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.setLevel = function(row, level) {
	if(!row || row._level == level)
		return;
	
	// store new level
	row._level = level;		
	
	// set class
	if(this.setClassLevel) {
		var pattern = /level\d+/;
		var matches = row.className.match(pattern);
		if(matches && matches[0]) {
			row.className = row.className.replace(matches[0],"level"+level);
		} else {
			row.className += " level"+level;
		}	
	}	
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.setIndent = function(row) {
	// adjust indent and tree lines
	var primaryCell = row.childNodes[this.primaryColumnIndex];
	var level = row._level;
	var spacers = primaryCell.firstChild;	
	if(spacers) {
		for(var i=0;i<level;i++) {
			
			if(i==level-1)
				var type = this.hasNextSibling(row, i+1)?"branch":"last";
			else 
				var type = this.hasNextSibling(row, i+1)?"line":"";
				
			if(spacers.childNodes[i]) {
				// make sure the spacer is of the right type.
				var spacer = spacers.childNodes[i];
				spacer.className = "spacer "+type;
			} else {
				// create spacer
				var spacer = spacers.appendChild(this.createSpacerElement(type));
			}	
			// Adjust spacer height to match row height (which may vary based on content)
			var h = spacers.parentNode.parentNode.offsetHeight;
			if(h>0) // h may equal zero if the row is collapsed (visibility = none)
				spacer.style.height =  h + "px";	
		}
		while(spacers.childNodes[i]) {
			// delete extra spacers
			spacers.removeChild(spacers.childNodes[i]);
		}	
	}	
}

/* 
 * XHTML DRAG&DROP 
 */
 
hXUL.TreeView.Renderer.XHTMLRenderer.prototype.mousedownHandler = function(e) {	
	if(!e) e=window.event;
	var target =  e.target || e.srcElement;
	while(target && target.tagName!='TR') {
		target = target.parentNode;
	}
	if(target) {
		this.cleanDragged();
		this._clickedRow = target;
		var mouse = hXUL._aux.getMouseCoordinates(e);	
		this._dragGestureY = mouse.y;
		this.tree.onmousemove = hXUL._aux.bind("checkDragGesture",this);
		document.body.onselectstart = function(e) { 
			hXUL._aux.stopPropagation(e); 
			return hXUL._aux.preventEvent(e); 
		};
		document.body.ondrag = function(e) { 
			hXUL._aux.stopPropagation(e); 
			return hXUL._aux.preventEvent(e); 
		};
	}
	hXUL._aux.stopPropagation(e); 
	return hXUL._aux.preventEvent(e); 	
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.mouseupHandler = function(e) {
	var isSelected = this.toggleRowSelection(this._clickedRow);	
	this.tree.onmousemove = null;
	document.body.ondrag  = null;
	document.body.onselectstart = null;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.checkDragGesture = function(e) {
	var mouse = hXUL._aux.getMouseCoordinates(e);	
	var difY = this._dragGestureY - mouse.y;
	if(difY > 4 || difY < -4)
		this.startDrag(e, this._clickedRow);
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.startDrag = function(e, row) {
	
	if(this.isDraggable(row)) {		
		if(!e) e=window.event;
		
		this.tree.onmouseup   = hXUL._aux.bind("dropDrag",this);
		document.onkeypress   = hXUL._aux.bind("resetDrag",this);	
		this.tree.onmousemove = hXUL._aux.bind("drag",this);
		this.tree.onmouseover = hXUL._aux.bind("dragOver",this);
		this.tree.onmouseout  = hXUL._aux.bind(function(e){ 		
			if (!e) var e = window.event;
			var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
			p = this.tree.parentNode;
			while(p && p!=reltg) {
				 p = p.parentNode;
			}
			if(p) 
				this.resetDrag();	
			}
		 ,this);
					
		this.tree.style.cursor = "pointer";	
		this._clickedRow.className += " dragged";		
		if(this.isContainer(this._clickedRow)) {
			var rows = this.getChildrenRows(this._clickedRow);
			for(var i=0;i<rows.length;i++) {
				rows[i].className += " dragged";
			}
		}
		this._insertType = "insertAfter";
		
		// dragged ghost icon
		var divs = this._clickedRow.firstChild.getElementsByTagName("div");
		for (var i=0;i<divs.length;i++) {
			if(divs[i].className == 'content') {
				var b = document.body;
				var g = divs[i].cloneNode(true);
				g.className = "dragGhost";
				this._dragGhost = b.appendChild(g);										
				break;
			}
		}		
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.dropDrag = function() {
	if(this._insertPoint && this._clickedRow) {
		this.moveDraggedTo(this._insertPoint, this._insertType);
		// run onreorder event handler
		var treeview = hXUL.AssetManager.treeViews[this.assetIndex];
		if(treeview.onreorder) {
			treeview.onreorder(this._clickedRow, this._insertPoint, this._insertType, this.getChildrenRows(this._clickedRow));
		}
		this.resetDrag(true);
	} else {
		this.resetDrag();	
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.resetDrag = function(wasDropped) {

	this.tree.onmouseup = hXUL._aux.bind("mouseupHandler",this);
	this.tree.onmousemove = null;	
	this.tree.onmouseover = null;
	this.tree.onmouseout  = null;	
	document.onkeypress   = null;
	document.body.ondrag  = null;
	document.body.onselectstart = null;
	this.tree.style.cursor = "default";
	
	if(this._dragGhost) {
		this._dragGhost.parentNode.removeChild(this._dragGhost);
		this._dragGhost = null;
	}
	if(this._insertPoint) {
		this._insertPoint.className = this._insertPoint.className.replace(" "+this._insertType,"");	
		this._insertPoint = null;
	}
	this._cleanRow = this._clickedRow;
	this._clickedRow = null;
	if(this._cleanRow && wasDropped) {
		this._timeout = setTimeout(hXUL._aux.bind("cleanDragged",this), 2000);
	} else 
		this.cleanDragged();
		
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.cleanDragged = function() { 		
	if(this._cleanRow) {	
		if(this._timeout) {
			clearTimeout(this._timeout);
			this._timeout = null;			
		}
		this._cleanRow.className = this._cleanRow.className.replace(" dragged","");
		
		if(this.isContainer(this._cleanRow)) {
			var rows = this.getChildrenRows(this._cleanRow);
			for(var i=0;i<rows.length;i++) {
				rows[i].className = rows[i].className.replace(" dragged","");
			}
		}			
		this._cleanRow = null;
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.drag = function(e) {

	var mouse = hXUL._aux.getMouseCoordinates(e);	 	

	if(this._dragGhost) {		
		this._dragGhost.style.top  = mouse.y + "px";
		this._dragGhost.style.left = mouse.x + "px";	
	}
	if(this._insertPoint) {
		if(mouse.y > this._midPoint) {
			if(this.isContainer(this._insertPoint) ) {
				this._insertType = "insertInside";
			} else {
				this._insertType = "insertAfter";
			}
		} else if(mouse.y <= this._midPoint) { 
			this._insertType = "insertBefore";
		}	
		if(this._insertType != this._previousInsertType) {
			this._insertPoint.className = this._insertPoint.className.replace(" insertInside","");
			this._insertPoint.className = this._insertPoint.className.replace(" insertAfter","");
			this._insertPoint.className = this._insertPoint.className.replace(" insertBefore","");
			this._insertPoint.className += " " + this._insertType;	
			this._previousInsertType = this._insertType;
		}
			
		// set timer to open the container.	
		if(this._insertType == "insertInside" && this.isContainerClosed(this._insertPoint) ) {
			if(!this._openContainerTimer) {
				this._openContainerTimer = setTimeout(hXUL._aux.bind(function() { 
					this.openContainer(this._insertPoint);  			
				},this), 1200);
			}
			return;
		} 
		else {
			if(this._openContainerTimer) {
				clearTimeout(this._openContainerTimer);
				this._openContainerTimer = null;
			}
		}
	} 	
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.dragOver = function(e) {	
	
	if(!e) e=window.event;
	
	var target =  e.target || e.srcElement;
	while(target && target.tagName!='TR') {
		target = target.parentNode;
	}
		
	if(this.isDraggedRow(target) || !this.isDroppable(target)) 
		return;			
	
	if(target!=this._insertPoint) {
		if(this._insertPoint) {
			this._insertPoint.className = this._insertPoint.className.replace(" insertInside","");
			this._insertPoint.className = this._insertPoint.className.replace(" insertAfter","");
			this._insertPoint.className = this._insertPoint.className.replace(" insertBefore","");
		
			if(this._openContainerTimer) {
				clearTimeout(this._openContainerTimer);
				this._openContainerTimer = null;
			}
		}
		this._insertPoint = target;
		this._midPoint = this._treeOffsetTop+target.offsetTop+target.offsetHeight/2;	
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.moveDraggedTo = function(insertRow, insertType) {
	var rows = this.getChildrenRows(this._clickedRow);
	var currentLevel = this.getLevel(this._clickedRow);
	var targetLevel = this.getLevel(insertRow);
	var levelAdjustment = targetLevel - currentLevel;
	var oldSibling = this._clickedRow.previousSibling;

	if(insertType=="insertBefore")
		this._clickedRow = insertRow.parentNode.insertBefore(this._clickedRow, insertRow);
	else {
		if(this.isContainer(insertRow) && insertType=="insertInside") {
			targetLevel++;
			levelAdjustment++;
			// insert after container's children
			var children = this.getChildrenRows(insertRow);
			if(children[0])
				insertRow = children[0];
		}
		this._clickedRow = insertRow.parentNode.insertBefore(this._clickedRow, insertRow.nextSibling);
	}
	
	this.setLevel(this._clickedRow, targetLevel);			
	for(var i=0;i<rows.length;i++) {
		var targetLevel = this.getLevel(rows[i]) + levelAdjustment;
		var row = this._clickedRow.parentNode.insertBefore(rows[i],this._clickedRow.nextSibling);			
		this.setLevel(row, targetLevel);	
	}
	// Get the higher in the tree of the 2: oldSibling or clickedRow
	if (oldSibling.offsetTop < this._clickedRow.offsetTop) {
		var resetFromRow  = oldSibling;	
		while(resetFromRow && this.getLevel(resetFromRow)>=currentLevel) {
			resetFromRow = resetFromRow.previousSibling;
		}
		var resetUntilRow = rows[0] || this._clickedRow;		
	} else {
		var resetFromRow  = this._clickedRow;
		var resetUntilRow = oldSibling;
	}
	
	// Reset the indent and alternate rows between the origin and the destination
	this.resetTreeLayout({indent: true, alternateRows: true, startRow: resetFromRow, endRow: resetUntilRow});
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.toggleRowSelection = function(row) {
	if(row == this.selectedRow) {
		this.deselectRow();
		return false;
	} else {		
		this.selectRow(row);
		return true;
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.selectRow = function(row, preventOnSelectEvent) {
	
	if(typeof row == "string") {
		// assume id was given.
		row = document.getElementById(row);
	}
	
	if(!this.isSelectable(row)) {
		return false;
	}
		
	this.deselectRow();
	this.selectedRow = row;
	
	if(this.selectedRow) 
		this.selectedRow.className += " selected";
	
	// run onselect event handler
	var treeview = hXUL.AssetManager.treeViews[this.assetIndex];
	if(treeview.onselect && !preventOnSelectEvent) {
		// Set a timeout to decouple the onselect function (tree feels more responsive this way)
		setTimeout(hXUL._aux.bind( function() { this.onselect(this._renderer.selectedRow);	}, treeview), 1);
		//treeview.onselect(this.selectedRow);	
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.deselectRow = function() {	
	if(this.selectedRow) {
		this.selectedRow.className = this.selectedRow.className.replace(" selected","");
		// run ondeselect event handler		
		var treeview = hXUL.AssetManager.treeViews[this.assetIndex];
		if(treeview.ondeselect) {
			// Set a timeout to decouple the ondeselect function (tree feels more responsive this way)			
			setTimeout(hXUL._aux.bind( function() {	this.ondeselect(this._renderer.selectedRow); }, treeview), 1);
			//treeview.ondeselect(this.selectedRow);	
		}
		this.selectedRow = null;
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.getSelected = function() {
	return this.selectedRow;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.isSelectable = function(row) {
	return row && !hXUL._aux.hasClass(row,"inert");
}	

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.resetTreeLayout = function(filter) {
	
	if(filter && filter.startRow)
		var row = filter.startRow;
	else
		var row = this.tree.firstChild.firstChild;
	
	if(filter && filter.endRow)
		var end = filter.endRow.nextSibling;
	else
		var end = this.tree.firstChild.lastChild;
	
	var i = 0;
	if(row.previousSibling && hXUL._aux.hasClass(row.previousSibling,"odd"))
		var startEven = 0;
	else
		var startEven = 1;
		
	while(row && row!=end ) {
		if(row.style.display!="none")
			i++;		
		if(!filter || filter.indent==true) {	
			this.setIndent(row);	
		}
		if(!filter || filter.alternateRows==true) {
			if(i%2==startEven) {
				if(!hXUL._aux.hasClass(row,"odd"))
					row.className += " odd";
			} else {
				if(hXUL._aux.hasClass(row,"odd"))
					row.className = row.className.replace(" odd","");
			}
		}
		row = row.nextSibling;
	}
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.getChildrenRows = function(container) {
	if(!container) return null;
	
	var parentLevel = this.getLevel(container);
	var rows = [];
	var row = container.nextSibling;
	while(row) {
		var level = this.getLevel(row);
		if(level > parentLevel) {
			rows.unshift(row);
			row = row.nextSibling;
		} else 
			row = null;
	}
	return rows;
}
 
hXUL.TreeView.Renderer.XHTMLRenderer.prototype.hasNextSibling = function(row, currentLevel) {
	if(!row)
		return false;
		
	if(!currentLevel)
		currentLevel = this.getLevel(row);
		
	row = row.nextSibling;
	while(row) {
		var lvl = this.getLevel(row);
		if(lvl == currentLevel) {
			return true;
		}
		if(lvl < currentLevel) {					
			return false;
		}
		row = row.nextSibling;
	}
	return false;
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.isDraggedRow = function(row) {
	return hXUL._aux.hasClass(row,"dragged");	
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.isDraggable = function(row) {	
	return row && !hXUL._aux.hasClass(row,"anchored") && !hXUL._aux.hasClass(row,"inert");
}

hXUL.TreeView.Renderer.XHTMLRenderer.prototype.isDroppable = function(row) {	
	return row && !hXUL._aux.hasClass(row,"undroppable"); 	
}
