var path = "static/taxtree/";
var viewer="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=genome&cmd=Retrieve&dopt=Overview&list_uids=";
var object_unit = "sequence";

var maxNodeId = 0;
var treeFX = 0;
var treeFY = 12;
var shiftX = 20;
var shiftY = 0;
var TopObj;
var root = new Node(0, null, 0);
var total_width = 0;
var parent_win =  parent.document.getElementById("tree_frame");

var isExplorer = (navigator.appName=="Microsoft Internet Explorer");

function Node(id, parent, dist, acc, label, highlight)
{
    this.id = id;
    this.parent = parent;
    this.dist = dist;
    this.accession = acc;
    this.label = label;
    this.leaves = 0;
    this.isopen = 1;          
    if(highlight) {
     this.highlight = highlight;
    }
    else {
     this.highlight = 0;
    }
    this.x = 0;
    this.y = 0;
    this.diameter = 0;
    this.level = 1000;

    this.Nodes = [];        

    if(id == 0) node_ids = [];
     node_ids[id] = this;
	
};


Node.prototype.add = function(dist, acc, label, highlight) 
{
  if(dist < 0) {
    dist = 0;
  }
   maxNodeId += 1;  
   node = new Node(maxNodeId, this, dist);
  if( acc ) {
    if(typeof(acc) == 'string') {
           maxNodeId += 1;  
           node.Nodes[0] = new Node(maxNodeId, this, 0, acc, label, highlight);
    }
    else {
      node.diameter = acc;
      node.label = label;
    }
    
  }
  else {
     node.label = label;
  }
  this.Nodes[this.Nodes.length] = node;
  return node;
};


function CalcYPos(node, offs, deep)
{
 if(node.id == 0) {
   total_width = 0;
 }
 var len = node.Nodes.length;
 if(len == 0 || node.isopen == 0) {
   if(node.isopen == 2) {
        total_width += 0.2;
        offs -= 0.4;
  }
  else {
     ++total_width;
   }
   node.y = offs;
   return offs;
 }
 else {
  var s1 = 0;
  var s2 = 0;
  var s3 = 0;
  for(var n = 0; n < len; ++n) {
    var r = CalcYPos(node.Nodes[n], total_width, deep);
    if(n == 0) s1 = r;
    s2 = r;
  }
  s3 = (s1 + s2) / 2;
  node.y = s3;  

  return s3;
 }
}

function NodeSortCallback(x1, x2) {
  return x2.d - x1.d;
};

function CalcXPos(node, dist) 
{
   var arr = new Array();
   var distlen = 0;
   if( node.id == 0 ) {
     dist = 0;
     treeFX = 0;
    }
    dist += node.dist;

    var len =  node.Nodes.length;
    if(len > 0) {       
        for (var n=0; n < node.Nodes.length; n++) {
            var a={"n":n, "d":0};
            a.d = CalcXPos(node.Nodes[n], dist);       
            distlen += a.d;
            arr[n] = a;
        }	
        distlen /= len;
   }
   else {
     if(node.accession) {
         //tlen =  (node.accession.length + node.label.length + 1) * 8;
      tlen =  (node.accession.length + 40 + 1) * 8;
      fx = (TopObj.offsetParent.offsetWidth - tlen) / dist ;
      if(treeFX == 0 || treeFX > fx) {
          treeFX = fx;
       }
     }
     distlen = dist ;   

   }
    node.x = dist;
    if(node.id == 0) {
    }
    return distlen;
};

function CalcLeaves(node) 
{
   var len = node.Nodes.length;
   if(len == 0 || node.isopen == 0) {
       node.leaves = 1;
  }   
  else {
   node.leaves = 0;
   for(var n=0; n < len; n++) {
        node.leaves += CalcLeaves(node.Nodes[n]);
   }
  }
   return node.leaves;
};

var lastinserted = null;
function DrawNodeLines(x0, y0, x1, y1)
{
    var obj = document.createElement("div");
    obj.style.position = "absolute";
    obj.style.fontSize = 0 ;
    obj.style.borderStyle = 'solid';
    obj.style.borderColor = 'navy'; 
    obj.style.borderWidth = 0;
    MoveNodeLines(obj, x0, y0, x1, y1);
    TopObj.insertBefore(obj, lastinserted);
    lastinserted = obj;
    return obj;
};

function MoveNodeLines(obj, x0, y0, x1, y1)
{
    var objstyle = obj.style
    objstyle.left = x0 + shiftX;
    objstyle.width = x1 - x0 ;
    objstyle.borderWidth = 0;
    if(y1 != y0) {
	objstyle.borderLeftWidth = 1;
     }
     if(y1 > y0) {    
	objstyle.top = y0 + shiftY;
	objstyle.height = y1 - y0 ;
	objstyle.borderBottomWidth = 1;
     }
     else if(y1 < y0) {
        if(isExplorer) {
	        objstyle.top = y1 + shiftY -1;
        }
        else {
	        objstyle.top = y1 + shiftY;
        }
	objstyle.height = y0 - y1 + 1;
	objstyle.borderTopWidth = 1;
     }
     else {
        if(isExplorer) {
        	objstyle.top = y1 + shiftY - 1;
        }
        else {
        	objstyle.top = y1 + shiftY;
        }
	objstyle.height = 0;
	objstyle.borderTopWidth = 1;
    }
};

function MoveNodeLines2(obj, x0, y0, x1, y1)
{
    obj.style.left = x0 + shiftX;
    obj.style.width = x1 - x0 ;
    if(y1 != y0) {
     }
     if(y1 > y0) {    
	obj.style.top = y0 + shiftY;
	obj.style.height = y1 - y0 ;
     }
     else if(y1 < y0) {
	obj.style.top = y1 + shiftY ;
	obj.style.height = y0 - y1;
     }
     else {
	obj.style.top = y1 + shiftY;
	obj.style.height = 0;
    }
};

function DrawObject(x, y, obj2)
{    
    var obj = document.createElement("div");
    TopObj.appendChild(obj);
    obj.style.position = "absolute";
    obj.style.left = (x + shiftX) ;
    obj.style.top = (y + shiftY);
    obj.appendChild(obj2);
	return obj;
};

function NodeClick2(){
 var id;
 if( event.srcElement.node ) {
  id = event.srcElement.node.id; 
  }
  else {
    id = event.srcElement.parentElement.node.id;
  }
  hidetip();
  Toggle(id);
};

  function NodeTooltip( e ) 
{
  var el;
  var node;

  if( e.target )  {
    el = e.target;
  }
  else {
    el = e.srcElement;
  }

  if( el.node ) {
   node = el.node;
  }     
   
   if(node.label) 
         showtip(this, e, node.label);

   MarkNodes(node);
}

function NodeClick(e)
{
  var el;
  var node;


  if( e.target )  {
    el = e.target;
  }
  else {
    el = e.srcElement;
  }

  if( el.node ) {
   node = el.node;
  }     

   id = node.id;
   isopen = node.isopen;
    
 
        var text = '<a href="javascript:hidetip();Toggle(' + id + ');">';
         if(isopen == 1) {
                text += 'Collapse';
        }
        else if(isopen == 2) {       
                Toggle(id, 1);
                return ;
        }
        else {
            Toggle( id );
            return;
        }

        text += '</a><br><a href="javascript:hidetip();Toggle(' + id + ', 1);">' +
        'Squeeze';
        text += '</a><br><a href="javascript:hidetip();Expand(' + id + ');">' +
        'Expand';
         showtip(this, e, text);
};

function NodeHidetip(e) 
{
 var node;
   if( e.srcElement ) {
     node =  e.srcElement.node;
  }  
  else {
    node = e.target.node;
  }   
  SetLineColor(node);
  hidetip();
}

function OutNode(node, x0, y0, depth) 
{

    var id = node.id;
    var x = Math.floor(node.x * treeFX + 0.5);
    var y = Math.floor(node.y * treeFY + 0.5);

    var len = node.Nodes.length;
    if( !depth ) {
      depth = 0;
    }
    if(node.id >= 0) {  
        if(node.id == 0) {
           x0 = x;
           y0 = y;
        }
       node.lines = DrawNodeLines(x0, y0, x, y); 		
       var obj_m = document.createElement("DIV");
 
       TopObj.appendChild(obj_m);
       var m_style = obj_m.style;
       m_style.position = "absolute";
       m_style.left = x0 + shiftX;
       m_style.top = y - 5 + shiftY;
       m_style.width = x - x0;
       m_style.fontSize = 0;
       m_style.height = 11;       
       if(len > 0) {
         obj_m.node = node;
         node.lines.node = node;
        if(obj_m.attachEvent) {
         if(node.leaves > 1) {
          obj_m.attachEvent('onclick', NodeClick);
          node.lines.attachEvent('onclick', NodeClick);
         }
         obj_m.attachEvent('onmouseover', NodeTooltip);
         obj_m.attachEvent('onmouseout', NodeHidetip);
        }
        else {
         if(node.leaves > 1) {
                 obj_m.setAttribute('onclick', 'NodeClick(event)');
        }
         obj_m.setAttribute('onmouseover', 'NodeTooltip(event)');
         obj_m.setAttribute('onmouseout', 'NodeHidetip(event)');
        }

       }
       node.m = obj_m;         
   }
   if(len == 0) {
       var b_img = document.createElement("img");
       b_img.setAttribute("src", path + "ball2.gif");
       b_img.setAttribute("border", "0");
       node.b = DrawObject(x + 1, y - 3, b_img);
       var obj_label;
       if(node.accession) {
          obj_label = document.createElement("a");
          obj_label.setAttribute("href", 
               "javascript:var win=window.open('" +
               viewer + 
	        + node.accession + "');");
          var label =  node.label;
          obj_label.appendChild(document.createTextNode(label));
          obj_label.setAttribute("title", label);
      }
      else if(node.label){
	 obj_label.appendChild(document.createTextNode(node.label));
      }
      if(obj_label) {
           obj_label.style.fontSize = 10;
           if(node.highlight) {
                obj_label.style.color = 'red';
           }
           else {
                obj_label.style.color = '#1B3E81';
           }
 	   node.obj_label =DrawObject(x + 10,
 			y - treeFY / 2, 			
 		        obj_label);
      }
   }
   else {
        if(node.isopen > 0)
              for(var n = 0; n < len ; n++) {
                 OutNode(node.Nodes[n], x, y, depth + 1);
              }
   } 
};


function MoveObject(obj, x, y)
{
	if( obj ) {
		obj.style.left = x + shiftX ;
		obj.style.top = y + shiftY ;
	}
};

function MoveNode(node, x0, y0, iscollapsed) 
{
 id = node.id;
 var x = Math.round(node.x * treeFX);
 var y = Math.round(node.y * treeFY);
 
 var len = node.Nodes.length; 

 if(id == 0) {
  x0 = x;
  y0 = y;
  iscollapsed = 0;
 }


 if( iscollapsed == 1 ) {

  if(node.lines) {
   node.lines.style.display = "none";
   node.m.style.display = "none";
   if(node.b) node.b.style.display = "none";
   if(node.plus) node.plus.style.display = "none";
   if(node.obj_label)node.obj_label.style.display = "none";
  }
 }
 else if(node.id >= 0 ) {
 if( !node.lines ) {
   OutNode(node, x, y, 1);
  }
   node.lines.style.display = "block";
   node.m.style.display = "block";
   if(node.b) node.b.style.display = "block";
   if(node.plus) {
     if(node.isopen == 0) {
              node.plus.style.display = "block"; 
     }
     else {
              node.plus.style.display = "none"; 
     }
 }


  MoveNodeLines(node.lines, x0, y0, x, y );
  if(node.m) node.m.style.width = x - x0 + 1;
  MoveObject(node.m, x0 , y - 5 );
 }
 else {
   iscollapsed = 0;
 }

 if(len == 0) {
  if(iscollapsed == 0) {
    if(node.obj_label)
  {
       var obj_label = node.obj_label;
        if(node.isopen == 1) {
                obj_label.style.display = "block";
                obj_label.firstChild.style.fontSize = 10;
                obj_label.firstChild.style.fontWeight = 'normal';
                MoveObject(node.b, x + 1, y - 3);
                MoveObject(obj_label, x + 10, y - treeFY / 2);
                obj_label.style.clip = 'rect(0, 999px, 14, 0)';

        }
        else if(node.isopen == 2){
                obj_label.style.display = "block";
                if(node.b) node.b.style.display = "none";
                 MoveObject(obj_label, x, y );
                 obj_label.firstChild.style.fontSize = 1;
                 obj_label.firstChild.style.fontWeight = 'bold';
                 obj_label.style.clip = 'rect(0, 999px, 2, 0)';
       }
  }

  }
 }
 else {
    if(node.isopen == 0) {
	 MoveObject(node.plus, x, y - 4 );
	iscollapsed = 1;
    }
	for(var n = 0; n < len ; n++) {
	  MoveNode(node.Nodes[n], x, y, iscollapsed);
	}
  }
};


function FindNode(id, node) 
{
return node_ids[id];
   var len = node.Nodes.length;
   if(node.id == id) {
       return node;
   }
   for(var n=0; n < len; n++) {
        node2 = FindNode(id, node.Nodes[n]);
        if(node2 != null) {
                return node2;
        }
   }
   return null;
};

function AddPlusSign(node)
{
   var obj_i = document.createElement("img");
  obj_i.src=path + "plus.gif";
  obj_i.setAttribute("border", "0");
  obj_i.setAttribute("align", "center");
  obj_i.title='Sequences:' + node.leaves + ' (Click to expand)'; 
  var x = Math.floor(node.x * treeFX + 0.5);
  var y = Math.floor(node.y * treeFY + 0.5);
  if(isExplorer) {
        var obj_a = document.createElement("a");
        obj_a.href = "javascript:Toggle(" + node.id + ")";
        obj_a.appendChild(obj_i);
         node.plus = DrawObject(x, y - 4, obj_a);
  }
  else {
          node.plus = DrawObject(x, y - 4, obj_i);
          node.plus.setAttribute('onclick', 'Toggle("' + node.id + '")');
  }

  node.plus.style.fontSize = 0;

  var obj2 = document.createElement("div");
  obj2.style.position = "relative";
  obj2.style.top = - treeFY + 'px' ;
  obj2.style.left = 12 ;
  
  obj2.style.fontSize = 11;
  node.plus.style.fontFamily = 'Arial';
  obj2.style.color = 'green';
  var text;
  if(node.label) {
     text = ' ' + node.label;
  }
  var obj_text = document.createTextNode(text);

  obj2.style.height = 12;
  obj2.style.width = 999;
  obj2.style.overflowY = 'hidden';
  obj2.appendChild(obj_text);
  var obj2_2 = document.createElement("font");
  var obj_text2 = document.createTextNode(' ' + node.leaves + ' ' + object_unit + '(s)');
  obj2_2.style.color = 'black';
  obj2_2.appendChild(obj_text2);
  obj2.appendChild(obj2_2);
   node.plus.appendChild(obj2);
 

}

function Expand(id) 
{
  node = FindNode(id, root);
  squeeze(node, 1)
  if(node.plus) node.plus.style.display = "none";
  CalcYPos(root, 0, 0);
  MoveNode(root); 
  status = 'Done';
  TopObj.style.height =  (total_width + 1) * treeFY;

  if(parent_win) 
          parent_win.height =  (total_width + 1) * treeFY + 300;
}

function Toggle(id, sqz)
{
  node = FindNode(id, root);
  if(node.isopen == 1) {
   if(sqz == 1) {
        squeeze(node, 2);     
   }
   else {
     node.isopen = 0;
//  CalcXPos(root);
     if(!node.plus) {
        AddPlusSign(node);
      }      
      node.plus.style.display = "block";
     
   }
  }
  else {
   
    if(node.isopen == 2) {
            squeeze(node, 1);
     }
     else {

   node.isopen = 1;

   var len = node.Nodes.length;
  if(len > 1) {
   for(var n=0; n <  node.Nodes.length; n++) {
        var node2 =  node.Nodes[n];
        node2.isopen = 0;
        if(  node2.plus ) {
                node2.plus.style.display = "block";                
        }
        else {
                AddPlusSign(node2);
        }

   }
  }
   if(node.plus)   node.plus.style.display = "none";
}
  }
   status = 'Please wait...';
    CalcYPos(root, 0, 0);
  MoveNode(root); 
status = 'Done';
  TopObj.style.height =  (total_width + 1) * treeFY;
 if(parent_win)
        parent_win.height =  (total_width + 1) * treeFY + 300;
}

function CollapseByRank(node, rank) 
{
   var len = node.Nodes.length;
   if(node.label && node.Nodes.length > 0 &&
        node.level >= rank ) {
        node.isopen = 0;
        if( node.plus ) {
                node.plus.style.display = "block";                
        }
        else {
                AddPlusSign(node);
        }
        return;
   }
   node.isopen = 1;
  if(node.plus) {
        node.plus.style.display = "none";
   }
   for(var n=0; n < len; n++) {
        CollapseByRank(node.Nodes[n], rank);
   }
   if(node.id == 0) {
          CalcYPos(root, 0, 0);
          TopObj.style.height =  (total_width + 1) * treeFY;
   if(parent_win)
         parent_win.height =  (total_width + 1) * treeFY + 300;

   if(node.lines)
          MoveNode(root); 
   }

   return;
};


function CollapseByDiameter(node, diameter) 
{
   var len = node.Nodes.length;
   if(node.id > 0 && len > 1 && node.diameter <= diameter) {
        node.isopen = 0;
        AddPlusSign(node);
        return;
   }
   for(var n=0; n < len; n++) {
        CollapseByDiameter(node.Nodes[n], diameter);
   }
   if(node.id == 0) {
          CalcYPos(root, 0, 0);
          TopObj.style.height =  (total_width + 1) * treeFY;
   if(parent_win)
        parent_win.height =  (total_width + 1) * treeFY + 300;
          MoveNode(root); 
   }
   return;
};

function SqueezeByDiameter(node, diameter) 
{
   var len = node.Nodes.length;
   if(node.id > 0 && len > 1 && node.diameter <= diameter) {
        squeeze(node, 2);
        return;
   }
   for(var n=0; n < len; n++) {
        SqueezeByDiameter(node.Nodes[n], diameter);
   }
   if(node.id == 0) {
          CalcYPos(root, 0, 0);
          TopObj.style.height =  (total_width + 1) * treeFY;
   if(parent_win)
        parent_win.height =  (total_width + 1) * treeFY + 300;
          MoveNode(root); 
   }

   return;
};
function squeeze(node, factor) 
{
   var len = node.Nodes.length;
   node.isopen = factor;
   for(var n=0; n < len; n++) {
        squeeze(node.Nodes[n], factor);
   }
   return;
};


function IntSortDesc(x1, x2) {
  return x1 - x2;
};

var diameters = [];
function CollapseByNumber(number)
{
  diameters = [];
  PutDiameters(root);
  diameters.sort(IntSortDesc);
  if(diameters.length > number) {
    var diam = 0 + diameters[diameters.length - number];
    CollapseByDiameter(root, diam);
  }
}

function PutDiameters(node) 
{
   diameters[diameters.length] = node.diameter;
   var len = node.Nodes.length;
   for(var n=0; n < len; n++) {
        PutDiameters(node.Nodes[n]);
   }
   return;
};


function GetXY(obj){
      var b={"x":0, "y":0};
      if (obj.offsetParent) {
          while(obj.offsetParent){
              b.x += obj.offsetLeft;
              b.y += obj.offsetTop;
              obj = obj.offsetParent;
          }
      } else if (obj.x) {
          b.x += obj.x;
          b.y += obj.y;
      }

      return b;
};

function ResizeObj(){
   shiftY = GetXY(TopObj).y ;
   shiftX = GetXY(TopObj).x;
    CalcXPos(root);
    MoveNode(root); 
};

function SwitchParent(node, prev_dist)
{
  var parent = node.parent;
  parent.label  = 0;
  node.Nodes[node.Nodes.length] = parent;
  var len = parent.Nodes.length;
  var shift = 0;
  for(var n = 0; n < len; n++) {
    if(parent.Nodes[n] == node) {
      shift = 1;
    }
    else if(shift > 0){
      parent.Nodes[n - shift] = parent.Nodes[n];
    }
  }
  parent.Nodes.length = len - 1;
  dist = parent.dist;
  parent.dist = prev_dist;
  if( parent.parent ) {
         SwitchParent(parent, dist);
  }
  parent.parent = node;
}


function SetLineColor(node) 
{
  var len = node.Nodes.length;
  if(len == 0) {
        return node.highlight;
  }
  var f1 = 1;
if(node.isopen > 0) {
  for(var n = 0; n < len; n++) {
    f1 &= SetLineColor(node.Nodes[n]);
  }
}
else f1 = 0;
  if(f1) {
    node.lines.style.borderColor = 'red';
  }
  else {
    node.lines.style.borderColor = 'navy';
  } 
  return f1;
}

function MarkNodes(node) 
{
  var len = node.Nodes.length;
if(node.isopen > 0) {
  for(var n = 0; n < len; n++) {
    MarkNodes(node.Nodes[n]);
  }
}
  node.lines.style.borderColor = 'orange';
}


function ReRoot(id)
{
  var node = FindNode(id, root);
  if(node.parent) {
       SwitchParent(node, node.dist);
 }
  root.id = node.id;
  node.id = 0;
  node.parent = null;
  node.dist = 0;
  root = node;

  CalcXPos(root);
  CalcYPos(root, 0, 0);
  CalcLeaves(root);
  MoveNode(root); 
  SetLineColor(root);
}

function SetPresentation(event)
{
  var target;
  if(event.srcElement)
        target = event.srcElement.value;
  else 
        target = event.target.value;
  if(target == "expanded")
        CollapseByRank(root, 'ss');
   else if(target == "squeezed") 
        Toggle(0, 1);
   else 
        CollapseByRank(root, target);        
};

function OutTree(id)
{
  TopObj = document.getElementById(id);  
  if(!TopObj || !TopObj.offsetParent || TopObj.offsetParent.offsetWidth <= 0) {
    setTimeout("OutTree('" + id + "')", 100);
    return;
  }
  TopObj.style.color = "red";
  tl =  GetXY(TopObj);
  shiftY =tl.y + 5;
  shiftX = tl.x + 10;
  CalcXPos(root);
  CalcYPos(root, 0, 0);
  CalcLeaves(root);
  TopObj.style.height =  (total_width + 1) * treeFY;
  TopObj.style.display = "none";
  CollapseByRank(root, 7);
  OutNode(root);
  TopObj.style.display = "block";
  SetLineColor(root);
  MoveNode(root);
  TopObj.width = 800;

  TopObj.style.height =  (total_width + 1) * treeFY;

   if(parent_win)
        parent_win.height =  (total_width + 1) * treeFY + 300;
};

