var fastTreeConfig = {
	persist       : false,
    loadingText   : "Loading...",
    loadErrorText : "Error loading",
    emptyNodeText : "Does not contain any tree items",
    addTooltip    : "Add item at this level",
    editTooltip   : "Indicators",
    deleteTooltip : "Delete",
    fillTooltip   : "Fill",
    checkTooltip  : "Check",
    oneSignedTooltip:"one signed",
    isEnableDrag  : true,
    setNodeValue  : function(oNode) {
        var oldValue = oNode.firstChild.getAttribute("oldvalue");
        oNode.innerHTML = oldValue.indexOf("<a") == 0 ?
                oldValue.substr(0, oldValue.indexOf(">")+1) + oNode.firstChild.value + "</a>" : oNode.firstChild.value;
    },
    resetEdited   : function(oNode) { oNode.innerHTML = oNode.firstChild.getAttribute("oldvalue"); },
    createEditor  : function(oNode) {
        var childNode = getNonEmptyNode(oNode.firstChild);
        oNode.innerHTML = "<input type='text' value='"+(childNode && childNode.tagName.toLowerCase() == "a" ? childNode.innerHTML : oNode.innerHTML)+"' oldvalue='"+oNode.innerHTML+"' onkeypress='return inputKeyPressed(event, \""+oNode.getAttribute("id")+"\");' class='treeEditName'/>";
        oNode.firstChild.focus();
    },
    moveNode      : function(movedId, beforeId, afterId) {
        var movedItems = document.getElementById("movedItems");
        if (!movedItems) {
            movedItems = document.createElement("input");
            document.appendChild(movedItems);
        }
        movedItems.value = (movedItems.value.length > 0 ? movedItems.value + ';' : '') +
                           movedId + (beforeId ? '<' + beforeId : '>' + afterId);
    },
    deleteNode    : function(nodeId) {
        var deletedItems = document.getElementById("deletedItems");
        if (!deletedItems) {
            deletedItems = document.createElement("input");
            document.appendChild(deletedItems);
        }
        deletedItems.value = (deletedItems.value.length > 0 ? deletedItems.value + ';' : '') + nodeId;
    },
    onLoad : function(oNode) {}
};

var fastTreeHandler = {
    treeCounter : 0,
    treePrefix  : "fastTree",
    opened      : new CookiesPersister(),
    getTreeId   : function() { return this.treePrefix + this.treeCounter++; }
};

var fastTreeEditedId = null;
var mouseOffset = null;
var startPos = null;
var draggedNode = null;
var dragNodeId = null;
var dragNodeTable = null;
var dndNodeIndex = null;
var dndObject = null;
var dndDelimiter = null;
var dndTargetsContainer = null;
var possibleTargets = null;

/*
 * FastTree class
 */

function FastTree(sText, sTreeStateId, extandeable, deepExtendable, container, onclickHandler) {
    this.id = fastTreeHandler.getTreeId();
    this.treeStateId = sTreeStateId;
    this.text = sText;

    var html = [];
    html[html.length] = "<div id='";
    html[html.length] = this.id;
    if (this.treeStateId) {
        this.treeState = document.getElementById(this.treeStateId);
        html[html.length] = "' stateId='";
        html[html.length] = this.treeStateId;
    }
    html[html.length] = "' class='fastTree'><table class='fastTreeNode'><tr><td class='fastTreePlus' style='display: none;' id='toggler";
    html[html.length] = this.id;
    html[html.length] = "'></td><td class='fastTreeIconI'><div class='fastTreeOpenFolder'>&nbsp;</div></td><td class='fastTreeRootItem' id='";
    html[html.length] = this.id;
    html[html.length] = "Root";
    if (onclickHandler) {
        html[html.length] = "' style='cursor: pointer;' onclick='";
        html[html.length] = onclickHandler;
    }
    html[html.length] = "'>";
    html[html.length] = this.text;
    html[html.length] = "</td>";
    if (extandeable) {
        html[html.length] = "<td onclick='addNode(this, \"";
        html[html.length] = this.id;
        html[html.length] = "\");' title='";
        html[html.length] = fastTreeConfig.addTooltip;
        html[html.length] = "' id='add";
        html[html.length] = this.id;
        if (deepExtendable) {
            html[html.length] = "' deepextendable='true";
        }
        html[html.length] = "' class='fastTreeAddButton'><div class='fastTreeBlank'/></td>";
    }
    html[html.length] = "</tr></table>";

    if (this.treeState) {
        // restore tree state on body onload
        html[html.length] = "<div>";
        html[html.length] = fastTreeConfig.loadingText;
        html[html.length] = "</div>";
        var tree = this;
        if (window.addEventListener) // W3C standard
            window.addEventListener('load', function() {tree.renderingOnLoad();}, false);
        else if (window.attachEvent) // Microsoft
            window.attachEvent('onload', function() {tree.renderingOnLoad();});
    }
    html[html.length] = "</div>";
    if (container)
        container.innerHTML = container.innerHTML+html.join('');
    else
        document.write(html.join(''));

    if (document.addEventListener) // W3C standard
        document.addEventListener("click", fastTreeCheckBlur, false);
    else if (document.attachEvent) // Microsoft
        document.attachEvent("onclick", fastTreeCheckBlur);
}

FastTree.prototype.setXMLString = function(sXmlString) {
    if (this.treeState)
        this.xmlString = sXmlString;
    else {
        document.getElementById(this.id).appendChild(document.createElement("div"));
        xmlFileLoaded(getXMLObject(sXmlString), getNonEmptyNode(document.getElementById(this.id).firstChild), false);
    }
};

FastTree.prototype.setSrc = function(sXmlSrc) {
    if (this.treeState)
        this.xmlSrc = sXmlSrc;
    else
        load(getNonEmptyNode(document.getElementById(this.id).firstChild.firstChild.firstChild.firstChild), sXmlSrc, false);
};

FastTree.prototype.renderingOnLoad = function() {
    if (this.treeState && this.treeState.value) {
        var tree = document.getElementById(this.id);
        tree.innerHTML = this.treeState.value;
    } else
        if (this.xmlString)
            xmlFileLoaded(getXMLObject(this.xmlString), getNonEmptyNode(document.getElementById(this.id).firstChild));
        else if (this.xmlSrc)
            load(getNonEmptyNode(document.getElementById(this.id).firstChild.firstChild.firstChild.firstChild), this.xmlSrc, true);
};


/*
 * FastTree handling routine
 */

function render(oNode, indent) {
    // retrieve attributes
	var isFolder = oNode.tagName == "folder";
    var text = oNode.getAttribute("text");
	var action = oNode.getAttribute("action");
    var hint = oNode.getAttribute("hint");
	var src = oNode.getAttribute("src");
	var target = oNode.getAttribute("target");
    var expand = oNode.getAttribute("expand");
    var expandOnlyByPlus = oNode.getAttribute("expandOnlyByPlus");
    var selected = oNode.getAttribute("selected");
    var id = oNode.getAttribute("id");
    var iconClass = oNode.getAttribute("iconClass");
    var openIconClass = oNode.getAttribute("openIconClass");
    var iconAction = oNode.getAttribute("iconAction");
    var iconTarget = oNode.getAttribute("iconTarget");
    var iconHint = oNode.getAttribute("iconHint");
    var extendable = oNode.getAttribute("extendable");
    var editable = oNode.getAttribute("editable");
    var dragable = oNode.getAttribute("dragable");
    var deleteable = oNode.getAttribute("deleteable");
    var deepExtendable = oNode.getAttribute("deepExtendable");
    var fillable = oNode.getAttribute("fillable");
    var checkable = oNode.getAttribute("checkable");
    var oneValued = oNode.getAttribute("oneValued");
    var type = oNode.getAttribute("type");
    var code = oNode.getAttribute("code");
    var name = oNode.getAttribute("name");
    var parameters = oNode.getAttribute("parameters");

    var childrenText = "";
	var nextNode = getNonEmptyNode(oNode.nextSibling);
    var cs = oNode.childNodes;
	var childCount = cs.length;
    if (childCount > 0) {
        var childIndent = indent + "<td class='fastTree" + (nextNode ? "I" : "Blank") + "'><div class='fastTreeBlank'/></td>";
	    for (var i = 0; i < childCount; i++) {
            var child = cs[i];
		    if (child.tagName == "folder" || child.tagName == "item" || child.tagName == "section" ||
                child.tagName == "reference" || child.tagName == "indicator")
			    childrenText+= render(child, childIndent);
        }
    }
    if (childrenText.length > 0)
        childrenText = "<div" + (!expand ? " style='display: none'" : "") + ">"+childrenText+"</div>";

    var html = [];
    html[html.length] = "<table class='fastTreeNode'>";
    html[html.length] = indent;
    if (nextNode)
        html[html.length] = "<td class='fastTreeI'";
    else
        html[html.length] = "<td";
    var expandeable = src || childrenText.length > 0;
    if (expandeable) {
        html[html.length] = " id='toggler"+id+"'><div onclick='";
        if (childrenText.length > 0)
            html[html.length] = "toggle(this.parentNode);'";
        else {
            html[html.length] = "load(this.parentNode, \"";
            html[html.length] = src;
            html[html.length] = "\");'";
        }
        isFolder = true;
        html[html.length] = expand ? " class='fastTreeMinus'>" : " class='fastTreePlus'>";
    } else {
        html[html.length] = "><div class='fastTreeL'>";
    }
    html[html.length] = "&nbsp;</div></td>";

    if (childCount > 0)
        html[html.length] = "<td class='fastTreeIconI'";
    else
        html[html.length] = "<td class='fastTreeIcon'";
    if (iconAction) {
        if (iconAction.indexOf("javascript:") == 0) {
            html[html.length] = " onclick='";
            html[html.length] = iconAction.substr("javascript:".length);
            html[html.length] = "'";
        } else {
            html[html.length] = "><a href='";
            html[html.length] = iconAction;
            html[html.length] = "'";
            if (iconTarget && iconTarget.length > 0) {
                html[html.length] = " target='";
                html[html.length] = iconTarget;
                html[html.length] = "'";
            }
        }
    } else if (dragable)
        html[html.length] = " onmousedown='return startDragNode(event, this);'";
    html[html.length] = "><div class='";
    html[html.length] = (isFolder ?
                            (expandeable || action ?
                                (childrenText.length > 0 && expand ?
                                    (openIconClass ? openIconClass : "fastTreeOpenFolder") :
                                    (iconClass ? iconClass : "fastTreeFolder")
                                ) : (iconClass ? iconClass : "fastTreeEmptyFolder")
                            ) : (iconClass ? iconClass : "fastTreeFile")
                        );
    if (iconHint) {
        html[html.length] = "' title='";
        html[html.length] = iconHint;
    }
    if (iconClass) {
        html[html.length] = "' iconclass='";
        html[html.length] = iconClass;
    }
    if (openIconClass) {
        html[html.length] = "' openiconclass='";
        html[html.length] = openIconClass;
    }
    html[html.length] = "'><div class='fastTreeBlank'/></div>";
    if (iconAction)
        html[html.length] = "</a>";
    html[html.length] = "</td>";

    html[html.length] = "<td id='";
    html[html.length] = id;
    html[html.length] = "' class='";
    if (selected)
        html[html.length] = "fastTreeSelectedItem";
    else
        if (expandeable || action)
            html[html.length] = "fastTreeItem";
        else
            html[html.length] = "fastTreeEmptyItem";
    if (hint) {
        html[html.length] = "' title='";
        html[html.length] = hint;
    }
    if(type){
        html[html.length] = "' type='";
        html[html.length] = type;
    }
    if(code){
        html[html.length] = "' code='";
        html[html.length] = code;
    }
    if(name){
        html[html.length] = "' name='";
        html[html.length] = name;
    }
    if (parameters) {
        html[html.length] = "' parameters='";
        html[html.length] = parameters;
    }
    html[html.length] = "'";

    if (action) {
        if (action.indexOf("javascript:") == 0) {
            html[html.length] = " onclick='";
            html[html.length] = action.substr("javascript:".length);
            html[html.length] = "'>";
            html[html.length] = text;
        } else {
            html[html.length] = "><a class='fastTreeItemName' href='";
            html[html.length] = action;
            html[html.length] = "'";
            if (target && target.length > 0) {
                html[html.length] = " target='";
                html[html.length] = target;
                html[html.length] = "'";
            }
            html[html.length] = ">";
            html[html.length] = text;
            html[html.length] = "</a>";
        }
    } else {
        if (childrenText.length > 0 && !expandOnlyByPlus)
            html[html.length] = " onclick='toggle(this.previousSibling.previousSibling);'>";
        else if (src && !expandOnlyByPlus) {
            html[html.length] = " onclick='load(this.previousSibling.previousSibling, \"";
            html[html.length] = src;
            html[html.length] = "\");'>";
        } else
            html[html.length] = ">";
        html[html.length] = text;
    }
    html[html.length] = "</td>";

    if (editable) {
        html[html.length] = "<td class='fastTreeEditButton' id='edit";
        html[html.length] = id;
        html[html.length] = "' onclick='editNode(this, \"";
        html[html.length] = id;
        html[html.length] = "\");' title='";
        html[html.length] = fastTreeConfig.editTooltip;
        html[html.length] = "'><div class='fastTreeBlank'/></td>";
    }

    if (deleteable) {
        html[html.length] = "<td class='fastTreeDeleteButton' id='delete";
        html[html.length] = id;
        html[html.length] = "' onclick='deleteNode(this, \"";
        html[html.length] = id;
        html[html.length] = "\");' title='";
        html[html.length] = fastTreeConfig.deleteTooltip;
        html[html.length] = "'><div class='fastTreeBlank'/></td>";
    }

    if (extendable) {
        html[html.length] = "<td class='fastTreeAddButton' id='add";
        html[html.length] = id;
        html[html.length] = "' onclick='addNode(this, \"";
        html[html.length] = id;
        html[html.length] = "\");' title='";
        html[html.length] = fastTreeConfig.addTooltip;
        if (deepExtendable)
            html[html.length] = "' deepextendable='true";
        html[html.length] = "'><div class='fastTreeBlank'/></td>";
    }
    if (fillable) {
        html[html.length] = "<td class='fastTreeFillButton' id='fill";
        html[html.length] = id;
        html[html.length] = "' onclick='fillCodes(this, \"";
        html[html.length] = id;
        html[html.length] = "\");' title='";
        html[html.length] = fastTreeConfig.fillTooltip;
        html[html.length] = "'><div class='fastTreeBlank'/></td>";
    }
    if (oneValued) {
        html[html.length] = "<td class='fastTreeOneValuedButton' id='fill";
        html[html.length] = id;
        html[html.length] = "' onclick='addNode(this, \"";
        html[html.length] = id;
        html[html.length] = "\", \"true\");' title='";
        html[html.length] = fastTreeConfig.oneSignedTooltip;
        html[html.length] = "'><div class='fastTreeBlank'/></td>";
    }
    if (checkable) {
        html[html.length] = "<td class='fastTreeCheckButton' id='fill";
        html[html.length] = id;
        html[html.length] = "' onclick='check(this, \"";
        html[html.length] = id;
        html[html.length] = "\");' title='";
        html[html.length] = fastTreeConfig.checkTooltip;
        html[html.length] = "'><div class='fastTreeBlank'/></td>";
    }

	html[html.length] = "</table>";
    html[html.length] = childrenText;
    return html.join('');
}

function toggle(oNode) {
	var oParentNode = oNode.parentNode.parentNode.parentNode;
    var childredDiv = getNonEmptyNode(oParentNode.nextSibling);
    var toggler = getNonEmptyNode(oNode.firstChild);
    if (childredDiv.style.display == "none") {
        childredDiv.style.display = "block";
        toggler.className = "fastTreeMinus";
    } else {
        childredDiv.style.display = "none";
        toggler.className = "fastTreePlus";
    }

    var itemIconContainer = getNonEmptyNode(oNode.nextSibling);
    itemIconContainer.className = childredDiv.style.display == "none" ? "fastTreeIcon" : "fastTreeIconI";
    var itemIcon = getNonEmptyNode(itemIconContainer.firstChild);
    itemIcon.className = (childredDiv.style.display == "none" ?
                          itemIcon.getAttribute("iconclass") ? itemIcon.getAttribute("iconclass") : "fastTreeFolder" :
                          itemIcon.getAttribute("openiconclass") ? itemIcon.getAttribute("openiconclass") : "fastTreeOpenFolder");
    saveTreeState(oNode);
}

function load(oNode, xmlSrc, doNotCreateContentDiv) {
    if (oNode.nextSibling && oNode.nextSibling.nextSibling && oNode.nextSibling.nextSibling.nextSibling &&
        oNode.nextSibling.nextSibling.nextSibling.className == "fastTreeEditDisabledButton")
        return;

    var oParentNode = oNode.parentNode.parentNode.parentNode;
    var nextNode = getNonEmptyNode(oParentNode.nextSibling);
    if (nextNode && nextNode.tagName.toLowerCase() == "div") {
        toggle(oNode);
        return;
    }

    var parentHTML = oParentNode.innerHTML.toLowerCase();
    var start = parentHTML.indexOf("<td");
    var end = parentHTML.indexOf("id=\"toggler");
    if (end < 1)
        end = parentHTML.indexOf("id=toggler");
    var indent = oParentNode.innerHTML.substr(start, end);
    indent = indent.substr(0, indent.toLowerCase().lastIndexOf("<td"));
    if (oParentNode.parentNode.className != "fastTree")
        indent+= "<td class='fastTree" + (nextNode ? "I" : "Blank") + "'><div class='fastTreeBlank'/></td>";

    var contentDiv;
    if (doNotCreateContentDiv)
        contentDiv = nextNode;
    else {
        contentDiv = document.createElement("div");
        contentDiv.innerHTML = "<table class='fastTreeNode'><tr>" + indent + "<td class='fastTreeLoading'>" + fastTreeConfig.loadingText + "</td></tr></table>";
        if (nextNode)
            oParentNode.parentNode.insertBefore(contentDiv, nextNode);
        else
            oParentNode.parentNode.appendChild(contentDiv);
    }

    var itemIconContainer = getNonEmptyNode(oNode.nextSibling);
    itemIconContainer.className = "fastTreeIconI";
    var itemIcon = getNonEmptyNode(itemIconContainer.firstChild);
    itemIcon.className = itemIcon.getAttribute("openiconclass") ? itemIcon.getAttribute("openiconclass") : "fastTreeOpenFolder";

    if (xmlSrc.indexOf('http') == 0) {
        var loadScript = document.createElement("script");
        loadScript.type = "text/javascript";
        loadScript.src = xmlSrc;
        document.body.appendChild(loadScript);
    } else {
        loadXML(xmlSrc, function (xml) {
            xmlFileLoaded(xml, oParentNode, oNode.firstChild);
            fastTreeConfig.onLoad(oParentNode);
        });
    }
}

function loaded(sXmlString, oNode) {
    var oParentNode = oNode.parentNode.parentNode.parentNode;
    xmlFileLoaded(getXMLObject(sXmlString), oParentNode, oNode.firstChild);
}

// Inserts an xml document as a subtree to the provided node
function xmlFileLoaded(oXmlDoc, oParentNode, toggler) {
    var l = 0;
    var html = [];
    var contentDiv = getNonEmptyNode(oParentNode.nextSibling);
    var nextNode = getNonEmptyNode(contentDiv.nextSibling);
    var parentHTML = oParentNode.innerHTML.toLowerCase();
    var start = parentHTML.indexOf("<td");
    var end = parentHTML.indexOf("id=\"toggler");
    if (end < 1)
        end = parentHTML.indexOf("id=toggler");
    var indent = oParentNode.innerHTML.substr(start, end);
    indent = indent.substr(0, indent.toLowerCase().lastIndexOf("<td"));
    if (oParentNode.parentNode.className != "fastTree")
        indent+= "<td class='fastTree" + (nextNode ? "I" : "Blank") + "'><div class='fastTreeBlank'/></td>";

	// check that the load of the xml file went well
	if (oXmlDoc == null || oXmlDoc.documentElement == null)
		html[html.length] = "<table class='fastTreeNode'><tr>" + indent + "<td class='fastTreeErrorItem'>" + fastTreeConfig.loadErrorText + "</td></tr></table>";
    else {
        // there is one extra level of tree elements
        var root = oXmlDoc.documentElement;

        // loop through all tree children
        var cs = root.childNodes;
        l = cs.length;
        for (var i = 0; i < l; i++) {
            var child = cs[i];
            if (child.tagName == "folder" || child.tagName == "item")
                html[html.length] = render(child, indent);
        }

        // if no children we got an error
        if (html.length == 0) {
            contentDiv.className = "fastTreeEmptyNode";
            html[html.length] = "<table class='fastTreeNode'><tr>" + indent + "<td class='fastTreeErrorItem'>" + fastTreeConfig.emptyNodeText + "</td></tr></table>";
        }
    }

    contentDiv.innerHTML = html.join('');
    if (toggler)
        toggler.className = toggler.className = "fastTreeMinus";
    saveTreeState(oParentNode);
}

function saveTreeState(oNode) {
    while (!oNode.getAttribute("id")) {
        oNode = oNode.parentNode;
    }
    if (oNode.getAttribute("stateId")) {
        var treeState = document.getElementById(oNode.getAttribute("stateId"));
        if (treeState)
            treeState.value = oNode.innerHTML;
    }
}

function addNode(oNode, nodeId) {
    setTreeValue();
    var toggler = document.getElementById("toggler"+nodeId);
    if (toggler && toggler.firstChild && toggler.firstChild.className == "fastTreePlus") {
        toggler.firstChild.onclick();
        doAddNode(oNode, nodeId);
    } else {
        if (!toggler) {
            var iconTd = oNode;
            while(iconTd && iconTd.className!= "fastTreeEmptyItem")
                iconTd = iconTd.previousSibling;
            if (iconTd) {
                iconTd = iconTd.previousSibling;
                iconTd.firstChild.className = "fastTreeOpenFolder";
                toggler = iconTd.previousSibling;
                toggler.setAttribute("id", "toggler"+nodeId);
                toggler.innerHTML = "<div class='fastTreeMinus' onclick='toggle(this.parentNode);'>&nbsp;</div>";
            }
        }
        doAddNode(oNode, nodeId);
    }
}

function doAddNode(oNode, nodeId) {
    var toggler = document.getElementById("toggler"+nodeId);
    if (toggler && toggler.firstChild && toggler.firstChild.className == "fastTreePlus") {
        window.setTimeout(function () {
            doAddNode(oNode, nodeId);
        }, 10);
        return;
    }

    var oParentNode = oNode.parentNode.parentNode.parentNode;
    var contentDiv = getNonEmptyNode(oParentNode.nextSibling);
    if (contentDiv == null) {
        contentDiv = document.createElement("div");
        oParentNode.parentNode.appendChild(contentDiv);
    } else if (contentDiv.className == "fastTreeNode") {
        var nextTreeNode = contentDiv;
        contentDiv = document.createElement("div");
        if (nextTreeNode != null)
            oParentNode.parentNode.insertBefore(contentDiv, nextTreeNode);
        else
            oParentNode.parentNode.appendChild(contentDiv);
    } else if (contentDiv.className == "fastTreeEmptyNode") {
        contentDiv.innerHTML = "";
        contentDiv.className = "";
    }

    var nextNode = getNonEmptyNode(contentDiv.nextSibling);
    var parentHTML = oParentNode.innerHTML.toLowerCase();
    var start = parentHTML.indexOf("<td");
    var end = parentHTML.indexOf("id=\"toggler");
    if (end < 1)
        end = parentHTML.indexOf("id=toggler");
    var indent = oParentNode.innerHTML.substr(start, end);
    indent = indent.substr(0, indent.toLowerCase().lastIndexOf("<td"));
    if (oParentNode.parentNode.className != "fastTree")
        indent+= "<td class='fastTree" + (nextNode ? "I" : "Blank") + "'><div class='fastTreeBlank'/></td>";

    if (!contentDiv.firstChild) {
        if (toggler)
            toggler.nextSibling.className = "fastTreeIconI";
        else
            getNonEmptyNode(oNode.parentNode.firstChild).className = "fastTreeIconI";
    }

    correctPreviousNodeIdent(contentDiv.lastChild, "fastTreeI");

    var addButton = document.getElementById("add"+nodeId);
    var deepExtendable = addButton && addButton.getAttribute("deepextendable");

    var content = contentDiv.innerHTML;
    var newNum = 0;
    while (content.indexOf(nodeId+"New"+newNum) >= 0)
        newNum++;
    contentDiv.innerHTML = content + render(getXMLObject("<folder text=\"\" id=\""+nodeId+"New"+newNum+"\" editable=\"true\" dragable=\"true\" deleteable=\"true\""+(deepExtendable ? " extendable=\"true\" deepExtendable=\"true\"" : "")+"/>").childNodes[0], indent);

    editNode(document.getElementById("edit"+nodeId+"New"+newNum), nodeId+"New"+newNum);
}

function deleteNode(oNode, nodeId) {
    var treeNode = oNode.parentNode.parentNode.parentNode;
    var nextNode = treeNode.nextSibling;
    if (nextNode && nextNode.tagName.toLowerCase() == 'div')
        nextNode = nextNode.nextSibling;
    if (!nextNode)
        correctPreviousNodeIdent(treeNode.previousSibling, "fastTreeBlank");

    var treeNodeContent = treeNode.nextSibling;
    if (treeNodeContent && treeNodeContent.tagName.toLowerCase() == "div")
        treeNodeContent.parentNode.removeChild(treeNodeContent);

    if (treeNode.parentNode.childNodes.length == 1) {
        var parentNode = treeNode.parentNode.previousSibling;
        var td = parentNode.firstChild.firstChild.firstChild;
        while (td) {
            var tdId = td.getAttribute("id");
            if (tdId && tdId.indexOf("toggler") == 0) {
                td.nextSibling.className = "fastTreeIcon";
                td.innerHTML = "<div class='fastTreeL'>&nbsp;</div>";
                td.removeAttribute("id");
                break;
            }
            td = td.nextSibling;
        }
        treeNodeContent = treeNode.parentNode;
        treeNodeContent.parentNode.removeChild(treeNodeContent);
    } else
        treeNode.parentNode.removeChild(treeNode);

    fastTreeConfig.deleteNode(nodeId);
}

function editNode(oNode, nodeId) {
    setTreeValue();
    var textNode = oNode.previousSibling;
    fastTreeConfig.createEditor(textNode);
    oNode.className = "fastTreeEditDisabledButton";
    fastTreeEditedId = nodeId;
    return false;
}

function fastTreeCheckBlur() {
    if (!fastTreeEditedId || !document.activeElement || !document.activeElement.className || !document.activeElement.parentNode.className ||
        (document.activeElement.className.indexOf("fastTree") < 0 &&
         document.activeElement.parentNode.className.indexOf("fastTree") < 0 &&
         document.activeElement.className.indexOf("edit") < 0 &&
         document.activeElement.parentNode.className.indexOf("tableCell") < 0))
    {
        setTreeValue();
    }
}

function correctPreviousNodeIdent(previousNode, newClass) {
    if (previousNode) {
        var previousNodeContainer = null;
        if (previousNode.tagName.toLowerCase() == "div") {
            previousNodeContainer = previousNode;
            previousNode = previousNode.previousSibling;
        }
        var previousNodeChild = previousNode.firstChild.firstChild.firstChild;
        var identChildCount = 0;
        var previousNodeChildClass;
        while (previousNodeChild && (!(previousNodeChildClass = previousNodeChild.className) || previousNodeChildClass.indexOf("fastTreeIcon") != 0)) {
            previousNodeChild = previousNodeChild.nextSibling;
            identChildCount++;
        }
        previousNodeChild = previousNodeChild.previousSibling;
        identChildCount--;
        if (previousNodeChild) {
            var oNode = previousNodeContainer ? previousNodeContainer.nextSibling : previousNode.nextSibling;
            if (oNode) {
                oNode = oNode.nextSibling;
                if (oNode && oNode.tagName.toLowerCase() == "div")
                    oNode = oNode.nextSibling;
            }
            previousNodeChild.className = oNode ? "fastTreeI" : newClass;
            if (previousNodeContainer)
                correctIdent(previousNodeContainer, identChildCount, newClass);
        }
    }
}

function correctIdent(container, childNum, newClass) {
    var node = container.firstChild;
    while (node) {
        if (node.tagName.toLowerCase() == "div")
            correctIdent(node, childNum, newClass);
        else {
            var nodeIdentItem = node.firstChild.firstChild.childNodes[childNum];
            nodeIdentItem.className = newClass;
        }
        node = node.nextSibling;
    }
}

function inputKeyPressed(e, nodeId) {
    var evt = e || window.event;
    var key = evt.keyCode ? evt.keyCode : evt.which ? evt.which : 0;
    if (key == 13) {
        fastTreeEditedId = nodeId;
        setTreeValue();
        return false;
    } else if (key == 27) {
        fastTreeEditedId = null;
        var oNode = document.getElementById(nodeId);
        oNode.nextSibling.className = "fastTreeEditButton";
        fastTreeConfig.resetEdited(oNode);
        return false;
    }
    return true;
}

function setTreeValue() {
    if (!fastTreeEditedId)
        return;
    var nodeId = fastTreeEditedId;
    fastTreeEditedId = null;
    var oNode = document.getElementById(nodeId);
    if (!oNode)
        return;

    oNode.nextSibling.className = "fastTreeEditButton";
    fastTreeConfig.setNodeValue(oNode);
}

function startDragNode(e, oNode) {
    if(!fastTreeConfig.isEnableDrag)
        return false;
    var isDragFolder = oNode.firstChild.className.indexOf("Folder") >= 0;
    draggedNode = oNode;
    dragNodeId = oNode.nextSibling.id;
    dragNodeTable = oNode.parentNode.parentNode.parentNode;
    var dragNodeContainer = dragNodeTable.parentNode;
    startPos = getElementPos(oNode);
    var mousePos = getMousePos(e);
    mouseOffset = {x: mousePos.x-startPos.x, y: mousePos.y-startPos.y};
    document.body.style.cursor = 'move';

    dndObject = document.createElement("div");
    dndObject.className = "dragable";
    var table = document.createElement("table");
    table.className = "fastTreeNode";
    dndObject.appendChild(table);
    var tbody = document.createElement("tbody");
    table.appendChild(tbody);
    var tr = document.createElement("tr");
    tbody.appendChild(tr);
    var clonnedNode = oNode.cloneNode(true);
    tr.appendChild(clonnedNode);
    tr.appendChild(oNode.nextSibling.cloneNode(true));
    document.body.appendChild(dndObject);
    dndObject.style.position = "absolute";

    var parentNode = dragNodeContainer.previousSibling;
    if (parentNode.className == "fastTreeNode")
        parentNode = parentNode.firstChild.firstChild.firstChild;
    while (parentNode.className != "fastTreeIcon" && parentNode.className != "fastTreeIconI")
        parentNode = parentNode.nextSibling;
    possibleTargets = [];
    var fastTreeIcons;
    if (document.getElementsByClassName) {
        fastTreeIcons = document.getElementsByClassName("fastTreeIcon");
        var fastTreeIconsI = document.getElementsByClassName("fastTreeIconI");
        for (var i = 0; i < fastTreeIconsI.length; i++) {
            fastTreeIcons[fastTreeIcons.length] = fastTreeIconsI[i];
        }
    } else { // IE
        fastTreeIcons = [];
        var nodes = document.getElementsByTagName('*');
        for (i = 0; i < nodes.length; i++)
            if (nodes[i].className == "fastTreeIcon" || nodes[i].className == "fastTreeIconI")
                fastTreeIcons[fastTreeIcons.length] = nodes[i];
    }
    for (i = 0; i < fastTreeIcons.length; i++) {
        if (fastTreeIcons[i] == oNode) {
            dndNodeIndex = possibleTargets.length;
        } else if (fastTreeIcons[i] != clonnedNode && fastTreeIcons[i] != parentNode &&
            ((isDragFolder && fastTreeIcons[i].firstChild.className.indexOf("Folder") >= 0) ||
             (!isDragFolder && fastTreeIcons[i].firstChild.className.indexOf("Folder") < 0)) &&
            dragNodeContainer == fastTreeIcons[i].parentNode.parentNode.parentNode.parentNode)
            possibleTargets[possibleTargets.length] = fastTreeIcons[i];
    }
/*
    for (i = 0; i < possibleTargets.length; i++)
        if (possibleTargets[i].className == "fastTreeIcon")
            possibleTargets[i].className = "fastTreeTargetIcon";
        else
            possibleTargets[i].className = "fastTreeTargetIconI";
*/    dndTargetsContainer = possibleTargets.length > 0 ? possibleTargets[0].parentNode.parentNode.parentNode.parentNode : null;

    if (document.addEventListener) { // W3C standard
        document.addEventListener('mousemove', dragNode, false);
        document.addEventListener('mouseup', endDragNode, false);
    } else if (document.attachEvent) {// Microsoft
        document.attachEvent('onmousemove', dragNode);
        document.attachEvent('onmouseup', endDragNode);
    }
    var dndTargetsContainerPos = getElementPos(dndTargetsContainer);

    dndDelimiter = document.createElement("div");
    dndDelimiter.className = "delimiter";
    dndDelimiter.innerHTML = "<table><tbody><tr><td class='delimiterLeft'> </td><td class='delimiterCenter'> </td><td class='delimiterRight'> </td></tr></tbody></table>";
    dndDelimiter.style.display = "none";
    dndDelimiter.style.left = dndTargetsContainerPos.x + 'px';
    dndDelimiter.style.width = dndTargetsContainer.offsetWidth + 'px';
    dndDelimiter.firstChild.firstChild.firstChild.firstChild.nextSibling.style.width = (dndTargetsContainer.offsetWidth-4) + 'px';
    dndDelimiter.style.position = "absolute";
    document.body.appendChild(dndDelimiter);

    dragNode(e);
    return false;
}

function dragNode(event) {
    var mousePos = getMousePos(event);
    var dndTargetsContainerPos = getElementPos(dndTargetsContainer);

    var insert = false;
    var element = possibleTargets.length > 0 ? possibleTargets[0] : null;
    var elementPos = element? getElementPos(element) : null;
    if (dndNodeIndex > 0 && elementPos &&
        mousePos.x >= dndTargetsContainerPos.x &&
        mousePos.y >= elementPos.y - 3 &&
        mousePos.x <= dndTargetsContainerPos.x + dndTargetsContainer.offsetWidth &&
        mousePos.y <= elementPos.y + 3)
    {
        elementPos.y = elementPos.y - element.offsetHeight;
        insert = true;
    } else {
        for (var i = 0; i < possibleTargets.length; i++) {
            element = possibleTargets[i];
            elementPos = getElementPos(element);
            if (dndNodeIndex != i+1 &&
                mousePos.x >= dndTargetsContainerPos.x &&
                mousePos.y >= elementPos.y + element.offsetHeight - 3 &&
                mousePos.x <= dndTargetsContainerPos.x + dndTargetsContainer.offsetWidth &&
                mousePos.y <= elementPos.y + element.offsetHeight + 3) {
                insert = true;
                break;
            }
        }
    }
    if (insert) {
        if (dndDelimiter.style.display == "none") {
            dndObject.style.display = "none";
            dndDelimiter.style.display = "";
        }
        dndDelimiter.style.top = elementPos.y + element.offsetHeight - 3 + 'px';
    } else {
        if (dndObject.style.display == "none") {
            dndDelimiter.style.display = "none";
            dndObject.style.display = "";
        }
        dndObject.style.left = (mousePos.x - mouseOffset.x) + 'px';
        dndObject.style.top  = (mousePos.y - mouseOffset.y) + 'px';
    }

    return false;
}

function endDragNode(event) {
    if (document.removeEventListener) { // W3C standard
        document.removeEventListener('mousemove', dragNode, false);
        document.removeEventListener('mouseup', endDragNode, false);
    } else if (document.detachEvent) {// Microsoft
        document.detachEvent('onmousemove', dragNode);
        document.detachEvent('onmouseup', endDragNode);
    }

    dndObject.parentNode.removeChild(dndObject);
    dndDelimiter.parentNode.removeChild(dndDelimiter);
    document.body.style.cursor = 'auto';
/*
    for (var i = 0; i < possibleTargets.length; i++)
        if (possibleTargets[i].className == "fastTreeTargetIcon")
            possibleTargets[i].className = "fastTreeIcon";
        else
            possibleTargets[i].className = "fastTreeIconI";
*/

    var mousePos = getMousePos(event);
    var dndTargetsContainerPos = getElementPos(dndTargetsContainer);

    var element = possibleTargets.length > 0 ? possibleTargets[0] : null;
    var elementPos = element? getElementPos(element) : null;
    if (dndNodeIndex > 0 && elementPos &&
        mousePos.x >= dndTargetsContainerPos.x &&
        mousePos.y >= elementPos.y - 3 &&
        mousePos.x <= dndTargetsContainerPos.x + dndTargetsContainer.offsetWidth &&
        mousePos.y <= elementPos.y + 3)
    {
        elementPos.y = elementPos.y - element.offsetHeight;
        var elementTable = element.parentNode.parentNode.parentNode;
        var parentFolder = dragNodeTable.parentNode;
        var previousNodeTable = dragNodeTable.previousSibling;
        parentFolder.removeChild(dragNodeTable);
        parentFolder.insertBefore(dragNodeTable, elementTable);
        if (draggedNode.previousSibling.className == "")
            draggedNode.previousSibling.className = "fastTreeI";
        if (!previousNodeTable.nextSibling) {
            var previousNode = previousNodeTable.firstChild.firstChild.firstChild;
            while (previousNode.nextSibling && previousNode.nextSibling.className.indexOf("fastTreeIcon") < 0)
                previousNode = previousNode.nextSibling;
            if (previousNode.nextSibling && previousNode.className == "fastTreeI")
                previousNode.className = "";
        }
        fastTreeConfig.moveNode(dragNodeId, element.nextSibling.id, null);
    } else {
        for (var i = 0; i < possibleTargets.length; i++) {
            element = possibleTargets[i];
            elementPos = getElementPos(element);
            if (dndNodeIndex != i+1 &&
                mousePos.x >= dndTargetsContainerPos.x &&
                mousePos.y >= elementPos.y + element.offsetHeight - 3 &&
                mousePos.x <= dndTargetsContainerPos.x + dndTargetsContainer.offsetWidth &&
                mousePos.y <= elementPos.y + element.offsetHeight + 3) {
                parentFolder = dragNodeTable.parentNode;
                elementTable = element.parentNode.parentNode.parentNode;
                parentFolder.removeChild(dragNodeTable);
                if (elementTable.nextSibling) {
                    parentFolder.insertBefore(dragNodeTable, elementTable.nextSibling);
                    var nextNodeTable = dragNodeTable.nextSibling;
                    var nextNode = nextNodeTable.firstChild.firstChild.firstChild;
                    while (nextNode.nextSibling && nextNode.nextSibling.className.indexOf("fastTreeIcon") < 0)
                        nextNode = nextNode.nextSibling;
                    if (!nextNodeTable.nextSibling && nextNode.className == "fastTreeI")
                        nextNode.className = "";
                } else {
                    if (element.previousSibling.className == "")
                        element.previousSibling.className = "fastTreeI";
                    parentFolder.appendChild(dragNodeTable);
                }
                if (dragNodeTable.nextSibling) {
                    if (draggedNode.previousSibling.className == "")
                        draggedNode.previousSibling.className = "fastTreeI";
                } else
                    if (draggedNode.previousSibling.className == "fastTreeI")
                        draggedNode.previousSibling.className = "";
                fastTreeConfig.moveNode(dragNodeId, null, element.nextSibling.id);
                break;
            }
        }
    }

    return false;
}


/*
 * Support routine
 */

function getNonEmptyNode(oNode) {
    while (oNode && oNode.nodeType != 1)
        oNode = oNode.nextSibling;
    return oNode;
}

function getElementPos(element) {
    var left = 0, top  = 0;

    if (element.offsetParent)
        do {
            left += element.offsetLeft;
            top  += element.offsetTop;
            element = element.offsetParent;
        } while (element.offsetParent);

    return {x: left, y: top};
}

function getMousePos(e) {
    var evt = e || window.event;
    return 'pageX' in evt && 'pageY' in evt ?
           {x: evt.pageX, y: evt.pageY} :
           {x: evt.clientX + document.body.scrollLeft - document.body.clientLeft,
            y: evt.clientY + document.body.scrollTop  - document.body.clientTop};
}

function getXMLObject(xmlstring) {
    var xmlobject;
    if (window.ActiveXObject) { // code for IE
        xmlobject = new ActiveXObject("Microsoft.XMLDOM");
        xmlobject.async = "false";
        xmlobject.loadXML(xmlstring);
        return xmlobject;
    } else { // code for Firefox, Opera, Safari, etc.
        var parser = new DOMParser();
        return parser.parseFromString(xmlstring, "text/xml");
    }
}

/*
 * CookiesPersister class
 */

function CookiesPersister() {
	if (document.cookie.length)
        this.cookies = ' ' + document.cookie;
}

CookiesPersister.prototype.setCookie = function (key, value) {
	document.cookie = key + "=" + escape(value);
};

CookiesPersister.prototype.getCookie = function (key) {
	if (this.cookies) {
		var start = this.cookies.indexOf(' ' + key + '=');
		if (start == -1)
            return null;
		var end = this.cookies.indexOf(";", start);
		if (end == -1)
            end = this.cookies.length;
		end -= start;
		var cookie = this.cookies.substr(start, end);
		return unescape(cookie.substr(cookie.indexOf('=') + 1, cookie.length - cookie.indexOf('=') + 1));
	} else
        return null;
};

