

function Tree (oDiv, fLoadParams, sTreeVarName) {
	this.oDiv_ = oDiv;
	this.oChilds_ = new Array();
	this.fLoadParams_ = fLoadParams;
	this.oTree_ = this;
	this.oNodeSel_ = null;
	this.sTreeVarName_ = sTreeVarName;
	this.iExpandLevel_ = 1;
	this.fSelPredicate = null;
	this.fSelListener = null;
	this.iFullExpLimit = 60;
	this.sFilter_ = null;
	this.sAutoSelMode_ = 'e';
	this.bLoading_ = false;
	this.bPostLoad_ = false;
	this.bDirectClick_ = false;
	this.fDblClick_ = null;
}

Tree.debug = false;

Tree.prototype.clear = function () {
	while (this.oChilds_.length > 0) {
		var oNode = this.oChilds_.pop();
		oNode.oDiv_.parentNode.removeChild (oNode.oDiv_);
	}
	this.oNodeSel_ = null;
}

Tree.prototype.setExpandLevel = function (iNumLevels) {
	this.iExpandLevel_ = iNumLevels;
}

Tree.prototype.setFullExpLimit = function (iNumNodes) {
	this.iFullExpLimit = iNumNodes;
}

Tree.prototype.selectOnlyLeafs = function () {
	this.fSelPredicate = function (oNode) {
		return oNode.bLeaf_;
	}
}

Tree.prototype.setAutoSelMode = function (sWhat) {
	this.sAutoSelMode_ = sWhat;
}

Tree.prototype.setSelListener = function (fListener) {
	this.fSelListener = fListener;
}

Tree.prototype.setDblClickListener = function (fListener) {
	this.fDblClick_ = fListener;
}

Tree.prototype.setDirectClick = function (bWhat) {
	this.bDirectClick_ = bWhat;
}


Tree.prototype.load = function (oNode) {
	if (this.bLoading_) {
		if (!oNode) this.bPostLoad_ = true;
		return;
	} else {
		this.bLoading_ = true;
		this.bPostLoad_ = false;
	}
	//if (!oNode) this.clear();
	var oThis = this;
	var oParams = this.fLoadParams_();
	if (oParams.filter) this.sFilter_ = oParams.filter;
	else this.sFilter_ = null;
	if (!Tree.debug) DWREngine.setErrorHandler(null);
	var oFilter = oParams.filter ? oParams.filter : null;
	DWREngine._execute('/jv/x/dwr', 'DwrFac', 'domTree', 
	    oParams.tk, this.sTreeVarName_, 
	    oNode ? oNode.sId_ : "root", 
	    oParams.tag ? oParams.tag : null, 
	    oFilter, 
	    { callback: function(oRes){loadCallback(oRes,oThis,oFilter);}, 
	      verb: "GET",
	      timeout: 10000,
	      errorHandler: function(oRes){errorCallback(oRes,oThis);}
	    });
}

function errorCallback (oRes, oTree) {
	oTree.bLoading_ = false;
}

function loadCallback (oRes, oTree, oFilterAtCall) {
	oTree.bLoading_ = false;
	//if (Tree.debug) alert (oRes);
	if (!oRes || typeof oRes != "string") return;
	var p = new TreeParser (oRes);
	var oDom;
	try {
		oDom = p.parse();
	} catch (x) {
	    if (Tree.debug) alert(x);
	}
	if (!oDom) return;
	var sTreeNode = oDom;
	var idNode = sTreeNode["node"];
	if (!idNode) return;
	if (idNode=="root") {
		if (oFilterAtCall != oTree.sFilter_) {
			return;
		}
	}
	var tree = oTree;
	var toExtend = findNode (tree, idNode);
	if (!toExtend) return;
	if (idNode=="root") tree.clear();
	for (var i=0; i<sTreeNode.childNodes.length; i++) {
		var domNode = sTreeNode.childNodes[i];
		createChild (toExtend, domNode);
	}
	if (idNode=="root") { 
	    var levels = tree.iExpandLevel_;
		if (treeWeight(toExtend) <= tree.iFullExpLimit) levels = 5;
		expandNodes (toExtend, levels, 0);
		if (tree.sFilter_) tree.selectNode (tree.sFilter_);
	}
	if (oTree.bPostLoad_) oTree.load();
}

function createChild (oParentNode, oDomEle) {
	var oChildNode = new TNode (oParentNode, oDomEle["i"], oDomEle["t"], oDomEle["l"]=="1", false);
	for (var i=0; i<oDomEle.childNodes.length; i++) {
		createChild (oChildNode, oDomEle.childNodes[i]);
	}
}

Tree.prototype.selectNode = function (sNode) {
	var aNodes = new Array();
	var oNode = findNodes (this, 
		function (oNode2) {
			if (!oNode2.isSelectable()) return false;
			if (oNode2.oTree_.sAutoSelMode_ == 'e') {
				return oNode2.sTxt_.toLowerCase() == sNode.toLowerCase();
			} else {
				return oNode2.sTxt_.toLowerCase().indexOf(sNode.toLowerCase()) != -1;
			}
		},
		function (oNode2) {
			return oNode2.bExpanded_;
		},
		aNodes
	);
	if (aNodes.length==1) aNodes[0].setSel(true);
}

function findNode (oTN, sId) {
	if (sId=="root" && oTN instanceof Tree) return oTN;
	if (oTN instanceof TNode && oTN.sId_ == sId) return oTN;
	for (var i=0; i<oTN.oChilds_.length; i++) {
		var oNode = findNode (oTN.oChilds_[i], sId);
		if (oNode) return oNode;
	}
	return null;
}

function findNodes (oTN, fAcceptPred, fDescendPred, aRes) {
	if (oTN instanceof TNode && fAcceptPred(oTN)) aRes.push(oTN);
	if (oTN instanceof Tree || fDescendPred(oTN)) {
		for (var i=0; i<oTN.oChilds_.length; i++) {
			findNodes (oTN.oChilds_[i], fAcceptPred, fDescendPred, aRes);
		}
	}
}

function expandNodes (oTN, iNumLevels, iCurrentLevel) {
	if (iCurrentLevel > iNumLevels) return;
	if (oTN instanceof TNode) {
		if (!oTN.isLoaded()) return;
	    oTN.setExpanded(true);
    }
	for (var i=0; i<oTN.oChilds_.length; i++) {
		expandNodes (oTN.oChilds_[i], iNumLevels, iCurrentLevel+1);
	}
}

function treeWeight (oTN) {
	var iWeight = oTN instanceof TNode ? 1 : 0;
	for (var i=0; i<oTN.oChilds_.length; i++) {
		iWeight += treeWeight (oTN.oChilds_[i]);
	}
	return iWeight;
}

function TNode (oParent, sId, sTxt, bLeaf, bExpanded) {
	this.oParent_ = oParent;
	this.sId_ = sId;
	this.sTxt_ = sTxt;
	this.bLeaf_ = bLeaf;
	this.oTree_ = oParent.oTree_;
	this.bExpanded_ = bExpanded;
	this.bSel_ = false;
	this.oChilds_ = new Array();
	oParent.oChilds_.push(this);
	
	this.oDiv_ = document.createElement("div");
	this.oDiv_.className = "node";
	if (oParent instanceof Tree) {
	    this.oParent_.oDiv_.appendChild (this.oDiv_);	
    } else {
        this.oParent_.oDivC_.appendChild (this.oDiv_);
    }
    this.oDiv_.tnode_ = this;
	
	this.oL_ = document.createElement("table");
	this.oL_.cellSpacing = "0";
	this.oL_.cellPadding = "0";
	var tbody = document.createElement("tbody");
	this.oL_.appendChild (tbody);
	var tr = document.createElement("tr");
	tbody.appendChild (tr);

	var td = document.createElement("td");
	tr.appendChild (td);
	this.oImg1_ = document.createElement("div");
	td.appendChild (this.oImg1_);

	td = document.createElement("td");
	tr.appendChild (td);
	this.oImg2_ = document.createElement("div");
	td.appendChild (this.oImg2_);
	
	this.oTdText_ = document.createElement("td");
	td = this.oTdText_;
	tr.appendChild (td);
	td.className = "nodeText";
	td.appendChild (document.createTextNode (sTxt));
	if (this.oTree_.bDirectClick_) td.style.cursor = "pointer";
	
	this.oDiv_.appendChild (this.oL_);
	
	if (!bLeaf) {
		this.oDivC_ = document.createElement("div");
		this.oDivC_.className = "conti";
		this.oDiv_.appendChild (this.oDivC_);
    }
	
	this.getImg2().className = bLeaf ? "iskill" : "ifolder";
	var img1 = this.getImg1();
	if (bLeaf) { 
	 	img1.style.visibility = "hidden";
	} else {
		this.setExpanded (bExpanded);
	}
	img1.onclick = onclickImg1;
	this.oImg2_.onclick = onclickLDiv;
	this.oTdText_.onclick = onclickLDiv;
	if (!this.oTree_.bDirectClick_) this.oTdText_.ondblclick = ondblclickLDiv;
}

TNode.prototype.toString = function () {
	return "TNode " + this.sId_;
}

TNode.prototype.getImg1 = function () {
	return this.oImg1_;
}

TNode.prototype.getImg2 = function () {
	return this.oImg2_;
}

TNode.prototype.setExpanded = function (bWhat) {
	this.bExpanded_ = bWhat;
	this.getImg1().className = bWhat ? "iminus" : "iplus";
	if (this.oDivC_) this.oDivC_.style.display = bWhat ? "block" : "none";
}

TNode.prototype.isLoaded = function () {
	return this.bLeaf_ || this.oChilds_.length > 0;
}

TNode.prototype.isSelectable = function () {
	var fSelP = this.oTree_.fSelPredicate;
	return !fSelP || fSelP(this);
}

TNode.prototype.setSel = function (bWhat) {
	if (bWhat && !this.isSelectable()) return;
    if (bWhat && this.oTree_.oNodeSel_) this.oTree_.oNodeSel_.setSel (false);
    if (bWhat) {
        if (!this.oTree_.bDirectClick_) this.oL_.style.backgroundColor = "#d5d5d5";
        this.oTree_.oNodeSel_ = this;
        if (this.oTree_.fSelListener) this.oTree_.fSelListener (this.sId_, this.sTxt_);
    } else {
        this.oL_.style.backgroundColor = "";
        this.oTree_.oNodeSel_ = null;
    }
    this.bSel_ = bWhat;
}

onclickImg1 = function (oEvt) {
    var oEvent = oEvt;
    if (!oEvt) oEvent = window.event;
    if (oEvt) {
        if (oEvt.cancelBubble) oEvt.cancelBubble = true;
        if (oEvt.stopPropagation) oEvt.stopPropagation();
    }
    var oEnclosingDiv = findDomNodeParent (this.parentNode, "div");
    var oNode = oEnclosingDiv.tnode_;
    oNode.setExpanded (!oNode.bExpanded_);
    if (oNode.bExpanded_ && !oNode.bLeaf_ && oNode.oChilds_.length == 0) {
    		oNode.oTree_.load (oNode);
    }
}

onclickLDiv = function () {
    var oEnclosingDiv = findDomNodeParent (this.parentNode, "div");
    var oNode = oEnclosingDiv.tnode_;
    oNode.setSel (true);
    if (oNode.oTree_.bDirectClick_ && oNode.oTree_.fDblClick_) {
    	oNode.oTree_.fDblClick_ (oNode.sId_, oNode.sTxt_);
    }
}

ondblclickLDiv = function () {
    var oEnclosingDiv = findDomNodeParent (this.parentNode, "div");
    var oNode = oEnclosingDiv.tnode_;
    if (oNode && oNode.oTree_.fDblClick_) {
    	oNode.oTree_.fDblClick_ (oNode.sId_, oNode.sTxt_);
    }
}

function TreeParser (sIn) {
	this.lex = new Lexer (sIn);
}

TreeParser.prototype.parse = function () {
	var oNode = new Object();
	oNode.childNodes = [];
	var l = this.lex;
	if (l.nextTok() != Lexer.CHAR || l.consume() != '<') throw "< expected";
	var t = l.nextTok();
	while (t==Lexer.WORD) {
		var name = l.consume();
		if (l.nextTok() != Lexer.CHAR || l.consume() != '=') throw "= expected";
		if (l.nextTok() != Lexer.QSTRING) throw "QString expected";
		oNode[name] = l.consume();
		t = l.nextTok();
	}
	while (t==Lexer.CHAR && l.val == '<') {
		oNode.childNodes.push (this.parse());
		t = l.nextTok();
	}
	if (l.nextTok() != Lexer.CHAR || l.consume() != '>') throw "> expected";
	return oNode;
}

function Lexer (sIn) {
	this.s = sIn;
	this.len = sIn.length;
	this.val = "";
	this.act = 0;
	this.last = 0;
}

Lexer.prototype.nextTok = function () {
	this.act = this.last;
	var sMatch;
	while (this.act < this.len && (this.s.charAt(this.act) == ' ')) this.act++;
	if (this.act >= this.len) return Lexer.NONE;
	if (this.s.charAt(this.act) == '"') {
		var o2 = this.s.indexOf('"', this.act+1);
    	if (o2 >= 0) {
	  		this.val = this.unescape(this.s.substring(this.act+1, o2));
	  		this.act = o2+1;
			return Lexer.QSTRING;
    	}
	}
	var sub = this.s.substring(this.act, this.act+20);
	var match = sub.match(/^\w+/);
	if (match) {
		this.val = match[0];
		this.act = this.act + match[0].length;
		return Lexer.WORD;
	}
	this.val = this.s.charAt(this.act);
	this.act++;
	return Lexer.CHAR;
}

Lexer.prototype.unescape = function (s) {
	s = s.replace(/&q/g, '"');
	s = s.replace(/&a/g, '&');
	return s;
}

Lexer.prototype.consume = function () {
	this.last = this.act;
	return this.val;
}

Lexer.prototype.allTokens = function () {
	sRes = "";
	while(true){
		oTok = this.nextTok();
		if (oTok == Lexer.NONE) break;
		sRes += oTok + ":"+this.consume() + "; ";
	}
	return sRes;
}

Lexer.QSTRING = "Q";
Lexer.WORD = "W";
Lexer.CHAR = "C";
Lexer.NONE = "N";








