// Node object

var Node = Class.create();

Node.prototype =
{
    // serviceType : service type for ruleNodeTree only.
    initialize: function(nodeId, parentNodeId, nodeName, nodeType, webviewFlag, nodeDepth, sortOrder, domainId, isAuthorized, serviceType, deleteFlag)
    {
        this.nodeId = nodeId;
        this.parentNodeId = parentNodeId;
        this.nodeName = nodeName;
        this.url = "_";
        this.nodeType = nodeType;
        this.webviewFlag = webviewFlag;
        this.deleteFlag = deleteFlag? deleteFlag:"N";
        this.nodeDepth = nodeDepth;
        this.sortOrder = sortOrder;
        this.domainId = domainId;
        this.serviceType = serviceType; // service type of ruleNode tree
        this.isAuthorized = isAuthorized;
        this.isOpen = false || false; // whether node is open.
        this.isSelected = false; // whether node is selected.
        this.isLastInLevel = false; // whether node is last in the same level.
        this.hasLeaf = false; // whether node has leaf.
        this._ai = 0; // added number.
        this.parentNode; // parent node object
        this.icon = "";
        this.iconOpen = "";
        this.isChecked = false;
        this.isShow = false; // for check speed of checkbox tree
    }
};

/**
 * Tree object
 * objName - object name.
*/
var Tree = Class.create();

Tree.prototype =
{
    initialize: function(objName, context)
    {
        this.obj = objName;
        this.context = context==null? "..":context;

        this.treeId = "";
        this.aNodes = [];
        this.aIndent = [];
        this.cNodes = {};
        this.aIndex = {};
        this.root = new Node(objName + "_ROOT");
        this.root.isShow = true;
        this.selectedNode = null;
        this.selectedFound = false;
        this.completed = false;
        this.checkedValueSeparator = Public.COLUMN_SEPARATOR;
        this.checkedParamValue = ""; // checked parameter value;
        this.childNodeList = ""; // child node of a node.
        this.clickAddNodeAsEventListener = null;
        this.clickModifyNodeAsEventListener = null;
        this.clickDeleteNodeAsEventListener = null;
        this.template;
        this.leafTemplate;

        this.initConfig();
        this.initIcon();
        this.initSelection();
        this.initSelections();
        this.initLoadImages();

        this.property =
        {
            newRegionName    : "New Region",
            newDomainName    : "New Domain",
            newCategoryName    : "New Category",
            newGroupName    : "New Group",
            keypressCount    : 0
        };

        this.aTreeHtml = new Array();

        this.NODE_TYPE = { REGION: "RNODE", DOMAIN : "DNODE", CATEGR : "CNODE", ACCGRP : "ACCGR", SERVICE : "SNODE" }
        this.SERVICE_TYPE = { COMMON: "SVCOM" };
    },

    resetTree : function ()
    {
        this.aNodes = [];
        this.aIndent = [];
        this.cNodes = {};
        this.aIndex = {};
        this.selectedNode = null;
    },

    getRootId: function()
    {
        return this.root.nodeId;
    },

    initConfig :     function()
    {
        this.config =
        {
            target                  : null,
            folderLinks             : true,
            useSelection            : true,
            useCookies              : false,
            useLines                : true,
            useIcons                : true,
            useStatusText           : false,
            closeSameLevel          : false,
            inOrder                 : true,
            iconPath                : this.context + "/js/spectra/widget/tree/images/",
            useContextMenu          : false, // Whether context-menu displays on mouse-right clicks.
            displayNodeProperty     : false,
            isCheckbox              : false, // Whether tree is type of checkbox. (true, false), default : false.
            rootLinkEnabled         : false, // Whether root tree is linked to any page.
            allNodeDisabled         : false, // Whether all of the node are disabled. (This value is true when faqs are trained.)
            nodePathDelimiter       : " > ", // node's path delimiter
            preloadIndentImage      : false
        };
    },

    initIcon :     function()
    {
        this.icon =
        {
            root                    : this.config.iconPath + "closed_root_folder.gif", // root
            rootUnauthorized        : this.config.iconPath + "closed_root_folder.gif", // unauthorized closed root
            region                  : this.config.iconPath + "closed_region_folder.gif", // closed region folder
            regionOpen              : this.config.iconPath + "opened_region_folder.gif", // opened region folder
            regionUnauthorized      : this.config.iconPath + "unauthorized_closed_region_folder.gif", // unauthorized closed region folder
            regionOpenUnauthorized  : this.config.iconPath + "unauthorized_opened_region_folder.gif", // unauthorized opened region folder
            regionDeleted           : this.config.iconPath + "deleted_closed_region_folder.gif", // deleted and closed region folder
            regionOpenDeleted       : this.config.iconPath + "deleted_opened_region_folder.gif", // deleted and opened region folder

            domain                  : this.config.iconPath + "closed_domain_folder.gif", // closed domain folder
            domainOpen              : this.config.iconPath + "opened_domain_folder.gif", // opened domain folder
            domainUnauthorized      : this.config.iconPath + "unauthorized_closed_domain_folder.gif", // unauthorized closed domain folder
            domainOpenUnauthorized  : this.config.iconPath + "unauthorized_opened_domain_folder.gif", // unauthorized opened domain folder
            domainDeleted           : this.config.iconPath + "deleted_closed_domain_folder.gif", // deleted and closed domain folder
            domainOpenDeleted       : this.config.iconPath + "deleted_opened_domain_folder.gif", // deleted and opened domain folder

            folder                  : this.config.iconPath + "closed_default_folder.gif", // default closed
            folderOpen              : this.config.iconPath + "opened_default_folder.gif", // default opened
            folderUnauthorized      : this.config.iconPath + "unauthorized_closed_default_folder.gif", // unauthorized default closed
            folderOpenUnauthorized  : this.config.iconPath + "unauthorized_opened_default_folder.gif", // unauthorized default opened
            folderHidden            : this.config.iconPath + "hidden_closed_folder.gif", // hidden closed
            folderHiddenOpen        : this.config.iconPath + "hidden_opened_folder.gif", // hidden opened
            folderDeleted           : this.config.iconPath + "deleted_closed_folder.gif", // deleted and closed folder
            folderOpenDeleted       : this.config.iconPath + "deleted_opened_folder.gif", // deleted and opened folder

            accgroup                : this.config.iconPath + "closed_accgroup_folder.gif", // default closed account group
            accgroupOpen            : this.config.iconPath + "opened_accgroup_folder.gif", // default opened account group
            accgroupDeleted         : this.config.iconPath + "deleted_closed_accgroup_folder.gif", // deleted and closed account group
            accgroupOpenDeleted     : this.config.iconPath + "deleted_opened_accgroup_folder.gif", // deleted and opened account group

            ruleSet                 : this.config.iconPath + "closed_default_folder.gif", // default closed account group
            ruleSetOpen             : this.config.iconPath + "opened_default_folder.gif", // default opened account group

            node                    : this.config.iconPath + "node.gif",
            empty                   : this.config.iconPath + "empty.gif",
            line                    : this.config.iconPath + "vertical_line.gif",
            join                    : this.config.iconPath + "node.gif",
            joinBottom              : this.config.iconPath + "lastnode.gif",
            plus                    : this.config.iconPath + "closed_node.gif",
            plusBottom              : this.config.iconPath + "closed_lastnode.gif",
            minus                   : this.config.iconPath + "opened_node.gif",
            minusBottom             : this.config.iconPath + "opened_lastnode.gif"
        };
    },

    initLoadImages : function()
    {
        // pre-load images for fast speed.
        var tree_image_root = new Image();
        tree_image_root.src = this.icon.root;
        var tree_image_rootUnauthorized = new Image();
        tree_image_rootUnauthorized.src = this.icon.rootUnauthorized;
        var tree_image_region = new Image();
        tree_image_region.src = this.icon.region;
        var tree_image_regionOpen = new Image();
        tree_image_regionOpen.src = this.icon.regionOpen;
        var tree_image_regionUnauthorized = new Image();
        tree_image_regionUnauthorized.src = this.icon.regionUnauthorized;
        var tree_image_regionOpenUnauthorized = new Image();
        tree_image_regionOpenUnauthorized.src = this.icon.regionOpenUnauthorized;
        var tree_image_domain = new Image();
        tree_image_domain.src = this.icon.domain;
        var tree_image_domainOpen = new Image();
        tree_image_domainOpen.src = this.icon.domainOpen;
        var tree_image_domainUnauthorized = new Image();
        tree_image_domainUnauthorized.src = this.icon.domainUnauthorized;
        var tree_image_domainOpenUnauthorized = new Image();
        tree_image_domainOpenUnauthorized.src = this.icon.domainOpenUnauthorized;
        var tree_image_folder = new Image();
        tree_image_folder.src = this.icon.folder;
        var tree_image_folderOpen = new Image();
        tree_image_folderOpen.src = this.icon.folderOpen;
        var tree_image_folderUnauthorized = new Image();
        tree_image_folderUnauthorized.src = this.icon.folderUnauthorized;
        var tree_image_folderOpenUnauthorized = new Image();
        tree_image_folderOpenUnauthorized.src = this.icon.folderOpenUnauthorized;
        var tree_image_folderHidden = new Image();
        tree_image_folderHidden.src = this.icon.folderHidden;
        var tree_image_folderHiddenOpen = new Image();
        tree_image_folderHiddenOpen.src = this.icon.folderHiddenOpen;
        var tree_image_node = new Image();
        tree_image_node.src = this.icon.node;
        var tree_image_empty = new Image();
        tree_image_empty.src = this.icon.empty;
        var tree_image_line = new Image();
        tree_image_line.src = this.icon.line;
        var tree_image_join = new Image();
        tree_image_join.src = this.icon.join;
        var tree_image_joinBottom = new Image();
        tree_image_joinBottom.src = this.icon.joinBottom;
        var tree_image_plus = new Image();
        tree_image_plus.src = this.icon.plus;
        var tree_image_plusBottom = new Image();
        tree_image_plusBottom.src = this.icon.plusBottom;
        var tree_image_minus = new Image();
        tree_image_minus.src = this.icon.minus;
        var tree_image_minusBottom = new Image();
        tree_image_minusBottom.src = this.icon.minusBottom;
    },
    /**
     *  normal tree
     */
    initSelection :         function()
    {
        this.selection = // normal tree
        {
            nodeId          : "",
            parentNodeId    : "",
            nodeName        : "",
            nodeType        : "",
            webviewFlag     : "",
            deleteFlag      : "",
            nodeDepth       : "",
            sortOrder       : "",
            domainId        : "",
            isAuthorized    : false,
            isOpen          : false,
            hasLeaf         : false,
            parentNode      : "",
            serviceType     : ""
        };
    },

    /**
     * checked tree
     */
    initSelections :         function()
    {
        this.selections = // checked tree
        {
            nodeId          : "",
            parentNodeId    : "",
            nodeName        : "",
            nodeType        : "",
            webviewFlag     : "",
            deleteFlag      : "",
            nodeDepth       : "",
            sortOrder       : "",
            domainId        : "",
            isAuthorized    : false,
            isOpen          : false,
            hasLeaf         : false,
            parentNode      : "",
            serviceType     : ""
        };
    },
    /**
     * Adds a new node to the node array
     * nodeId : node's id(NODE00000003')
     * parent nodeId : node's parent nodeId
     * nodeName : node's name
     * nodeType : node's type. (ROOT, "RNODE"-REGION, "DNODE"-DOMAIN, "CNODE"-CATEGORY)
     * webviewFlag : Whether node is visible in web or not (Y/N)
     * isAuthorized : Whether agent is accessible to node (true/false)
     */
    add : function(nodeId, parentNodeId, nodeName, nodeType, webviewFlag, nodeDepth, sortOrder, domainId, isAuthorized, serviceType)
    {
        var node = new Node(nodeId, parentNodeId, nodeName, nodeType, webviewFlag, nodeDepth, sortOrder, domainId, isAuthorized, serviceType);
        this.addNode(node);
        node = null;
    },

    addNode : function(node)
    {
        if (node.parentNodeId == this.root.nodeId && this.config.rootLinkEnabled)
            node.isAuthorized = true;

        this.aNodes[this.aNodes.length] = node;

        var idx = this.aNodes.length-1;
        this.setNodeProperty(idx);

        // This code is for fast access node
        this.aIndex[node.nodeId] = idx;
        if( this.cNodes[node.parentNodeId] == null)
            this.cNodes[node.parentNodeId] = new Array(node.nodeId);
        else
            this.cNodes[node.parentNodeId][this.cNodes[node.parentNodeId].length] = node.nodeId;
    },

    updateNodeId : function(tempNodeId, nodeId)
    {
        // This code is for fast access node
        var idx = this.aIndex[tempNodeId];
        this.aIndex[nodeId] = idx;
        this.aIndex[tempNodeId] = null;

        var node = this.aNodes[idx];
        node.nodeId = nodeId;
        this.aNodes[idx] = node;

        if( this.cNodes[node.parentNodeId] == null)
        {
            this.cNodes[node.parentNodeId] = new Array(node.nodeId);
        }
        else
        {
            idx = this.cNodes[node.parentNodeId].indexOf(tempNodeId);
            this.cNodes[node.parentNodeId][idx] = nodeId;
        }
    },

    updateNodeName : function(nodeId, nodeName)
    {
        var idx = this.aIndex[nodeId];
        var node = this.aNodes[idx];
        node.nodeName = nodeName;
        this.aNodes[idx] = node;
        var nodeTextObj = $("n" + this.obj + idx);
        nodeTextObj.innerHTML = nodeName;
    },

    updateNodeIcon : function(nodeId, webviewFlag)
    {
        var idx = this.aIndex[nodeId];
        var node = this.aNodes[idx];
        node.webviewFlag = webviewFlag;
        this.aNodes[idx] = node;
        this.setNodeProperty(idx);
        node = this.aNodes[idx];
        var nodeImageObj = $("i" + this.obj + idx);
        nodeImageObj.src = ((node.isOpen) ? node.iconOpen : node.icon);
    },

    addList : function(arrNode)
    {
        if( arrNode )
        {
            this.root.nodeId = arrNode[0].parentNodeId;
            //arrNode[0].parentNodeId = this.getRootId();
            //this.addNode(arrNode[0]);
            for( var i=0; i < arrNode.length; i++ )
                this.addNode(arrNode[i]);
        }
    },

    setNodeProperty : function(id)
    {
        switch(this.aNodes[id].nodeType)
        {
            case this.NODE_TYPE.CATEGR : // If nodeType is "CATEGR"
                if (this.aNodes[id].webviewFlag == "N")
                {
                    this.aNodes[id].icon = this.icon.folderHidden;
                    this.aNodes[id].iconOpen = this.icon.folderHiddenOpen;
                }
                else
                {
                    this.aNodes[id].icon = this.icon.folder;
                    this.aNodes[id].iconOpen = this.icon.folderOpen;
                }

                if (!this.aNodes[id].isAuthorized)
                {
                    this.aNodes[id].icon = this.icon.folderUnauthorized;
                    this.aNodes[id].iconOpen = this.icon.folderOpenUnauthorized;
                }

                if (this.aNodes[id].deleteFlag == "Y")
                {
                    this.aNodes[id].icon = this.icon.folderDeleted;
                    this.aNodes[id].iconOpen = this.icon.folderDeletedOpen;
                }
                break;
            case this.NODE_TYPE.REGION : // If nodeType is "REGION"
                this.aNodes[id].icon = this.icon.region;
                this.aNodes[id].iconOpen = this.icon.regionOpen;
                if (!this.aNodes[id].isAuthorized)
                {
                    this.aNodes[id].icon = this.icon.regionUnauthorized;
                    this.aNodes[id].iconOpen = this.icon.regionOpenUnauthorized;
                }

                if (this.aNodes[id].deleteFlag == "Y")
                {
                    this.aNodes[id].icon = this.icon.regionDeleted;
                    this.aNodes[id].iconOpen = this.icon.regionDeletedOpen;
                }
                break;
            case this.NODE_TYPE.DOMAIN : // If nodeType is "DOMAIN"
                this.aNodes[id].icon = this.icon.domain;
                this.aNodes[id].iconOpen = this.icon.domainOpen;
                if (!this.aNodes[id].isAuthorized)
                {
                    this.aNodes[id].icon = this.icon.domainUnauthorized;
                    this.aNodes[id].iconOpen = this.icon.domainOpenUnauthorized;
                }

                if (this.aNodes[id].deleteFlag == "Y")
                {
                    this.aNodes[id].icon = this.icon.domainDeleted;
                    this.aNodes[id].iconOpen = this.icon.domainDeletedOpen;
                }
                break;
            case this.NODE_TYPE.ACCGRP : // If nodeType is "ACCGR"
                this.aNodes[id].icon = this.icon.accgroup;
                this.aNodes[id].iconOpen = this.icon.accgroupOpen;

                if (this.aNodes[id].deleteFlag == "Y")
                {
                    this.aNodes[id].icon = this.icon.accgroupDeleted;
                    this.aNodes[id].iconOpen = this.icon.accgroupDeletedOpen;
                }
                break;
            case this.NODE_TYPE.SERVICE : // If nodeType is "SNODE"
                this.aNodes[id].icon = this.icon.ruleSet;
                this.aNodes[id].iconOpen = this.icon.ruleSetOpen;
                break;
        }

        //if (!this.aNodes[id].target && this.config.target) this.aNodes[id].target = this.config.target;
        if (this.config.useSelection && this.aNodes[id].nodeId == this.selectedNode && !this.selectedFound )
        {
            this.aNodes[id].isSelected = true;
            this.selectedNode = id;
            this.selectedFound = true;
        }
    },

    // Open all nodes
    openAll : function()
    {
        this.oAll(true);
    },

    // Close all nodes
    closeAll : function()
    {
        this.oAll(false);
    },

    // Outputs the tree to the page
    toString : function()
    {
        this.aTreeHtml = new Array();
        this.aTreeHtml.push('<div class="dtree">\n');
        try
        {
            this.createTemplet();
            this.selectedNode = this.getSelected();
            this.setCS();
            this.addNodeUI(this.root);
        }
        catch(e) {}

        this.aTreeHtml.push('</div>');
        if (!this.selectedFound) this.selectedNode = null;
        this.completed = true;
        return this.aTreeHtml.join('');
    },

    // Creates the tree structure
    addNodeUI : function(pNode)
    {
        var arrCn = this.cNodes[pNode.nodeId];

        if( arrCn )
            for( var j=0; j < arrCn.length; j++ )
            {
                var cn = this.aNodes[this.aIndex[arrCn[j]]];

                cn.parentNode = pNode;
                cn._ai = this.aIndex[cn.nodeId];
                if (cn.hasLeaf && !cn.isOpen && this.config.useCookies) cn.isOpen = this.isOpen(cn.nodeId);
                if (!this.config.folderLinks && cn.hasLeaf) cn.url = null;

                //str += this.node(cn, this.aIndex[cn.nodeId]);
                this.node(cn, this.aIndex[cn.nodeId]);
            }
            //return str;
    },

    createTemplet : function()
    {
        var str = "<div id=\"node" + this.obj + "#{NODE_INDEX}\" class=\"dtree\">#{INDENT}";
        if (this.config.useIcons)
        {
            if (this.config.isCheckbox) // If tree is checkbox.
            {
                str += "<input type=\"checkbox\" name=\"#{NODE_ID}\" id=\"" + this.obj
                    + "_#{NODE_ID}\" style=\"width:15; height:13; valign:bottom;\" onclick=\"javascript:"
                    + this.obj + ".checkOnNode('" + this.obj + "', #{NODE_INDEX});\" #{DISABLED} #{CHECKED}>";
            }
            str += "<img src=\"" + this.icon.empty + "\" width=\"1\" height=\"1\"><img id=\"i"
                + this.obj + "#{NODE_INDEX}\" src=\"#{NODE_ICON}\" alt=\"\" onclick=\"javascript:"
                + this.obj + ".clickOnNode('#{NODE_INDEX}');\" ondblclick=\"javascript:"
                + this.obj + ".dblClickOnNode('#{NODE_INDEX}');\"";

            if (this.config.useContextMenu)
                str += " oncontextmenu=\"return " + this.obj + ".onContextMenu(event, '#{NODE_INDEX}');\" ";
            str += " style=\"cursor:pointer\"/>";
        }
        str += "<img src=\"" + this.icon.empty + "\" width=\"1\" height=\"1\"><a id=\"s"
            + this.obj + "#{NODE_INDEX}\" onclick=\"javascript:"
            + this.obj + ".clickOnNode('#{NODE_INDEX}');\" ondblclick=\"javascript:"
            + this.obj + ".dblClickOnNode('#{NODE_INDEX}');\" ";

        if (this.config.useContextMenu)
            str += " oncontextmenu=\"return " + this.obj + ".onContextMenu(event, '#{NODE_INDEX}');\" ";
        str += " style=\"color: #000000; cursor:pointer;\"><span id=\"n" + this.obj + "#{NODE_INDEX}\" class=\"#{NODE_CLASS}\">#{NODE_NAME}";

        if (this.config.displayNodeProperty)
            str += "[#{PARENT_NODE_ID}][#{NODE_ID}][#{NODE_DEPTH}][#{SORT_ORDER}][#{IS_AUTHORIZED}][#{HAS_LEAF}][#{AI}]";
        str += "</span><span id=\"inputNodeId" + this.obj + "#{NODE_INDEX}\" style=\"padding: 0px; height: 14px;\"></span></a>";

        //<input type=\"text\" id=\"focusNodeId" + this.obj + "#{NODE_INDEX}\" name=\"focusNodeId" + this.obj + "#{NODE_INDEX}\" style=\"width:1; height:1\">
        //if (node.url || ((!this.config.folderLinks || !node.url) && node.hasLeaf)) str += '</a>';

        str += "</div>";

        this.template = new Template(str);
    },

    // Creates the node icon, url and text
    node : function(node, nodeId)
    {
        //var str = "";
        var templetData =
        {
            NODE_INDEX: nodeId,
            NODE_ID : node.nodeId,
            PARENT_NODE_ID : node.parentNodeId,
            NODE_NAME : node.nodeName,
            NODE_DEPTH : node.nodeDepth,
            SORT_ORDER : node.sortOrder,
            IS_AUTHORIZED : node.isAuthorized,
            HAS_LEAF : node.hasLeaf,
            AI : node._ai,
            INDENT: '',
            DISABLED : '',
            CHECKED : '',
            NODE_ICON : '',
            NODE_CLASS : ''
        }

        templetData.INDENT = this.indent(node, nodeId);
        if (this.config.useIcons)
        {
            if (this.config.isCheckbox) // If tree is checkbox.
            {
                if (!node.isAuthorized || (node.parentNodeId == this.root.nodeId && !this.config.rootLinkEnabled) )
                    templetData.DISABLED = "disabled";
                if (this.checkedParamValue.indexOf(node.nodeId) > -1)
                    templetData.CHECKED = "checked";
            }

            templetData.NODE_ICON = ((node.isOpen) ? node.iconOpen : node.icon);
        }

        templetData.NODE_CLASS = ((this.config.useSelection) ? ((node.isSelected ? "nodeSel"+(node.isAuthorized?"":"UnAuthorized") : "node"+(node.isAuthorized?"":"UnAuthorized"))) : "node");

        this.aTreeHtml.push(this.template.evaluate(templetData));

        if (node.hasLeaf)
        {
            this.aTreeHtml.push("<div id=\"d" + this.obj + nodeId + "\" class=\"dtree\" style=\"display:"
                            + ((this.root.nodeId == node.parentNodeId || node.isOpen) ? "block" : "none") + " ;\">");

            // Check show status of child nodes
            if( (this.root.nodeId == node.parentNodeId || node.isOpen) )
            {
                this.aNodes[nodeId].isShow = true;
                var arrCn = this.cNodes[node.nodeId];
                if( arrCn )
                    for( var j=0; j < arrCn.length; j++ )
                    {
                        this.aNodes[this.aIndex[arrCn[j]]].isShow = true;
                    }
            }

            this.addNodeUI(node);
            this.aTreeHtml.push("</div>");
        }

        this.aIndent.pop();
        //return str;
    },

    // Adds the empty and line icons
    indent : function(node, nodeId)
    {
        var str = '';
        if (this.root.nodeId != node.parentNodeId)
        {
            for (var i=0; i<this.aIndent.length; i++)
            {
                str += '<img src="' + ( (this.aIndent[i] == 1 && this.config.useLines) ? this.icon.line : this.icon.empty ) + '"/>';
            }

            (node.isLastInLevel) ? this.aIndent.push(0) : this.aIndent.push(1);
            if (node.hasLeaf)
            {
                str += '<img id="j' + this.obj + nodeId + '" src="';
                if (!this.config.useLines) str += (node.isOpen) ? this.icon.nlMinus : this.icon.nlPlus;
                else str += ( (node.isOpen) ? ((node.isLastInLevel && this.config.useLines) ? this.icon.minusBottom : this.icon.minus) : ((node.isLastInLevel && this.config.useLines) ? this.icon.plusBottom : this.icon.plus ) );
                str += '" alt="" onclick="' + this.obj + '.toggle(' + nodeId + ')" style="cursor:pointer"/>';
            }
            else str += '<img src="' + ( (this.config.useLines) ? ((node.isLastInLevel) ? this.icon.joinBottom : this.icon.join ) : this.icon.empty) + '" alt="" style="cursor:pointer" />';
        }
        return str;
    },

    // Checks if a node has any children and if it is the last sibling
    setCS : function()
    {
        var arrCn;
        for( var property in this.cNodes )
        {
            if( this.root.nodeId == property )
                continue;

            arrCn = this.cNodes[property];
            if( arrCn )
            {
                if( arrCn.length > 0 )
                    this.aNodes[this.aIndex[property]].hasLeaf = true;
                    this.aNodes[this.aIndex[arrCn[arrCn.length-1]]].isLastInLevel = true;
            }
        }
    },

    // Returns the selected node
    getSelected : function()
    {
        var sn = this.getCookie('cs' + this.obj);
        return (sn) ? sn : null;
    },

    // Highlights the selected node
    setSelected : function(id)
    {
        if (!this.config.useSelection) return;
        var cn = this.aNodes[id];

        if (cn.hasLeaf && !this.config.folderLinks) return;

        if (this.selectedNode || this.selectedNode==0)
        {
            var eOld = $("n" + this.obj + this.selectedNode);
            eOldAuth = this.aNodes[this.selectedNode];
            eOld.className = "node" + (eOldAuth.isAuthorized?"":"UnAuthorized");
        }
        eNew = $("n" + this.obj + id);
        eNewAuth = this.aNodes[id];
        eNew.className = "nodeSel" + (eNewAuth.isAuthorized?"":"UnAuthorized");
        this.selectedNode = id;

        if (this.config.useCookies) this.setCookie('cs' + this.obj, cn.nodeId);
    },

    // Focus on selected node
    setFocus : function(nodeId)
    {
        try
        {
            var cn = this.aNodes[this.aIndex[nodeId]];
            var selObj = $("n" + this.obj + this.aIndex[nodeId]);
            selObj.focus();
            selObj.scrollIntoView();
        }
        catch(e) {}
    },

    // Toggle Open or close
    toggle : function(id)
    {
        var cn = this.aNodes[id];
        this.nodeStatus(!cn.isOpen, id, cn.isLastInLevel);
        cn.isOpen = !cn.isOpen;
        if (this.config.closeSameLevel) this.closeLevel(cn);
        if (this.config.useCookies) this.updateCookie();
    },

    // Sets node's object.
    setSelection : function(flag)
    {
        var nodeObj = this.aNodes[this.selectedNode];
        if (typeof nodeObj != "undefined" && flag)
        {
            this.selection.nodeId = nodeObj.nodeId;
            this.selection.parentNodeId = nodeObj.parentNodeId;
            this.selection.nodeName = nodeObj.nodeName;
            this.selection.nodeType = nodeObj.nodeType;
            this.selection.webviewFlag = nodeObj.webviewFlag;
            this.selection.nodeDepth = nodeObj.nodeDepth;
            this.selection.sortOrder = nodeObj.sortOrder;
            this.selection.domainId = nodeObj.domainId;
            this.selection.isAuthorized = nodeObj.isAuthorized;
            this.selection.isOpen = nodeObj.isOpen;
            this.selection.hasLeaf = nodeObj.hasLeaf;
            this.selection.parentNode = nodeObj.parentNode;
            this.selection.serviceType = nodeObj.serviceType;
       }
       else
       {
            this.selection.nodeId = "";
            this.selection.parentNodeId = "";
            this.selection.nodeName = "";
            this.selection.nodeType = "";
            this.selection.webviewFlag = "";
            this.selection.nodeDepth = "";
            this.selection.sortOrder = "";
            this.selection.domainId = "";
            this.selection.isAuthorized = false;
            this.selection.isOpen = false;
            this.selection.hasLeaf = false;
            this.selection.parentNode = "";
            this.selection.serviceType = "";
       }
    },

    // Click a node
    clickOnNode : function(nodeId, isLeftClick)
    {
        if ( this.selectedNode != null)
            this.aNodes[this.selectedNode].isSelected = false;

        this.setSelected(nodeId);
        if (this.aNodes[nodeId].isAuthorized)
        {
            this.setSelection(true);
            this.unfocusNode();
            if( isLeftClick != false) // null or true
            {
                if( this.treeSelectionListener )
                    this.treeSelectionListener(this.selection);
            }
        }
        else
        {
            this.setSelection(false);
        }
    },

    // Unfocus a node
    unfocusNode : function()
    {
        if (typeof treeArray != "undefined")
        {
            for (i=0; i<treeArray.length; i++)
            {
                if (this.obj != treeArray[i])
                {
                    selObj = eval(treeArray[i]).selection;
                    if (selObj.nodeId != null && selObj.nodeId != "")
                    {
                        var eOld = $("s" + treeArray[i] + eval(treeArray[i]).selectedNode);
                        eOldAuth = eval(treeArray[i]).aNodes[eval(treeArray[i]).selectedNode];
                        eOld.className = "nodeUnfocus" + (eOldAuth.isAuthorized?"":"UnAuthorized");
                        eval(treeArray[i]).setSelection(false);
                    }
                }
            }
        }
    },

    // DoubleClick a node
    dblClickOnNode : function(nodeId)
    {
        this.toggle(nodeId);
    },

    // Checks a node
    checkOnNode : function(obj, id)
    {
        var obj = $(this.obj + "_"  + this.aNodes[id].nodeId);
        this.aNodes[id].isChecked = obj.checked;

        if( this.aNodes[id].hasLeaf )
            this.checkChildNode(obj, this.aNodes[id], obj.checked);
    },

    checkChildNode : function(obj, node, checked)
    {
        /*for (var i=0; i<this.aNodes.length; i++)
        {
            if (this.aNodes[i].parentNodeId == node.nodeId)
            {
                if (this.aNodes[i].isAuthorized)
                    $( this.obj + "_"  + this.aNodes[i].nodeId ).checked = checked;
                this.checkChildNode(obj, this.aNodes[i], checked);
            }
        }*/
        var arrCn = this.cNodes[node.nodeId];
        var i=0;
        for (var j=0; j< arrCn.length; j++)
        {
            i = this.aIndex[arrCn[j]];
            if( this.aNodes[i].isAuthorized )
            {
               // $( this.obj + "_"  + this.aNodes[i].nodeId ).checked = checked;
                this.aNodes[i].isChecked = checked;
                if( this.aNodes[i].isShow  )
                {
                    $( this.obj + "_"  + this.aNodes[i].nodeId ).checked = checked;
                }
            }

            if( this.aNodes[i].hasLeaf )
                this.checkChildNode(obj, this.aNodes[i], checked);
        }
    },

    // Get checked node in checkbox.
    validateCheckedNode : function()
    {
        this.selections.nodeId = "";
        this.selections.nodeName = "";
        this.selections.parentNodeId = "";
        this.selections.nodeType = "";
        this.inspectNodeChecked(this.root);
    },

    // Inspect All of the node if node is checked.
    inspectNodeChecked : function(node)
    {
        var arrCn = this.cNodes[node.nodeId];
        var i=0;
        if( !arrCn ) return;

        for (var j=0; j< arrCn.length; j++)
        {
            i = this.aIndex[arrCn[j]];

            var obj = $( this.obj + "_"  + this.aNodes[i].nodeId );
            if (obj.checked)
            {
                var value = "";
                // Sets node'id.
                if (this.selections.nodeId == "")
                    this.selections.nodeId = this.aNodes[i].nodeId;
                else
                    this.selections.nodeId = this.selections.nodeId + this.checkedValueSeparator + this.aNodes[i].nodeId;

                // Sets node'name.
                if (this.selections.nodeName == "")
                    this.selections.nodeName = this.aNodes[i].nodeName;
                else
                    this.selections.nodeName = this.selections.nodeName + this.checkedValueSeparator + this.aNodes[i].nodeName;

                // Sets parent node'id.
                if (this.selections.parentNodeId == "")
                    this.selections.parentNodeId = this.aNodes[i].parentNodeId;
                else
                    this.selections.parentNodeId = this.selections.parentNodeId + this.checkedValueSeparator + this.aNodes[i].parentNodeId;

                // Sets node's type.
                if (this.selections.nodeType == "")
                    this.selections.nodeType = this.aNodes[i].nodeType;
                else
                    this.selections.nodeType = this.selections.nodeType + this.checkedValueSeparator + this.aNodes[i].nodeType;
            }
            this.inspectNodeChecked(this.aNodes[i]);
        }
    },

    // Open or close all nodes
    oAll : function(status)
    {
        for (var i=0; i<this.aNodes.length; i++)
        {
            if (this.aNodes[i].hasLeaf && this.aNodes[i].parentNodeId != this.root.nodeId)
            {
                this.nodeStatus(status, i, this.aNodes[i].isLastInLevel)
                this.aNodes[i].isOpen = status;
            }
        }
        if (this.config.useCookies) this.updateCookie();
    },

    openToCheckbox : function(idList, separator)
    {
        if (idList != "")
        {
            if( separator == null )
                separator = this.checkedValueSeparator;

            var arIdList = idList.split(separator);
            if (arIdList != null && arIdList.length > 0)
            {
                for (i=0; i<arIdList.length; i++)
                {
                    this.aNodes[this.aIndex[arIdList[i]]].isChecked = true;
                    this.openTo(arIdList[i], false, false);
                }
            }
        }
    },

    // Opens the tree to a specific node
    openTo : function(nId, bSelect, bFirst)
    {
        try
        {
            if (!bFirst)
            {
                nId = this.aIndex[nId];
            }

            var cn=this.aNodes[nId];

            if (cn.parentNodeId==this.root.nodeId || !cn.parentNode) return;
            if (cn.hasLeaf)
                cn.isOpen = true;
            cn.isSelected = bSelect;
            if (this.completed && cn.hasLeaf) this.nodeStatus(true, cn._ai, cn.isLastInLevel);
            if (this.completed && bSelect) this.setSelected(cn._ai);
            else if (bSelect) this._sn=cn._ai;
            this.openTo(cn.parentNode._ai, false, true);
        }
        catch(e) {}
    },

    initializeTree : function(treeId, selectedNodeId)
    {
        try
        {
            this.treeId = treeId;
            if (selectedNodeId != null && selectedNodeId.length > 0)
            {
                this.openTo(selectedNodeId, true, false);
                this.setFocus(selectedNodeId);
                this.setSelection(true);
            }
            this.aTreeHtml = new Array();
        }
        catch(e)
        {
            alert("TreeId[" + treeId + "] is not defined!");
        }
    },

    reloadTree : function(treeId, treeHtml)
    {
        if ($(treeId) != null)
            $(treeId).innerHTML = treeHtml;
    },

    selectAndClickOnNode : function(nodeId, id)
    {
        if (nodeId != null && nodeId.length > 0)
        {
            this.openTo(nodeId, true, false);
            this.setFocus(nodeId);
        }
        this.clickOnNode(id);
    },

    // Closes all nodes on the same level as certain node
    closeLevel : function(node)
    {
        for (var i=0; i<this.aNodes.length; i++)
        {
            if (this.aNodes[i].parentNodeId == node.parentNodeId && this.aNodes[i].nodeId != node.nodeId && this.aNodes[i].hasLeaf)
            {
                this.nodeStatus(false, i, this.aNodes[i].isLastInLevel);
                this.aNodes[i].isOpen = false;
                this.closeAllChildren(this.aNodes[i]);
            }
        }
    },

    // Closes all children of a node
    closeAllChildren : function(node)
    {
        for (var i=0; i<this.aNodes.length; i++)
        {
            if (this.aNodes[i].parentNodeId == node.nodeId && this.aNodes[i].hasLeaf)
            {
                if (this.aNodes[i].isOpen) this.nodeStatus(false, i, this.aNodes[i].isLastInLevel);
                this.aNodes[i].isOpen = false;
                this.closeAllChildren(this.aNodes[i]);
            }
        }
    },

    // Select all children of a node by a separator.
    selectAllChildNodeList : function(nodeId, separator)
    {
        this.childNodeList = "";
        return this.inspectAllChildNode(nodeId, separator);
    },

    inspectAllChildNode : function(nodeId, separator)
    {
        for (var i=0; i<this.aNodes.length; i++)
        {
            if (this.aNodes[i].parentNodeId == nodeId)
            {
                this.childNodeList = this.childNodeList + separator + this.aNodes[i].nodeId;
                this.inspectAllChildNode(this.aNodes[i].nodeId, separator);
            }
        }
        return this.childNodeList;
    },

    // Change the status of a node(open or closed)
    nodeStatus : function(status, id, bottom)
    {
        var cn = this.aNodes[id];
        if (cn.hasLeaf)
        {
            try
            {
                eDiv    = $('d' + this.obj + id);
                eJoin    = $('j' + this.obj + id);
                if (this.config.useIcons)
                {
                    eIcon    = $('i' + this.obj + id);
                    eIcon.src = (status) ? this.aNodes[id].iconOpen : this.aNodes[id].icon;
                }
                eJoin.src = (this.config.useLines)?
                ((status)?((bottom)?this.icon.minusBottom:this.icon.minus):((bottom)?this.icon.plusBottom:this.icon.plus)):
                ((status)?this.icon.nlMinus:this.icon.nlPlus);
                eDiv.style.display = (status) ? 'block': 'none';

                if( this.config.isCheckbox )
                {
                    if( cn.hasLeaf )
                    {
                        var arrCn = this.cNodes[cn.nodeId];
                        for( var i=0; i < arrCn.length; i++ )
                        {
                            cn = this.aNodes[this.aIndex[arrCn[i]]];
                            if( cn.isChecked )
                                $( this.obj + "_"  + cn.nodeId ).checked = true;
                            else
                                $( this.obj + "_"  + cn.nodeId ).checked = false;

                            if( status )
                                this.aNodes[this.aIndex[arrCn[i]]].isShow = true;
                            else
                                this.aNodes[this.aIndex[arrCn[i]]].isShow = false;
                        }
                    }
                }
            }
            catch(e) {}
        }
        else
        {
            if (this.config.useIcons)
            {
                //eIcon    = $('i' + this.obj + id);
                //eIcon.src = (status) ? this.aNodes[id].iconOpen : this.aNodes[id].icon;
            }
        }
    },

    // [Cookie] Clears a cookie
    clearCookie : function()
    {
        var now = new Date();
        var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);
        this.setCookie('co'+this.obj, 'cookieValue', yesterday);
        this.setCookie('cs'+this.obj, 'cookieValue', yesterday);
    },

    // [Cookie] Sets value in a cookie
    setCookie : function(cookieName, cookieValue, expires, path, domain, secure)
    {
        document.cookie =
            escape(cookieName) + '=' + escape(cookieValue)
            + (expires ? '; expires=' + expires.toGMTString() : '')
            + (path ? '; path=' + path : '')
            + (domain ? '; domain=' + domain : '')
            + (secure ? '; secure' : '');
    },

    // [Cookie] Gets a value from a cookie
    getCookie : function(cookieName)
    {
        var cookieValue = '';
        var posName = document.cookie.indexOf(escape(cookieName) + '=');
        if (posName != -1)
        {
            var posValue = posName + (escape(cookieName) + '=').length;
            var endPos = document.cookie.indexOf(';', posValue);
            if (endPos != -1) cookieValue = unescape(document.cookie.substring(posValue, endPos));
            else cookieValue = unescape(document.cookie.substring(posValue));
        }
        return (cookieValue);
    },

    // [Cookie] Returns ids of open nodes as a string
    updateCookie : function()
    {
        var str = '';
        for (var i=0; i<this.aNodes.length; i++)
        {
            if (this.aNodes[i].isOpen && this.aNodes[i].parentNodeId != this.root.nodeId)
            {
                if (str) str += '.';
                str += this.aNodes[i].nodeId;
            }
        }
        this.setCookie('co' + this.obj, str);
    },

    // [Cookie] Checks if a node id is in a cookie
    isOpen : function(id)
    {
        var aOpen = this.getCookie('co' + this.obj).split('.');
        for (var i=0; i<aOpen.length; i++)
            if (aOpen[i] == id) return true;
        return false;
    },

    /**
     * get parent node's path by separator.
     * range : CATEGR, DOMAIN, REGION, ALL
     */

    getNodePath : function(range)
    {
        var path = "";
        try
        {
            var range = range? range:this.NODE_TYPE.DOMAIN;
            var cn = this.aNodes[this.selectedNode];

            path = cn.nodeName;
            if (cn.parentNodeId == this.root.nodeId)
                return path;

            while (true)
            {
                if (range == this.NODE_TYPE.CATEGR && cn.parentNode.nodeType == this.NODE_TYPE.DOMAIN)
                {
                    break;
                }
                else if (range == this.NODE_TYPE.DOMAIN && cn.parentNode.nodeType == this.NODE_TYPE.REGION)
                {
                    break;
                }
                else
                {
                    if (cn.parentNode.parentNodeId == this.root.nodeId)
                    {
                        path = cn.parentNode.nodeName + this.config.nodePathDelimiter + path;
                        break;
                    }
                }
                path = cn.parentNode.nodeName + this.config.nodePathDelimiter + path;
                cn = cn.parentNode;
            }
        } catch (e) {}
        return path;
    },

    // get if node is leaf
    isLeaf : function()
    {
        var cn = this.aNodes[this.selectedNode];
        return !cn.hasLeaf;
    },

    // get child node List
    getChildNodes : function(nodeId)
    {
        return this.cNodes[nodeId];
    },

    //disable all of the node.
    disabledAllNode : function(obj)
    {
        for (var i=0; i<this.aNodes.length; i++)
        {
               nodeObj = this.aNodes[i];
            if (nodeObj.nodeType == this.NODE_TYPE.REGION)
            {
                nodeObj.icon = this.icon.regionUnauthorized;
                nodeObj.iconOpen = this.icon.regionOpenUnauthorized;
            }
            else if (nodeObj.nodeType == this.NODE_TYPE.DOMAIN)
            {
                nodeObj.icon = this.icon.domainUnauthorized;
                nodeObj.iconOpen = this.icon.domainOpenUnauthorized;
            }
            else
            {
                nodeObj.icon = this.icon.folderUnauthorized;
                nodeObj.iconOpen = this.icon.folderOpenUnauthorized;
            }
            nodeObj.isAuthorized = false;
            nodeIconObj = $("i" + obj + i);
            if (nodeObj.isOpen)
                nodeIconObj.src = nodeObj.iconOpen;
            else
                nodeIconObj.src = nodeObj.icon;
        }
    },

    // Gets node's default parameter. ex)nodeId=NODE0000000007&nodeName=%EC%97%85%EB%AC%B4%EA%B4%80%EB%A0%A8&parentNodeId=NODE0000000006&nodeType=1&&nodeDepth=2&sortOrder=0)
    getNodeParam : function(nodeObj)
    {
        var param = "";
        if (typeof nodeObj != "undefined")
        {
            param = "nodeId=" + nodeObj.nodeId;
              param += "&nodeName=" + encodeURIComponent(nodeObj.nodeName);
              param += "&parentNodeId=" + nodeObj.parentNodeId;
            if (nodeObj.nodeType == this.NODE_TYPE.REGION)
                  param += "&nodeType=0";
            else if (nodeObj.nodeType == this.NODE_TYPE.DOMAIN)
                param += "&nodeType=1";
            else if (nodeObj.nodeType == this.NODE_TYPE.CATEGR)
                param += "&nodeType=2";
              param += "&nodeDepth=" + nodeObj.nodeDepth;
              param += "&sortOrder=" + nodeObj.sortOrder;
              param += "&domainId=" + nodeObj.domainId;
            param += "&serviceType=" + nodeObj.serviceType;

        }
        return param;
    },

    // Opens the tree from a specific node to terminal
    openFrom : function(nodeId)
    {
        try
        {
            for (var i=0; i<this.aNodes.length; i++)
            {
                if (this.aNodes[i].nodeId == nodeId)
                {
                    if (this.aNodes[i].hasLeaf)
                        this.nodeStatus(true, this.aNodes[i]._ai, this.aNodes[i].isLastInLevel);
                    else
                        return;
                }
            }

            var node;
            var pNode;
            for (var i=0; i<this.aNodes.length; i++)
            {
                node = this.aNodes[i];
                pNode = this.aNodes[i].parentNode;
                if (typeof pNode != "undefined" && pNode.nodeId == nodeId)
                {
                    this.nodeStatus(true, this.aNodes[i]._ai, this.aNodes[i].isLastInLevel);
                    this.openFrom(this.aNodes[i].nodeId);
                }
            }
        }
        catch(e) {}
    },

    onMouseOutMenu : function()
    {
        var contextMenuId = "ContextMenuId";
        if ( $(contextMenuId) != null )
            $(contextMenuId).style.display = "none";
    },

    onMouseOverMenu : function()
    {
        var contextMenuId = "ContextMenuId";
    },

    onContextMenu : function(e, nodeId)
    {
        try
        {
            var e = e? e: event;
            this.clickOnNode(nodeId, Event.isLeftClick(e));

            var functionContextMenu = eval( this.obj + "_onContextMenu");
            if( functionContextMenu )
            {
                functionContextMenu.call(null, e, this.selection);
            }
        }
        catch(e) {}
        return false;
    },

    // Generates a unique nodeId.
    getTempNodeId : function()
    {
        var today = new Date();
        var random = Math.random() * 1000000000;
        //var date = + today.getYear() + today.getMonth() + today.getDate() + today.getHours() + today.getMinutes() + today.getSeconds();
        var nodeId = "_NODE"  + random;
        return nodeId;
    },

    addCategory : function(id, nodeType, webviewFlag, serviceType)
    {
        var nodeId = this.getTempNodeId();
        var pNode = this.aNodes[id];

        for (var i=0; i<this.aNodes.length; i++)
        {
            if (this.aNodes[i] != null &&  (this.aNodes[i].parentNodeId == pNode.nodeId) )
            {
                this.aNodes[i].isLastInLevel = false;
            }
        }

        var nodeType = nodeType? nodeType:this.NODE_TYPE.CATEGR;
        var webviewFlag = webviewFlag? webviewFlag:"N";
        var nodeName = this.property.newCategoryName;
        switch(nodeType)
        {
            case this.NODE_TYPE.REGION :
                nodeName = this.property.newRegionName;
                break;
            case this.NODE_TYPE.DOMAIN :
                nodeName = this.property.newDomainName;
                break;
            case this.NODE_TYPE.ACCGRP :
                nodeName = this.property.newGroupName;
                break;
        }
        var serviceType = serviceType? serviceType: this.SERVICE_TYPE.COMMON;

        this.add(nodeId, pNode.nodeId, nodeName, nodeType, webviewFlag, (pNode.nodeDepth+1), 1, pNode.domainId, true, serviceType);
        this.reloadTree(this.treeId, this.toString());
        this.initializeTree(this.treeId, nodeId);

        var newId = this.aNodes.length-1;

        var selObj = $("inputNodeId" + this.obj + newId);
        var inputHtml = "<input id=\"newCategory" + this.obj + newId + "\" name=\"newCategory" + this.obj + newId + "\" value=\"" + nodeName + "\" ";
        inputHtml += "maxlength=\"20\" ";
        inputHtml += "onblur=\"javascript:"+this.obj+".onBlurAddNodeInput(" + newId + ")\" ";
        inputHtml += "onkeydown=\"javascript: "+this.obj+".onKeyPressAddNodeInput(event, " + newId + ")\" ";
        inputHtml += "style=\"padding: 0px;width:100px; height: 14px; font-family: arial; font-size:8pt; color:#FFFFFF; background-color:#316AC5; border:1px #CCCCCC solid;\" ";
        inputHtml += "onselectstart=\"return true\" ";
        inputHtml += ">";

        selObj.innerHTML = inputHtml;
        var nodeTextObj = $("n" + this.obj + newId);
        nodeTextObj.style.display = "none";
        this.property.keypressCount = 0;
        var newNodeObj = $("newCategory" + this.obj + newId);
        newNodeObj.select();
        newNodeObj.focus();
    },

    // This fires when the user presses a key on a inputbox(nodeName).
    onKeyPressAddNodeInput : function(e, id)
    {
        var newNodeObj = $("newCategory" + this.obj + id);
        var e = e? e:event;

        if (e.keyCode == 13)
        {
            newNodeObj.blur();
            return;
        }
        if (this.property.keypressCount == 0)
        {
            newNodeObj.value = "";
        }
        this.property.keypressCount++;
        newNodeObj.style.color = "#000000";
        newNodeObj.style.backgroundColor = "#FFFFFF";
    },

    // This causes the inputbox(nodeName) to lose focus and fires the onblur event.
    onBlurAddNodeInput : function(id)
    {
        var newNodeObj = $("newCategory" + this.obj + id);
        this.aNodes[id].nodeName = newNodeObj.value;
        var nodeTextObj = $("n" + this.obj + id);
        if ( this.aNodes[id].nodeName.strip() == "" )
        {
            alert(Lang.tree.please_input_category_name);
            newNodeObj.select();
            return;
        }

        nodeTextObj.innerHTML = newNodeObj.value;
        nodeTextObj.style.display = "";
        newNodeObj.style.display = "none";

        var nodeObj = this.aNodes[id];
        // Ajax Process
        if( this.clickAddNodeAsEventListener )
            this.clickAddNodeAsEventListener(nodeObj, id);
    },

    // Modify a category.
    modifyCategory : function(id)
    {
        if (this.aNodes[id] != null ) // && this.aNodes[id].nodeType == this.NODE_TYPE.CATEGR)
        {
            var selObj = $("inputNodeId" + this.obj + id);
            var inputHtml = "<input id=\"inputModifyNodeId" + this.obj + id + "\" name=\"inputModifyNodeId" + this.obj + id + "\" value=\"" + this.aNodes[id].nodeName + "\" ";
            inputHtml += "maxlength=\"20\" ";
            inputHtml += "onblur=\"javascript:"+this.obj+".onBlurModifyNodeInput(" + id + ")\" ";
            inputHtml += "onkeydown=\"javascript:"+this.obj+".onKeyPressModifyNodeInput(event, " + id + ")\" ";
            inputHtml += "style=\"padding: 0px;width:100px; height: 14px; font-family: arial; font-size:8pt; color:#FFFFFF; background-color:#316AC5; border:1px #CCCCCC solid;\" ";
            inputHtml += "onselectstart=\"return true\" ";
            inputHtml += ">";
            //var inputObj = document.createElement(inputHtml);
            //selObj.appendChild(inputObj);
            selObj.innerHTML = inputHtml;

            var nodeTextObj = $("n" + this.obj + id);
            nodeTextObj.style.display = "none";

            this.property.keypressCount = 0;
            var modifyNodeObj = $("inputModifyNodeId" + this.obj + id);
            modifyNodeObj.select();
        }
    },

    // This fires when the user presses a key on a inputbox(nodeName).
    onKeyPressModifyNodeInput : function(e, id)
    {
        var e = e? e:event;

        var inputObj = $("inputModifyNodeId" + this.obj + id);
        var nodeTextObj = $("n" + this.obj + id);

        if (e.keyCode == 13) // enter
        {
            inputObj.blur();
            return;
        }

        if (this.property.keypressCount == 0 && e.keyCode > 40 && e.keyCode < 37)
        {
            inputObj.value = "";
        }

        this.property.keypressCount++;
        inputObj.style.color = "#000000";
        inputObj.style.backgroundColor = "#FFFFFF";
    },

    // This causes the inputbox(nodeName) to lose focus and fires the onblur event.
    onBlurModifyNodeInput : function(id)
    {
        var inputObj = $("inputModifyNodeId" + this.obj + id);
        var nodeTextObj = $("n" + this.obj + id);
        if ( inputObj.value.strip() == "")
        {
            alert(Lang.tree.please_input_category_name);
            inputObj.select();
            return;
        }
        nodeTextObj.innerHTML = inputObj.value;
        nodeTextObj.style.display = "";
        inputObj.style.display = "none";
        var selObj = $("inputNodeId" + this.obj + id);
        selObj.innerHTML = "";
        this.aNodes[id].nodeName = inputObj.value;

        var nodeObj = this.aNodes[id];

        if( this.clickModifyNodeAsEventListener )
            this.clickModifyNodeAsEventListener(nodeObj, id);
    },

    // Deletes a category.
    deleteCategory : function(id)
    {
        //var check = confirm(Lang.tree.confirm_delete_category_recursively);
        //if (check)
        //{
            if (this.aNodes[id] != null)
            {
                var parentNodeId = this.aNodes[id].parentNode.nodeId;
                this.deleteNode(id);
                this.reloadTree(this.treeId, this.toString());
                this.initializeTree(this.treeId, parentNodeId);
            }
        //}
    },

    deleteNode : function(id)
    {
        parentNode = this.aNodes[id].parentNode;
        var iLeafCount = 0;

        var nodeObj = this.aNodes[id];
        if( this.clickDeleteNodeAsEventListener )
            this.clickDeleteNodeAsEventListener(nodeObj, id);

        // Check Child Node of Parent Node
        for (var i=0; i<this.aNodes.length; i++)
        {
            if (this.aNodes[i].parentNodeId == parentNode.nodeId)
                   iLeafCount++;
               if (iLeafCount > 1)
                   break;
        }

        if (iLeafCount <= 1)
        {
            parentNode.isOpen = false;
            parentNode.hasLeaf = false;
        }

        // Check Child Node of Self Node
        this.deleteSelfNode(nodeObj.nodeId);

        this.aNodes = this.aNodes.compact();
        for (var i=0; i<this.aNodes.length; i++)
        {
            this.aIndex[this.aNodes[i].nodeId] = i;
        }
        //parentNode._ai = parentNode._ai - 1;
        //for (i=id+1; i<this.aNodes.length; i++)
            //this.aNodes[i-1] = this.aNodes[i];
        //this.aNodes.pop(); // Deletes the last element in Array and reduce size.
    },

    deleteSelfNode : function(nodeId)
    {
        var arrCn = this.cNodes[nodeId];

        if( arrCn )
        {
            for( var j=0; j < arrCn.length; j++ )
            {
               this.deleteSelfNode(arrCn[j]);
            }
        }

        this.deleteSelfParentNode(nodeId);
        this.aNodes[this.aIndex[nodeId]] = null;
    },

    deleteSelfParentNode : function(nodeId)
    {
        var parentNodeId = this.aNodes[this.aIndex[nodeId]].parentNodeId;
        var arrCn = this.cNodes[parentNodeId];
        arrCn = arrCn.without(nodeId);

        if( arrCn.length == 0 )
            this.cNodes[parentNodeId] = null;
        else
            this.cNodes[parentNodeId] = arrCn;
    },

    searchNodeByName : function(nodeName, nodeType)
    {
        var searchNodeType = nodeType? nodeType:this.NODE_TYPE.CATEGR;

        var searchNodeList = new Array();
        for (var i=0; i<this.aNodes.length; i++)
        {
            if ( this.aNodes[i].nodeName.indexOf(nodeName)>=0 && this.aNodes[i].nodeType==searchNodeType )
            {
                searchNodeList.push(this.aNodes[i]);
            }
        }
        if( searchNodeList.length>0 )
        {
            searchNodeList = this.sortNode(searchNodeList);
        }

        return searchNodeList;
    },

    sortNode : function(nodeList)
    {
        nodeList = nodeList.sortBy(
                function(node)
                {
                    var data = node.nodeName;
                    if( !isNaN(data) )
                        data = parseInt(data);
                    return data;
                }
            );
        return nodeList;
    },

    // new function by sungsi
    getNodeTypeByIndex : function(index)
    {
        return this.aNodes[index].nodeType;
    },

    getServiceTypeByIndex : function(index)
    {
        return this.aNodes[index].serviceType;
    }

};

