﻿//<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

/**
 *  GUI object Script for cross browser
 *
 *  author : Kim, Min Jong (pistos@qnsolv.com)
 *
 *  start date : 2003/06/04
 *
 *  version 0.1
 */
/**
 * Preference
 */
var client = navigator.appName == 'Microsoft Internet Explorer' ? "IE" : "NE";
/**
 * Nodes
 */
var nodes = new Array();
/**
 * Index of lastest node
 */
var lastestIdx = 0;
/*
 *  Tree class
 */

function Tree(tid, rootName)
{
   this.id = tid;
   this.iconNames = new Array('blank', //0
   'vertical_line', //1                     
   'closed_lastnode', //2  
   'closed_node', //3 
   'opened_lastnode', //4 
   'opened_node', //5 
   'lastnode', //6 
   'node', //7 
   'closed_default_folder', //8     
   'opened_default_folder', //9
   'leaf', //10
   'leaf_gray', //11
   'new');//12 
   /**
    * Icon Cache
    */
   this.icons = new Array();
   /**
    * Selection Model
    */
   this.SINGLE_TREE_SELECTION = 0;
   this.CONTIGUOUS_TREE_SELECTION = 1;
   this.DISCONTIGUOUS_TREE_SELECTION = 2;
   /**
    * Selection Mode
    */
   this.selectionMode = this.SINGLE_TREE_SELECTION;
   /**
    * Selected Node instance
    */
   this.selectedNode = new Array();
   
   /**
    * Modified Node instance
    */
   this.modifiedNode = new Array();
   
   /**
    * Opened Node
    */
   this.openedNode = null;
   /**
    * Background for unselected node
    */
   this.background = "#ffffff";
   /**
    * Foreground for unselected node
    */
   this.foreground = "#000000";
   /**
    * Background for selected node
    */
   this.selectedBackground = "navy";
   /**
    * Foreground for selected node
    */
   this.selectedForeground = "#ffffff";
   /**
    * Font size
    */
   this.fontSize = "11";
   /**
    * Font name
    */
   this.fontName = "arial";
   
   /**
    * Node width
    */
   this.nodeWidth = "120";
   
   
   
   /**
    * Directory for tree icon, must absolute path from webroot
    */
   this.iconDir = "http://img.imtel.com/images/treeicon/win2000";
   /**
    * Extension of icon file
    */
   this.iconExt = "png";
   /**
    * Icon width
    */
   this.iconWidth = "19";
   /**
    * Icon height
    */
   this.iconHeight = "16";
   /**
    * Table for this tree;
    */
   this.table = document.getElementById(tid);
   /**
    * Changed node list for repaint
    */
   this.changedNodes = new Array();
   /**
    * Root Node of tree
    */
   this.root = new TreeNode(rootName);
   /**
    * Preload icons
    */
   this.loadIcons = function()
   {
      for(var i = 0; i < this.iconNames.length; i++)
      {
         this.icons[i] = new Image();
         this.icons[i].src = this.iconDir + "/" + this.iconNames[i] + "." + this.iconExt;
      }
      this.BLANK_ICON = this.icons[0];
      this.VERTICAL_LINE_ICON = this.icons[1];
      this.CLOSED_LASTNODE_ICON = this.icons[2];
      this.CLOSED_NODE_ICON = this.icons[3];
      this.OPENED_LASTNODE_ICON = this.icons[4];
      this.OPENED_NODE_ICON = this.icons[5];
      this.LASTNODE_ICON = this.icons[6];
      this.NODE_ICON = this.icons[7];
      this.CLOSED_DEFAULT_FOLDER_ICON = this.icons[8];
      this.OPENED_DEFAULT_FOLDER_ICON = this.icons[9];
      this.LEAF_ICON = this.icons[10];
      this.LEAF_GRAY_ICON = this.icons[11];
      this.NEW_ICON = this.icons[12];
   }
   this.loadIcons();
   /**
    * paint tree
    */
   this.paint = function()
   {
      this.paintNodeForIE(this.root);
      
   }
   

   this.getRowIndexById = function(rowId)
   {
      var rows = this.table.childNodes;
      for(var i = 0; i < rows.length; i++)
      {
         if(rows[i].id == rowId)
         return i;
      }
      return - 1;
   }
   /**
    * repaint tree
    */
   this.repaint = function()
   {
      this.repaintForIE();
      this.changedNodes = new Array();
   }
   /**
    * repaint all
    */
   this.repaintAll = function()
   {
      if(client == "IE")
      {
         try
         {
            var size = this.table.rows.length;
            for(var j = 0; j < size; j++)
            {
               this.table.deleteRow(0);
            }
         }
         catch(exception)
         {
         }
         this.repaintNodeForIE(this.root, 0);
      }
	  	this.changedNodes = new Array();
   }
   
   this.repaintForIE = function()
   {
      for(var i = 0; i < this.changedNodes.length; i++)
      {
         var currentNode = this.changedNodes[i];
         //alert(currentNode.name);
         var rowId = "node" + currentNode.index;
         var nextRowId = - 1;
         var rowIndex1 = - 1;
         var rowIndex2 = - 1;
         if(currentNode != this.root)
         {
            rowIndex1 = this.table.rows[rowId].rowIndex;
            try
            {
               nextRowId = "node" + currentNode.parent.getChildAfter(currentNode).index;
               rowIndex2 = this.table.rows[nextRowId].rowIndex - 1;
               //alert("1 : "+rowIndex2);               
            }
            catch(exception)
            {
               try
               {
                  nextRowId = "node" + this.getNextOpenedAncestor(currentNode).index;
                  rowIndex2 = this.table.rows[nextRowId].rowIndex - 1;
               //alert("2 : "+rowIndex2);
               }
               catch(exception)
               {
                  //alert(exception.message+","+exception.line);
                  nextRowId = this.table.rows[this.table.rows.length - 1].id;
                  rowIndex2 = this.table.rows[nextRowId].rowIndex;
               //alert("3 : "+rowIndex2);
               }
            }
         }
         else 
         {
            rowIndex1 = 0;
            rowIndex2 = this.table.rows.length - 1;
         }
         try
         {
            for(var j = 0; j <(rowIndex2 - rowIndex1) + 1; j++)
            {
               this.table.deleteRow(rowIndex1);
            }
         }
         catch(exception)
         {
         }
         //alert(this.changedNodes[i].name);
         this.repaintNodeForIE(this.changedNodes[i], rowIndex1);
      }
   }

   /**
    * paint node
    */
   this.paintNodeForIE = function(node)
   {
      var newRow = this.table.insertRow(this.table.rows.length - 1);
      newRow.id = "node" + node.index;
      var newCell = newRow.insertCell();
      var renderString = this.leftSideForIE(node);
      newCell.innerHTML = renderString;
      for(var i = 0; i < node.children.length && node.isCollapsed == 0; i++)
      {
         this.paintNodeForIE(node.children[i]);
      }
   }

   
   /**
    * repaint node
    */
   this.repaintNodeForIE = function(node, index)
   {
      var newRow = this.table.insertRow(index);
      newRow.id = "node" + node.index;
      var newCell = newRow.insertCell();
      var renderString = this.leftSideForIE(node);
      newCell.innerHTML = renderString;
      for(var i = 0; i < node.children.length && node.isCollapsed == 0; i++)
      {
         //alert(node.children[i].name);
         if(i == 0)
         {
            this.repaintNodeForIE(node.children[i], index + 1);
         }
         else 
         {
            var rowId = null;
            try
            {
               rowId = "node" + this.getNextOpenedAncestor(node.children[i - 1]).index;
               this.repaintNodeForIE(node.children[i], this.table.rows[rowId].rowIndex);
            }
            catch(exception)
            {
               rowId = this.table.rows[this.table.rows.length - 1].id;
               this.repaintNodeForIE(node.children[i], this.table.rows[rowId].rowIndex + 1);
            }
         }
      }
   }
   
   /** 
   	* node width 지정
   	*/
   this.setNodeWidth = function(width)
   {
   		this.nodeWidth = width;
   }
   
   
   
   
   /**
    * generate leftside
    */
   this.leftSideForIE = function(node)
   {
      var renderString = "<table cellspacing=0 cellpadding=0><tr>";
	  // 1. leftside를 그린다.
      for(var i = 0; i < node.leftside.length; i++)
      {
         var iconSrc = this.BLANK_ICON.src;
         if(node.leftside[i] == 1) // 수직라인 아이콘을 그린다.
         {
            iconSrc = this.VERTICAL_LINE_ICON.src;
         }// 그렇지 않으면 빈칸을 그린다.
         renderString = renderString + "<td><IMG border='0' src='" + iconSrc + "' align='absmiddle'></td>";
      }
	  
	  // 2. 노드를 그린다.
	  // root가 아니면
      if(node != this.root)
      {
		 // 마지막 자식이면
         if(node.isLeaf())
         {
            var nodeIcon = this.LASTNODE_ICON;
            // 부모의 마지막 자식이 아니면 중간 가지 노드
			if(node.parent.getLastChild() != node)
            {
               nodeIcon = this.NODE_ICON;
            }
			// 부모의 마지막 자식이면 마지막 가지 노드
            renderString = renderString + "<td><IMG border='0' src='" + nodeIcon.src + "' align='absmiddle'></td>";
         }// 중간 노드이면
         else 
         {
            var nodeIcon = null;
			// 
			//document.write(node.isCollapsed+"<br>");
			// isCollapsed = 0 이면 확장된것
			//             = 1 이면 축소된것


            if(node.isCollapsed == 0) // 확장된 아이콘
            {
               nodeIcon = this.OPENED_LASTNODE_ICON;
               if(node.parent.getLastChild() != node)
               {
                  nodeIcon = this.OPENED_NODE_ICON;
               }
            }
            else // 축소된 아이콘
            {
               nodeIcon = this.CLOSED_LASTNODE_ICON;
               if(node.parent.getLastChild() != node)
               {
                  nodeIcon = this.CLOSED_NODE_ICON;
               }
            }
            
			renderString = renderString + "<td><IMG border='0' src='" + nodeIcon.src + "' onClick='nodes[" + node.index + "].tree.toggleNode(nodes[" + node.index + "]);' align='absmiddle'></td>";
         }
      }
	  // 3. 선택된 노드인지에 따라 그린다.
      var isSelectedNode = false;
      for(var i = 0; i < this.selectedNode.length; i++) {
         if(this.selectedNode[i] == node) isSelectedNode = true;
      }

	  // 3. 수정상태  노드인지에 따라 그린다.
      var isModifiedNode = false;
      for(var i = 0; i < this.modifiedNode.length; i++) {
         if(this.modifiedNode[i] == node) isModifiedNode = true;
      }
	  
	  
		  // 열려진 노드라면
	      if(this.openedNode == node)
	      {
	         var folderIcon = this.OPENED_DEFAULT_FOLDER_ICON;
	         if(node.icon != "")
	         {
	            folderIcon = new Image();
	            folderIcon.src = this.iconDir + "/opened_" + node.icon + "_folder." + this.iconExt;
	         }
	         if(node != this.root) {
		         renderString = renderString + "<td><IMG border='0' src='" + folderIcon.src + "' align='absmiddle' onClick='nodes[" + node.index + "].tree.treeSelectionListener(nodes[" + node.index + "],event)'></td>";
			 } else {
			     renderString = renderString + "<td><IMG border='0' src='" + folderIcon.src + "' align='absmiddle' onClick='nodes[" + node.index + "].tree.treeSelectionListener(nodes[" + node.index + "],event)'></td>";
			 }		
		  }
	      else // 닫혀진 노드라면
	      {
	         var folderIcon = this.CLOSED_DEFAULT_FOLDER_ICON;
	         if(node.icon != "") 
	         {
	            folderIcon = new Image();
	            folderIcon.src = this.iconDir + "/closed_" + node.icon + "_folder." + this.iconExt;
	         }
	         if(node != this.root) {
		         renderString = renderString + "<td><IMG border='0' src='" + folderIcon.src + "' align='absmiddle' onClick='nodes[" + node.index + "].tree.toggleNode(nodes[" + node.index + "]);nodes[" + node.index + "].tree.treeSelectionListener(nodes[" + node.index + "],event)'></td>";
			 } else {
			     renderString = renderString + "<td><IMG border='0' src='" + folderIcon.src + "' align='absmiddle' onClick='nodes[" + node.index + "].tree.treeSelectionListener(nodes[" + node.index + "],event)'></td>";
			 }		 
	      }
      
      var fg = this.foreground;
      var bg = this.background;
      if(isSelectedNode && !isModifiedNode) {
         fg = this.selectedForeground;
         bg = this.selectedBackground;
      }
      
      var border = "border:0;height:14;padding:0;cursor:hand;", readonly = "readonly";
      if (isModifiedNode) {
      	border = "border:1px solid #000000;height:17;padding:0;";
      	readonly = "onload=this.focus();";
      }
	  
	  var node_width = this.nodeWidth - (node.leftside.length * 19);
	  if (node.isNew) node_width -= 12;
	  // 최종적으로 <span></span>으로 처리된 구역을 클릭했을때 다음과 같은 메소드를 부른다.

      renderString = renderString + "<td title='"+ node.name+"'>" + (node.isNew?"<IMG border='0' src='" + this.NEW_ICON.src + "' align='abstop'> ":"") + "<input onKeyup='chkExecuteModifyKeyCode(nodes[" + node.index + "],this);' onchange='exeuteModify(nodes[" + node.index + "],this)' name='txtNode" + node.index + "' type=text " + readonly + " style='" + border + "width:" + node_width + ";overflow:hidden;text-overflow:ellipsis;color:" + fg + ";background-color:" + bg + ";font-size:" + this.fontSize + ";font-family:" + this.fontName + ";' " 
	  if (!isModifiedNode) {
		  if(!node.isLeaf() && node != this.root && node.isCollapsed) 
		        renderString += " onClick='nodes[" + node.index + "].tree.toggleNode(nodes[" + node.index + "]);nodes[" + node.index + "].tree.treeSelectionListener(nodes[" + node.index + "],event)' "  
		  else       	  
		      	renderString += " onClick='nodes[" + node.index + "].tree.treeSelectionListener(nodes[" + node.index + "],event)' "
	  }
	  renderString += " value=\"" + node.name + "\"></td>";
	  
	  if(node.tree.id == 'lastlog' && node != this.root && nodes[node.index].get("code") != '0') {
		  renderString += "<td><span style=cursor:hand onClick='nodes[" + node.index + "].tree.removeNode(nodes[" + node.index + "])'><b>x</b></span></td>";
	  }  
	  renderString = renderString + "</tr></table>";
	  return renderString;
   }


   /**
    * Returns next opened ancestor
    */
   this.getNextOpenedAncestor = function(node)
   {
      if(client == "IE")
      return this.getNextOpenedAncestorForIE(node);

	  else 
      return null;
   }
   this.getNextOpenedAncestorForIE = function(node)
   {
      var rowId = this.table.rows["node" + node.index].rowIndex;
      var nextNode = null;
      for(var i = rowId + 1; i < this.table.rows.length; i++)
      {
         var temp = nodes[this.table.rows[i].id.substring(4, this.table.rows[i].id.length)];
         //alert(node.name+","+temp.name);
         //alert(temp.parent);
         if(temp.parent==null)continue;
         if(!node.isAncestor(temp)&&!temp.isAncestor(node))
         {
            nextNode = temp;
            break;
         }
      }
      return nextNode;
   }

   /**
    * Returns the number of rows that are currently being displayed.
    */
   this.getRowCount = function()
   {
      if(client == "IE")
      return this.getRowCountForIE();
      else 
      return null;
   }
   
   this.getRowCountForIE = function()
   {
      return this.table.rows.length;
   }
   
      
   /**
    * Returns the path to the first selected node.
    */
   this.getSelectionPath = function()
   {
   }
   
   /**
    * Move node
    */
   this.moveNode = function(src, target)
   {
      src.parent.remove(src);
      target.add(src);
      tree.repaint();
   }
   /**
    * Copy node
    */
   this.copyNode = function(src, target)
   {
      var newNode = src.clone();
      target.add(newNode);
   }
   /**
    * Returns true if the node at the specified display row is collapsed.
    */
	// collapsed 0: 확장 1:축소
   this.isCollapsed = function(index)
   {
      if(client == "IE")
      return this.isCollapsedForIE(index);
      else 
      return null;
   }
   this.isCollapsedForIE = function(index)
   {
      var id = this.table.rows[index].id;
      id = id.substring(4, id.length);
      return nodes[id].isCollapsed ? true : false;
   }

   /**
    * Returns true if the node at the specified display row is currently expanded.
    */
   this.isExpanded = function(index)
   {
      if(client == "IE")
      return this.isExpandedForIE(index);
      else 
      return null;
   }
   this.isExpandedForIE = function(index)
   {
      var id = this.table.rows[index].id;
      id = id.substring(4, id.length);
      return nodes[id].isCollapsed ? false : true;
   }
   
   /**
    * Returns true if the node at the specified display row is currently selected
    */
   this.isSelected = function(index)
   {
      if(client == "IE")
         return this.isSelectedForIE(index);
      else 
         return null;
   }
   this.isSelectedForIE = function(index)
   {
      var id = this.table.rows[index].id;
      id = id.substring(4, id.length);
      return nodes[id].isSelected() ? false : true;
   }

   /**
    * Ensures that the node in the specified row is expanded and viewable.
    */
   this.expandRow = function(index)
   {
   }

   /**
    * Ensures that the node identified by the specified path is expanded and viewable.
    */
   this.expandPath = function(path)
   {
   }

   /**
    * 
    */
   this.expandAll = function(){   	  
      this.root.expandDecendants();
   }
   
   /**
    * Returns true if the node identified by row is selected.
    */
   this.isRowSelected = function(index)
   {
      if(client == "IE")
      return this.isRowSelectedForIE(index);
      else 
      return null;
   }

   this.isRowSelectedForIE = function(index)
   {
      var id = this.table.rows[index].id;
      id = id.substring(4, id.length);
      return this.selectedNode == nodes[id] ? true : false;
   }

   /**
    * Removes the row at the index row from the current selection.
    */
   this.removeSelectionRow = function()
   {
   }
   /**
    * Selects the node at the specified row in the display.\
    */
   this.setSelectionRow = function(index)
   {
      if(client == "IE") this.setSelectionRowForIE(index);

   }
   this.setSelectionRowForIE = function(index)
   {
      var id = this.table.rows[index].id;
      id = id.substring(4, id.length);
      this.selectNode(nodes[id]);
   }

   /**
    * 기존에 선택된 노드를 해제한다.
    */
   this.unselectNode = function(node)
   {
      var newArray = new Array();
	  
      for(var i = 0; i < this.selectedNode.length; i++)
      {
         if(this.selectedNode[i] != node){
			 newArray[newArray.length] = this.selectedNode[i];
			
		 }else this.addChangedNode(node);
      }
      this.selectedNode = newArray;
   }

   /**
    * 노드를 선택한다.
    * Selects the specified node
    */
   this.selectNode = function(node, event) {
      //수정상태인 Node를 해제한다.
      for(var i = 0; i < this.modifiedNode.length; i++) {
         this.unmodifyNode(this.modifiedNode[i]);
      }
      this.unmodifyNode();
      
      if(this.selectionMode == this.SINGLE_TREE_SELECTION)
      {
      	 if(this.selectedNode[0] != null)
         {
						// this.unselectNode(node);
						this.addChangedNode(this.selectedNode[0]);
         }
         this.selectedNode[0] = node;
         this.openedNode = node;
		 
      }
      else 
      {
         var withCtrl = false;
         if(client == "IE")
         {
            try
            {
               if(event.ctrlKey) withCtrl = true;
            }
            catch(exceptoin)
            {
            }
         }

         if(withCtrl)
         {
            if(node.isSelected())
            {
               this.unselectNode(node);
            }
            else 
            {
               this.selectedNode[this.selectedNode.length] = node;
            }
         }
         else 
         {
            for(var i = 0; i < this.selectedNode.length; i++)
            {
               this.addChangedNode(this.selectedNode[i]);
            }
            if(this.openedNode != null) this.addChangedNode(this.openedNode);
            this.selectedNode = new Array();
            this.selectedNode[0] = node;
            this.openedNode = node;
         }
      }
      this.addChangedNode(node);
      this.repaint();
   }
   
   /**
    * 기존에 수정상태인 노드를 해제한다.
    */
   this.unmodifyNode = function(node)
   {
      var newArray = new Array();
	  
      for(var i = 0; i < this.modifiedNode.length; i++)
      {
         if(this.modifiedNode[i] != node){
			 newArray[newArray.length] = this.modifiedNode[i];
			
		 }else this.addChangedNode(node);
      }
      this.modifiedNode = newArray;
   }
   
   /**
    * 노드를 수정상태로 만든다.
    * Modify the specified node
    */
   this.modifyNode = function(node, event) {
	  this.modifiedNode[0] = node;
	  this.addChangedNode(node);
	  this.repaint();
	  document.all("txtNode" + this.modifiedNode[0].index).select();
   }

   /**
    * remove node from selected node
    */
   this.removeFromSelectedNode = function(node)
   {
      var newSelectedNodes = new Array();
      for(var i = 0; i < this.selectedNode.length; i++)
      {
         if(!node == this.selectedNode[i])
         {
            newSelectedNodes[newSelectedNodes.length] = this.selectedNode[i];
         }
      }
      this.selectedNode = newSelectedNodes;
   }

   /**
    *  open node
    */
   this.openNode = function(node)
   {
      if(this.openedNode != null) 
      	this.addChangedNode(this.openedNode);
      this.openedNode = node;
      this.addChangedNode(node);
   }

   /**
    * 자식노르를 확장 / 축소 시키는 버튼을 눌렀을때
	* 축소되었을때는 어떻게 해야하는가? 트리가 사라졌다.
    */
   this.toggleNode = function(node)
   {
	  // 0이면 확장, 1이면 축소시킨다.
      var newValue = node.isCollapsed == 0 ? 1 : 0;
	  //alert(newValue);

      node.isCollapsed = newValue;
      if(newValue == 1) // 축소시킬때
      {
		  // 선택한 것을 취소한다.
         var setSelected = false;
		 // ^^ 수정 2004/10/28 전득진 
		 //alert("축소");
		 // 수정끝

		 //alert(node.name);
         for(var i = 0; i < this.selectedNode.length; i++)
         {
            if(node.isAncestor(this.selectedNode[i]))
            {
				// -를 누른 노드가 부모노드이면 선택됐던 자식노드를 해제하고 상위노드를 선택한후
				// 그 노드를 클릭한 효과를 준다.
			   //document.all("msg_name").innerText = " ";
			   //document.all("msg_code").innerText = " ";
               //this.unselectNode(this.selectedNode[i]);
               setSelected = true;
			   if(this.selectionMode == this.SINGLE_TREE_SELECTION){
				    var newArray = new Array();
					this.selectedNode = newArray;
			   }
			   // ^^ 수정 200410
			   node.tree.treeSelectionListener(node);
            }
         }
		 // toggleNode 수정하느라 고생하였음...
		 if(this.selectionMode == this.SINGLE_TREE_SELECTION){
			if(setSelected) this.selectedNode[0] = node;
		 }else{
			if(setSelected) this.selectedNode[this.selectedNode.length] = node;
		 }
         if(this.openedNode != null && node.isAncestor(this.openedNode)) this.openNode(node);


      }else{
		//alert("확장");
	  }
      this.addChangedNode(node);
      this.repaint();
   }

   /**
    * add node to changed node
    */
   this.addChangedNode = function(node)
   {
      /*var newChangedNodes = new Array();
	    	for( var i=0; i<this.changedNodes.length; i++){
	    		if(!node.isAncestor(this.changedNodes[i])){
	    		    newChangedNodes[newChangedNodes.length] = this.changedNodes[i];
	    		}
	    	}
	    	this.changedNodes = newChangedNodes;*/
      if(!this.hasChangedAncestor(node)) this.changedNodes[this.changedNodes.length] = node;
   }

   /**
    * remove node from changed node
    */
   this.removeFromChangedNode = function(node)
   {
      var newChangedNodes = new Array();
      for(var i = 0; i < this.changedNodes.length; i++)
      {
         if(!node == this.changedNodes[i])
         {
            newChangedNodes[newChangedNodes.length] = this.changedNodes[i];
         }
      }
      this.changedNodes = newChangedNodes;
   }

   /**
    * Returns true if node has changed ancestor
    */
   this.hasChangedAncestor = function(node)
   {
      var tempNode = node;
      var hasChangedAncestor = false;
      while(tempNode != this.root)
      {
         tempNode = tempNode.parent;
         if(this.isChangedNode(tempNode))
         {
            hasChangedAncestor = true;
            break;
         }
      }
      return hasChangedAncestor;
   }

   /**
    * Returns true is node is changed
    */
   this.isChangedNode = function(node)
   {
      var isChanged = false;
      for(var i = 0; i < this.changedNodes.length; i++)
      {
         if(this.changedNodes[i] == node) isChanged = true;
      }
      return isChanged;
   }

   this.treeSelectionListener = function(node)
   {
      this.selectNode(node);
   }

   this.root.tree = this;
   this.root.depth = 0;
   this.root.isCollapsed = 0;
   //this.selectedNode[0] = this.root;
   this.paint();
}

/**
 *  TreeNode class
 */
function TreeNode(name,icon,type,isNew)
{
   /**
    * node index
    */
   this.index = lastestIdx++;
   nodes[this.index] = this;
   /**
    * Tree
    */
   this.tree = null;
   /**
    * Node name
    */
   this.name = name;
   
   /**
    * node type
    */
   if(type)
	   this.type = type;
   else
   	 this.type = "folder";
   	   
   
   /**
    * note isNew
    */
   if(isNew)
	   this.isNew = 1;
   else
   	 this.isNew = 0;
   	   
   
   /**
    * Depth of node
    */
   this.depth = - 1;
   /**
    * leftside icons ( 0 : blank, 1: vertical line )
    */
   this.leftside = new Array();
   /**
    * is Collapsed
    */
   this.isCollapsed = 1;
   /**
    * is child allow
    */
   this.isAllowsChildren = 0;
   /**
    * icon name
    */
   if(icon)
	   this.icon = icon;
   else
   	 this.icon = "";
   /**
    * parent node
    */
   this.parent = null;
   /**
    * children
    */
   this.children = new Array();
   /**
    * hashmap
    */
   this.extData = new HashMap();
   /**
    * Returns true if this node has no children.
    */
   this.isLeaf = function()
   {
      return this.children.length == 0 ? true : false;
   }
   /**
    * Returns true if this node is Ancestor of specified node
    */
   this.isAncestor = function(node)
   {
      //alert(this.name+","+node.name);
      if(node == this.tree.root)
      return false;
      var parent = node.parent;
      //alert(parent.name);
      var isAncestor = false;
      while(parent != this.tree.root)
      {
         if(parent == this)
         {
            isAncestor = true;
            break;
         }
         parent = parent.parent;
      }
      return isAncestor;
   }

   /**
    * Removes newChild from its parent and makes it a child of this node by adding it to the end of this node's child array.
    */
   this.add = function(child)
   {
      this.children[this.children.length] = child;
      child.tree = this.tree; // ?? 부모의 트리를 자식에게 복사한다.
      child.parent = this;
      child.depth = this.depth + 1; 


      if(this.depth > 0 || true) // root 이하의 노드라면 이하 수행
      {
         child.leftside = new Array(); // child의 leftSide의 의미는 무엇인가?
         for(var i = 0; i < this.leftside.length; i++) {
            child.leftside[i] = this.leftside[i];
		 }

		 // 상위에서 자식을 만들어서 붙이는 경우에는 바로 상위 부모의 자식노드는 항상 마지막 자식이다.
         if (this.depth > 0) child.leftside[child.leftside.length] = this.parent.getLastChild() == this ? 0 : 1;
      }

      child.fixDecendantsInfo();

	  // 왼쪽 vertical line 을 그려준다.
      if(this.getChildCount() > 1) this.children[this.children.length - 2].fixLeftsideOfChildren();
	  if(this.tree != null) this.tree.addChangedNode(this);
   }
   
   /**
    * Expand all children
    */
   this.expandChildren = function()
   {
   	  this.isCollapsed = 0;
      for(var i=0; i<this.children.length; i++){
         this.children[i].isCollapsed = 0;
      }
   }

   /**
    * Expand all Decendants
    */
   this.expandDecendants = function()
   {
   	  this.isCollapsed = 0;
      for(var i=0; i<this.children.length; i++){
         this.children[i].isCollapsed = 0;
         this.children[i].expandDecendants();
      }
   }
      
   /**
    * Fix depth of decendants
	* 자식들의 depth를 재정의 한다.
    */
   this.fixDecendantsInfo = function()
   {	  
      for(var i = 0; i < this.children.length; i++)
      {
         this.children[i].tree = this.tree;
         this.children[i].depth = this.depth + 1;
         this.children[i].leftside = new Array();
         for(var j = 0; j < this.leftside.length; j++)
         {
            this.children[i].leftside[this.children[i].leftside.length] = this.leftside[j];
         }
         this.children[i].leftside[this.children[i].leftside.length] = this.parent.getLastChild() == this ? 0 : 1;
         this.children[i].fixDecendantsInfo();
      }
   }

   /**
    * Fix Leftside of Children
	* 자식의 왼쪽 사이드를 재정의 한다.
    */
   this.fixLeftsideOfChildren = function()
   {
      this.fixLeftsideOfDescendants(this.depth, this.parent.getLastChild() == this ? 0 : 1);
   }
   this.fixLeftsideOfDescendants = function(depth, value)
   {
      for(var i = 0; i < this.children.length; i++)
      {
         this.children[i].leftside[depth - 1] = value;
         this.children[i].fixLeftsideOfDescendants(depth, value);
      }
   }
   /**
    * Removes aChild from this node's child array, giving it a null parent.
    */
   this.remove = function(node)
   {
      var newChildren = new Array();
      for(var i = 0; i < this.children.length; i++)
      {
         if(this.children[i] == node)
         {
            node.parent = null;
            node.depth = - 1;
            node.tree = null;
            this.tree.removeFromChangedNode(node);
            this.tree.removeFromSelectedNode(node);
            if(this.tree.openedNode == node)
            {
               this.tree.openedNode = null;
            }
         }
         else 
         {
            newChildren[newChildren.length] = this.children[i];
         }
      }
      this.children = newChildren;
      if(this.getChildCount() > 0) this.children[this.children.length - 1].fixLeftsideOfChildren();
      if(this.tree != null) this.tree.addChangedNode(this);
      tree.repaint();
   }
   /**
    * Removes all of this node's children, setting their parents to null.
    */
   this.removeAllChildren = function()
   {
      for(var i = 0; i < this.children.length; i++)
      {
         this.children[i].parent = null;
         this.children[i].depth = - 1;
         this.children[i].tree = null;
         this.tree.removeFromChangedNode(this.children[i]);
      }
      this.children = new Array();
      this.tree.addChangedNode(this);
   }
   /**
    * Removes the subtree rooted at this node from the tree, giving this node a null parent
    */
   this.removeFromParent = function()
   {
      this.parent.remove(this);
   }
   /**
    * Sort children
    */
   this.sortChild = function()
   {
   }
   /**
    * Returns true if node is selected
    */
   this.isSelected = function()
   {
      var isSelected = false;
      if(this.tree != null)
      {
         for(var i = 0; i < this.tree.selectedNode.length; i++)
         {
            if(this.tree.selectedNode[i] == this) isSelected = true;
         }
      }
      return isSelected;
   }
   /**
    * Returns true is node is opened
    */
   this.isOpened = function()
   {
      var isOpened = false;
      if(this.tree != null)
      {
         if(this.tree.openedNode == this) isOpened = true;
      }
      return isOpened;
   }
   /**
    * Returns the number of children of this node.
    */
   this.getChildCount = function()
   {
      return this.children.length;
   }
   /**
    * Returns the child in this node's child array that immediately follows aChild, which must be a child of this node.
    * if the specified child is the lastest node or is not child of this, returns null;
    */
   this.getChildAfter = function(node)
   {
      var cAfter = null;
      for(var i = 0; i < this.children.length - 1; i++)
      {
         if(this.children[i] == node) cAfter = this.children[i + 1];
      }
      return cAfter;
   }
   /** 
    * Returns the child in this node's child array that immediately precedes aChild, which must be a child of this node.
    * if the specified child is the first node or is not child of this, returns null;
    */
   this.getChildBefore = function(node)
   {
      var cBefore = null;
      for(var i = 1; i < this.children.length; i++)
      {
         if(this.children[i] == node) cBefore = this.children[i - 1];
      }
      return cBefore;
   }
   /**
    * Returns this node's first child.
    */
   this.getFirstChild = function()
   {
      return this.children[0];
   }
   /**
    * Returns this node's last child.
    */
   this.getLastChild = function()
   {
      return this.children[this.children.length - 1];
   }
   /**
    * Returns the child at the specified index in this node's child array.
    */
   this.getChildAt = function(index)
   {
      return this.children[index];
   }
   /**
    * Returns the index of the specified child in this node's child array.
    * if this node does not have the specified child, return -1
    */
   this.getIndex = function(node)
   {
      var index = - 1;
      for(var i = 0; i < this.children.length; i++)
      {
         if(this.children[i] == node) index = i;
      }
      return index;
   }
   /**
    * Returns the path from the root, to get to this node.
    */
   this.getPath = function()
   {
   }
   /**
    * Returns the root of the tree that contains this node.
    */
   this.getRoot = function()
   {
      return this.tree.root;
   }
   /**
    * Associates the specified value with the specified key in this map.
    */
   this.put = function(key, value)
   {
      this.extData.put(key, value);
   }
   /**
    * Returns the value to which the specified key is mapped in this identity hash map, or null if the map contains no mapping for this key
    */
   this.get = function(key)
   {
      var value = null;
      value = this.extData.get(key);
      return value;
   }

   /**
    * Removes key and value mappings from this map.
    */
   this.deleteKeyValue = function(key)
   {
	   this.extData.deleteKeyValue(key)
   }

   /**
    * Clone of this
    */
   this.clone = function()
   {
      var newNode = new TreeNode(this.name);
      newNode.icon = this.icon;
      newNode.isAllowChildren = this.isAllowChildren;
      newNode.extData = this.extData;
      for(var i = 0; i < this.getChildCount(); i++)
      {
         newNode.add(this.children[i].clone());
      }
      return newNode;
   }
}

function HashMap()
{  
   var size = 0;
   this.keys = new Array();
   this.values = new Array();
   /**
    * Removes all mappings from this map.
    */
   this.clear = function()
   {
	   this.keys = new Array();
	   this.values = new Array();
	   this.size = 0;
   }

   /**
    * Removes key and value mappings from this map.
    */
   this.deleteKeyValue = function(key)
   {
	   var tmpKeys = new Array();
	   var tmpValues = new Array();

	   for(var i=0;i<this.keys;i++){
		 if(this.keys[i] != key){
			tmpKeys[tmpKeys.length] = this.keys[i];
			tmpValues[tmpValues.length] = this.values[i];
		 }
	   }
	   this.keys = tmpKeys;
	   this.values = tmpValues;
	   this.size = tmpKeys.length;
   }

   /**
    * Returns true if this map contains a mapping for the specified key.
    */
   this.containsKey = function(key)
   {
	   for(var i=0;i<this.size;i++){
		 if(this.keys[i] == key){
			return true;
		 }
	   }
	   return false;
   }
   /**
    * Returns true if this map maps one or more keys to the specified value.
    */
   this.containsValue = function(value)
   {
	   for(var i=0;i<this.size;i++){
		 if(this.values[i] == value){
			return true;
		 }
	   }
	   return false;
   }
   /**
    * Returns true if this map contains no key-value mappings.
    */
   this.isEmpty = function()
   {
	   return this.size == 0;
   }
   /**
    * Associates the specified value with the specified key in this map.
    */
   this.put = function(key, value)
   {
      this.keys[this.keys.length] = key;
      this.values[this.values.length] = value;
	  this.size ++;
   }
   /**
    * Returns the value to which the specified key is mapped in this identity hash map, or null if the map contains no mapping for this key
    */
   this.get = function(key)
   {
      var value = null;
      for(var i = 0; i < this.keys.length; i++)
      {
         if(this.keys[i] == key) value = this.values[i];
      }
      return value;
   }
   /**
    * Returns the number of key-value mappings in this map.
    */
   this.size = function()
   {
	   return this.size;
   }
}

function ListItem()
{
}

function List(lid)
{
   var items = new Array();
   this.add = function(item)
   {
      this.items[this.items.length] = item;
   }
}

function TableRow()
{
   var columnNames = new Array();
   var columnValues = new Array();
}

function Table(tid)
{
   var columnNames = new Array();
   var rows = new Array();
}

function FormUtil()
{
   this.validate = function(form)
   {
   }
}

/**
 * agent_code 에 맞는 노드를 검색하여 넘긴다.
 * 노드 하나만 반환한다.
 */
function getNodeByCode(agent_code){
	//alert(agent_code);
	for(var i=0;i<nodes.length;i++){
		if(nodes[i].get("code") == agent_code){
			//alert("agent_code"+i);
			return i;
		}
	}
	return -1;
}

//선택한 노드의 정보를 반환 (조직도 그룹)
function getNodeInfo(){
	var sNav = (navigator.appVersion);
	var nPos = sNav.indexOf("NT 5.1; SV1")
	var nHeight = (nPos != -1)?446:426;
	var height = screen.height;
  var width = screen.width;
	var toppos = height/ 2 - nHeight/2;
	var leftpos = width/ 2 - 300/2;
	
	//open_win_center("/biz_tree.do?flag=select","","250",nHeight);
	//return;
	return showModalDialog("/biz_tree.do?flag=select_hor","","dialogWidth:256px;dialogHeight:"+ nHeight +"px;dialogTop:"+toppos+"px;dialogLeft="+leftpos+";center=yes; screenTop=yes; scrolling=no; status=no; help=no;");
}

//선택한 노드의 정보를 반환  (게시물 분류)
function getBBSCategoryNodeInfo(treeRight){
	var sNav = (navigator.appVersion);
	var nPos = sNav.indexOf("NT 5.1; SV1")
	var nHeight = (nPos != -1)?446:426;
	var height = screen.height;
  var width = screen.width;
	var toppos = height/ 2 - nHeight/2;
	var leftpos = width/ 2 - 300/2;
	return showModalDialog("/biz_tree.do?flag=select&treeRight=" + treeRight,"","dialogWidth:256px;dialogHeight:"+ nHeight +"px;dialogTop:"+toppos+"px;dialogLeft="+leftpos+";center=yes; screenTop=yes; scrolling=no; status=no; help=no;");
}


//노드를 받아 하위노드의 uid를 검색해서 tree index값을 리턴한다. 
function findNodeChildIndex(node, uid){
	var nNode=0, nodeIndex;
	if( node.get("uid") == uid ){
		nodeIndex = node.index;
		//alert("if="+node.name+"||index="+nodeIndex);
	} else {
		//alert("else="+node.name+"||index="+nodeIndex);
		//alert("children.length="+node.children.length);
		for( var i=0 ; i<node.children.length ; i++){
			nodeIndex=findNodeChildIndex(node.children[i],uid);
			if(nodeIndex) break;
		}
	}
	return nodeIndex;
}


//노드를 받아 하위노드의 uid와 bbs_cd를  검색해서 tree index값을 리턴한다. 
function findNodeChildIndexByBBSCdUid(node, uid, bbs_cd){
	var nNode=0, nodeIndex;
	if( node.get("uid") == uid && node.get("bbs_cd") == bbs_cd ){
		nodeIndex = node.index;
		//alert("if="+node.name+"||index="+nodeIndex);
	} else {
		//alert("else="+node.name+"||index="+nodeIndex);
		//alert("children.length="+node.children.length);
		for( var i=0 ; i<node.children.length ; i++){
			nodeIndex=findNodeChildIndexByBBSCdUid(node.children[i],uid,bbs_cd);
			if(nodeIndex) break;
		}
	}
	return nodeIndex;
}




//현재노드 부터 하위 노드의 합을 구한다.
function findNodeCountSum(node){
	var cnt = Number(node.get("cnt"));
	var cnt_child = 0;
	//alert("node="+node.name+"||cnt="+cnt);
	
	for( var i=0 ; i<node.children.length ; i++){
		cnt_child = Number(eval(findNodeCountSum(node.children[i]) + cnt_child));
	}
	//alert("ret||"+ node.name +"="+ eval(cnt+cnt_child) );
	var ret = cnt+cnt_child;
	node.name = node.name + "["+ ret +"]";
	//alert(node.name);
	return ret;
}


function getNodeName(node){
	var name = node.name;
	var spos = name.lastIndexOf("[");
	if(	spos >=0 )
		name = name.substring(0,spos);
	return name;
}

function setNodeName(node){
	var cnt = node.get("cnt");
	node.name = node.name+"["+ cnt +"]";
	return;
}



//현재 노드의 부모노드 갯수 /텝스 
function checkParentNode(node){
	var i=0;
	
	for(i=0; 0<1 ;i++){
		if( node.parent!= null){
			node = node.parent;
		}else{
			break;
		}
	}
	return i;
}


//현재 노드의 자식노트 최대 텝스 
function checkChildNode(node){
	var maxchild = 0;
	var nNode=0;
	if(node.children.length > 0) maxchild++;
	
	for( var i=0 ; i<node.children.length ; i++){
		nNode=checkChildNode(node.children[i]);
		nNode +=1;
		if( nNode> maxchild) maxchild = nNode
		//alert("name="+node.children[i].name + "||"+ nNode +"||"+ maxchild);
	}
	
	return maxchild;
}


/**
 *agent_name에 맞는 노드를 검색하여 넘긴다.
 */
function getNodeByName(agent_name){
	
	var nodearray = new Array();
	// 전체를 검색하므로 시간이 걸린다.
	for(var i=0;i<nodes.length;i++){
		if(nodes[i].name == agent_name){
			nodearray[nodearray.length] = nodes[i];
			//alert(agent_name + "  " +nodearray.length);
			return nodearray;
		}
	}
	return -1;	
}

/**
 * agent_name 에 중복되는 노드가 있는지 검색한다.
 */ 
function isSameName(agent_name){
	for(var i=0;i<nodes.length;i++){
		if(nodes[i].name == agent_name){
			return true;
		}
	}
	return false;	 
}


/** 
 * agent_code 에 중복되는 코드가 있는지 검색한다.
 */
function isSameCode(agent_code){
	for(var i=0;i<nodes.length;i++){
		if(nodes[i].get("code") == agent_code){
			return true;
		}
	}
	return false;
}

