
addEvent(window, "load", sortables_init);

function sortables_init() {
    // Find all tables with class sortable and make them sortable
    if (!document.getElementsByTagName) return;
    tbls = document.getElementsByTagName("table");
    for (ti=0;ti<tbls.length;ti++) {
        thisTbl = tbls[ti];
        if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) {
            ts_makeSortable(thisTbl);
	    val=getCookie('column_order_'+thisTbl.id);
	    if (val!=null) {
	      setColumnOrder(thisTbl,val);
	    }
	    var val=getCookie('sort_inds_'+thisTbl.id);
	    if (val!=null) {
	      thisTbl.setAttribute('sort_inds',val);
	    }
	    val=getCookie('sort_dirn_'+thisTbl.id);
	    if (val!=null) {
	      thisTbl.setAttribute('sort_dirn',val);
	    }
	    val=getCookie('sort_dtyp_'+thisTbl.id);
	    if (val!=null) {
	      thisTbl.setAttribute('sort_dtyp',val);
	    }
	    if (thisTbl.getAttribute('sort_inds')!=null &&
		thisTbl.getAttribute('sort_inds')!='') {
	      sortTable(thisTbl);	      
	    } else {
	      table_display(thisTbl);
	    }
        }
    }
}

function reset_table(ev) {
  var code;
  if (!ev) var ev = window.event;
  if (ev.keyCode) code = ev.keyCode;
  else if (ev.which) code = ev.which;
  if (code == 27 && 
    confirm('Reset table(s) column order and sort options?')) {
    tbls = document.getElementsByTagName("table");
    for (ti=0;ti<tbls.length;ti++) {
      thisTbl = tbls[ti];
      if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) {
	
	var table = thisTbl;
	var oldcolinds = new Array();
	for (var i=0;i<table.rows[0].cells.length;i++) {
	  oldcolinds[i] = i;
	}
	setColumnOrder(thisTbl,oldcolinds.join(','));
	if (table.getAttribute('sort_inds') != null &&
	    table.getAttribute('sort_inds') != '') {
	  deleteCookie('column_order_'+table.id);
	  table.setAttribute('sort_inds','');
	  deleteCookie('sort_inds_'+table.id);
	  table.setAttribute('sort_dirn','');
	  deleteCookie('sort_dirn_'+table.id);
	  table.setAttribute('sort_dtyp','');
	  deleteCookie('sort_dtyp_'+table.id);
	  sortTable(table);
	}
      }
    }
  }
}

function ts_makeSortable(table) {
    if (table.rows && table.rows.length > 0) {
        var firstRow = table.rows[0];
    }
    if (!firstRow) return;

    document.onkeypress=reset_table;

    for (var i=1;i<table.rows.length;i++) {
	table.rows[i].setAttribute('origindex',i)
    }	

    // We have a first row: assume it's the header, and make its contents clickable links
    for (var i=0;i<firstRow.cells.length;i++) {
        var cell = firstRow.cells[i];
        var txt = ts_getInnerText(cell);
	if (cell.getAttribute('datatype') != 'unsortable') {
	  cell.innerHTML = '<a class="sortheader" onMouseover=\'tohand(this)\', onmouseout=\'toarrow(this)\' onclick="ts_resortTable(this);return false;">'+txt+'<span id=sortarrow_'+table.id+'_'+i+' class="sortarrow">&nbsp;&nbsp;</span></a>';
	} 
	if (cell.getAttribute('expands') == 'true') {
	  cell.innerHTML += '<a id="expands" onMouseover="tohand(this)", onmouseout="toarrow(this)" onclick="expand(this);return false;">&nbsp;+&nbsp;</a>';
	} 
	cell.onmousedown=MDOWN;
	cell.setAttribute('origindex',i);
	if (!cell.getAttribute("datatype") ||
	    cell.getAttribute("datatype") == "") {
	    var itm = ts_getInnerText(table.rows[1].cells[i]);
	    if (itm.match(/^\s*[\d\.]+\s*$/)) {
		cell.setAttribute("datatype","numeric");
	    } else {
		cell.setAttribute("datatype","lower");
	    }
	}
    }

    // for (var i=1;i<table.rows.length;i++) {
    //   for (var j=0;j<table.rows[0].cells.length;j++) {
    //     var elt = table.rows[i].cells[j];
    //     var tmp = elt.innerHTML;
    //     elt.innerHTML = "<span>"+tmp+"</span>";
    // 	   elt.onmousedown=MDOWN1;
    //   }	
    // }	
}

function ts_resortTable(lnk) {

  var span = getChild(lnk,'span');
  var td = lnk.parentNode;
  var column = td.cellIndex;
  var table = getParent(td,'TABLE');
  
  var inds;
  var dirn;
  var dtype;
  if (table.getAttribute('sort_inds')) {
    inds = table.getAttribute('sort_inds').split(',');
    dirn = table.getAttribute('sort_dirn').split(',');
    dtyp = table.getAttribute('sort_dtyp').split(',');
  } else {
    inds = new Array();
    dirn = new Array();
    dtyp = new Array();
  }
  
  var ipos = -1;
  var i,j;
  for (j=0;j<inds.length;j++) {
    if (inds[j] == column) {
      ipos = j;
      break;
    };
  };	
  
  if (ipos == -1) {
    inds.push(column);
    dirn.push(1);
    dtyp.push(td.getAttribute("datatype"));
    span.setAttribute('dirn',1);
  } else if (dirn[ipos] > 0) {
    dirn[ipos] = -1;
    span.setAttribute('dirn',-1);
  } else if (dirn[ipos] < 0) {
    inds.splice(ipos,1);
    dirn.splice(ipos,1);
    dtyp.splice(ipos,1);
    span.setAttribute('dirn',0);
  };
  
  table.setAttribute('sort_inds',inds.join(','));
  setCookie('sort_inds_'+table.id,inds.join(','));
  table.setAttribute('sort_dirn',dirn.join(','));
  setCookie('sort_dirn_'+table.id,dirn.join(','));
  table.setAttribute('sort_dtyp',dtyp.join(','));
  setCookie('sort_dtyp_'+table.id,dtyp.join(','));

  sortTable(table);

}

function set_dirn(table,inds,dirn) {
  var i,j;
  for (i=0;i<table.rows[0].cells.length;i++) {
    var a = getChild(table.rows[0].cells[i],'a');
    var span = getChild(a,'span');
    if (span) {
      span.setAttribute('dirn',0);
    }
  }
  for (i=0;i<inds.length;i++) {
    var a = getChild(table.rows[0].cells[inds[i]],'a');
    var span = getChild(a,'span');
    span.setAttribute('dirn',dirn[i]);
  }
}

function sortTable(table) {
    
    if (table.rows.length <= 1) return;

    var inds;
    var dirn;
    var dtype;
    if (table.getAttribute('sort_inds')) {
	inds = table.getAttribute('sort_inds').split(',');
	dirn = table.getAttribute('sort_dirn').split(',');
	dtyp = table.getAttribute('sort_dtyp').split(',');
    } else {
	inds = new Array();
	dirn = new Array();
	dtyp = new Array();
    }

    set_dirn(table,inds,dirn);

    if (inds.length == 0) {
        inds.push(-1);
        dirn.push(1);
        dtyp.push("numeric");
    }
    
    window.status = 'Getting values...';
    
    var vals = new Array();
    var cmps = new Array();
    var convs = new Array();
    var k;
    
    for (k=0;k<dtyp.length;k++) {
      if (inds[k] >= 0) {
	cmps[k] = getcolumncmp(table,inds[k]);
	convs[k] = getcolumnconv(table,inds[k]);
      } else {
	cmps[k] = numeric_cmp;
      }
    }
      
    for (j=1;j<table.rows.length;j++) { 
	var j1 = j-1;
	vals[j1] = new Array();
	for (k=0;k<inds.length;k++) {
	    if (inds[k] >= 0) {
	      vals[j1][k] = convs[k](table.rows[j].cells[inds[k]]);
	    } else {
	      vals[j1][k] = parseFloat(table.rows[j].getAttribute('origindex'));
	    }
	}
	vals[j1][inds.length] = j1;
    }
    cmps[inds.length] = numeric_cmp;
    dirn[inds.length] = 1;

    window.status = 'Sorting values...';
    
    vals.sort(multi_sort(cmps,dirn));

    window.status = 'Recreating table...';
    
    var oldRows = new Array();
    for (j=1;j<table.rows.length;j++) {
	oldRows.push(table.rows[j]);
    }

    var n = inds.length;
    for (i=0;i<vals.length;i++) { 
	table.tBodies[0].appendChild(oldRows[vals[i][n]]);
    }

    window.status = 'Table display...';
    
    table_display(table);

    window.status='';

}

function getcolumncmp(table,i) {
  var dt = table.rows[0].cells[i].getAttribute('datatype');
  if (dt == 'numeric') {
    return numeric_cmp;
  } else if (dt == 'lower') {
    return lower_cmp;
  } else if (dt == 'alpha') {
    return alpha_cmp;
  } else if (dt == 'unsortable') {
    return unsortable_cmp;
  }
  return alpha_cmp;
}

function getcolumnconv(table,i) {
  var dt = table.rows[0].cells[i].getAttribute('datatype');
  if (dt == 'numeric') {
    return numeric_conv;
  } else if (dt == 'lower') {
    return lower_conv;
  } else if (dt == 'alpha') {
    return alpha_conv;
  } else if (dt == 'unsortable') {
    return unsortable_conv;
  }
  return alpha_conv;
}

function table_display(table) {
  var i;
  var conv = new Array();
  var cmp = new Array();
  for (i=0;i<table.rows[0].cells.length;i++) {
    cmp[i] = getcolumncmp(table,i);
    conv[i] = getcolumnconv(table,i);
  }

  window.status = 'Coloring cells...';

  var prevval = new Array();
  var prevv,curv;
  var previndmax = -1;
  for (i=1;i<table.rows.length;i++) {
    var currow = table.rows[i];
    if (i%2 == 0) { 
      currow.className = 'even';
    } else {
      currow.className = 'odd';
    } 
    var match=(i>1);
    var curindmax=-1;
    for (j=0;j<currow.cells.length;j++) {
      var elt = currow.cells[j];
      if (match) {
	if (previndmax >= j) {
	  prevv = prevval[j];
	} else {
	  prevv = conv[j](table.rows[i-1].cells[j]);
	}
	curv = conv[j](elt);
	if (cmp[j](curv,prevv)!=0) {
	  match = 0;
	}
	prevval[j]=curv;
	curindmax=j
      }
      elt = elt.firstChild;
      if (match && (elt.className != '' || elt.className.charAt(0)!='i')) {
	if (i%2==0) {
	  elt.className = 'invisibleeven';
	} else {
	  elt.className = 'invisibleodd';		    
	}
      } else if (!match && (elt.className  != '' || elt.className.charAt(0)=='i')) {
	if (i%2==0) {
	  elt.className = 'even';
	} else {
	  elt.className = 'odd';		    
	}
      }
    }
    previndmax = curindmax;
  }

  // Delete any other arrows there may be showing
  for (var i=0;i<table.rows[0].cells.length;i++) {
    var elt=document.getElementById('sortarrow_'+table.id+'_'+i);
    if (elt != null) {
      if (elt.getAttribute('dirn')) {
	if (elt.getAttribute('dirn') > 0) {
	  elt.innerHTML = '&nbsp;&uarr;';
	} else if (elt.getAttribute('dirn') < 0) {
	  elt.innerHTML = '&nbsp;&darr;';
	} else {
	  elt.innerHTML = '&nbsp;&nbsp;';
          }
      } else {
	elt.innerHTML = '&nbsp;&nbsp;';
      }
    }
  }
  
  window.status = '';
}

function getX(e)
{
  var posx = 0;
  if (e.pageX) {
    posx = e.pageX;
  } else if (e.clientX) {
    posx = e.clientX + document.body.scrollLeft;
  }
  return posx;
}

function getY(e)
{
  var posy = 0;
  if (e.pageY) {
    posy = e.pageY;
  } else if (e.clientY) {
    posy = e.clientY + document.body.scrollTop;
  }
  return posy;
}

var startElt;
var startX;
var startY;
var downindex = -1;

function MDOWN(ev) {
  ev = ev || event;
  var elt = ev.srcElement || ev.target;
  downindex = getParent(elt,'TH').cellIndex;
  startElt = elt;
  startX = getX(ev);
  startY = getY(ev);
  document.onmouseup=MUP;
  document.onmousemove=MMOVE;
  return false;
}	

function MMOVE(ev) {
  ev = ev || event;
  var x=getX(ev);
  var y=getY(ev);
  var dragHeaderDiv = document.getElementById('dragHeaderDiv');
  if(dragHeaderDiv) {
    dragHeaderDiv.style.left = x+10+"px";
    dragHeaderDiv.style.top = y-10+"px";
  } else if (downindex >= 0 && (x<startX-3 || x>startX+3)) {
    var dragHeaderDiv = document.createElement('DIV');
    var textelt = document.createTextNode(ts_getInnerText(startElt));
    dragHeaderDiv.appendChild(textelt);
    dragHeaderDiv.id = "dragHeaderDiv";
    dragHeaderDiv.setAttribute("onmouseleave","");
    dragHeaderDiv.setAttribute("onmouseenter","");
    dragHeaderDiv.style.position = "absolute";
    dragHeaderDiv.style.left = x+10+"px";
    dragHeaderDiv.style.top = y-10+"px";
    dragHeaderDiv.style.zIndex = 10000;
    var bodyRef = document.getElementsByTagName("body").item(0);
    bodyRef.appendChild(dragHeaderDiv);
  }
  return false;
}

function getHeaderIndexAt(x,y) {
  if (!getParent(startElt,'TABLE')) {
    return -1;
  }
  var headerrow = getParent(startElt,'TABLE').rows[0];
  var offsetObj = headerrow;
  var offsetX = 0;
  var offsetY = 0;
  while(offsetObj) { 
    offsetX += offsetObj.offsetLeft;
    offsetY += offsetObj.offsetTop;
    offsetObj = offsetObj.offsetParent;
  }
  
  var offsetH = headerrow.offsetHeight;

  if (y<offsetY || y>=(offsetY+offsetH)) {
    return -1;
  }

  var headers = headerrow.childNodes;
  var column = -1;
  for(i=0;i<headers.length;i++) {
    if(x>offsetX && x<=(headers[i].offsetWidth+offsetX+5)) { 
      column=i; 
      break; 
    }
    offsetX+=headers[i].offsetWidth;
  }	
  return column;
}

function MUP(ev) {
  ev = ev || event;

  var dragHeaderDiv = document.getElementById('dragHeaderDiv');
  if(dragHeaderDiv) {
    var bodyRef = document.getElementsByTagName("body").item(0);
    bodyRef.removeChild(dragHeaderDiv);
  }
  document.onmouseup=null;
  document.onmousemove=null;

  var x=getX(ev);
  var y=getY(ev);
  
  i = getHeaderIndexAt(x,y);

  if (i != downindex && downindex != -1 && i != -1) {
    window.status = 'Moving...';
    move_col(getParent(startElt,'TABLE'),downindex,i);
    table_display(getParent(startElt,'TABLE'));
    window.status = '';
  } 
  downindex = -1;
  return false;
}	

function MDOWN1(ev) {
  ev = ev || event;
  var elt = ev.srcElement || ev.target;
  var cellindex = getParent(elt,'TD').cellIndex;
  var rowindex = getParent(elt,'TR').rowIndex;
  var table = getParent(elt,'TABLE');
  var span = getParent(elt,'TD').firstChild;

  if (table && span.className.charAt(0) != 'i') {
    var cnt = 1;
    for (var i=(rowindex+1);i<table.rows.length;i++) {
      if (table.rows[i].cells[cellindex].firstChild.className.charAt(0) == 'i') {
	cnt = cnt + 1
      } else {
	break;
      }
    }
    window.status = cnt + ' duplicate values';
    document.onmouseup=MUP1;
  }
  return true;
}	

function MUP1(ev) {
  window.status = '';
}

function setColumnOrder(table,colorderstr) {
  var i,j;
  var colorder = colorderstr.split(',');
  for (i=0;i<colorder.length;i++) {
    var curpos=-1;
    for (j=0;j<table.rows[0].cells.length;j++) {
      if (colorder[i] == table.rows[0].cells[j].getAttribute('origindex')) {
	curpos = j;
	break;
      }
    }
    if (curpos != i) {
    	move_col(table,curpos,i);
    }
  }
}

function move_col(table,from,to) {
    var newindex = new Array();
    for (var i=0;i<table.rows[0].cells.length;i++) {
	newindex[i] = i;
    }
    if (to > from) {
	newindex[from] = to;
	for (var i=from+1;i<=to;i++) {
	    newindex[i] = i-1;
	}
    } else {
	newindex[from] = to;
	for (var i=from-1;i>=to;i--) {
	    newindex[i] = i+1;
	}
    }
    if (table.getAttribute('sort_inds')) {
        var inds = table.getAttribute('sort_inds').split(',');
	for (var i=0;i<inds.length;i++) {
	    inds[i] = newindex[inds[i]];
	}
	table.setAttribute('sort_inds',inds.join(','));
    }
    for (var i=0;i<table.rows.length;i++) {
	if (to > from) {
	    if (to < table.rows[0].cells.length) {
		table.rows[i].insertBefore(table.rows[i].cells[from],table.rows[i].cells[to].nextSibling);
	    } else {
		table.rows[i].appendChild(table.rows[i].cells[from]);
	    }
	} else {
	    if (to > 0) {
		table.rows[i].insertBefore(table.rows[i].cells[from],table.rows[i].cells[to]);
	    } else {
		table.rows[i].insertBefore(table.rows[i].cells[from],table.rows[i].firstChild);
	    }
	}
    }
    var origindex = new Array();
    for (var i=0;i<table.rows[0].cells.length;i++) {
	origindex[i] = table.rows[0].cells[i].getAttribute('origindex');
    }
    setCookie('column_order_'+table.id,origindex.join(','));
}

function expand(lnk) {
    
    window.status = 'Expanding...';

    var span = getChild(lnk,'span');
    var td = lnk.parentNode;
    var column = td.cellIndex;
    var table = getParent(td,'TABLE');
    
    var i;
    for (i=1;i<table.rows.length;i++) {
      if (table.rows[i].cells[column].getAttribute('alt_text')) {
	var tmp = table.rows[i].cells[column].firstChild.innerHTML;
	var tmp1 = table.rows[i].cells[column].getAttribute('alt_text');
	tmp1 = unescape(tmp1);
	table.rows[i].cells[column].firstChild.innerHTML = tmp1;
	table.rows[i].cells[column].setAttribute('alt_text',tmp);
      } 
    }
    var a = getChildById(td,'expands');
    if (a.innerHTML == "&nbsp;+&nbsp;") {
      a.innerHTML = "<NOBR>&nbsp;&ndash;&nbsp;</NOBR>";
    } else {
      a.innerHTML = "&nbsp;+&nbsp;";
    }

    window.status = '';

}

function ts_getInnerText(el) {
	if (typeof el == "string") return el;
	if (typeof el == "undefined") { return el };
	if (el.innerText) return el.innerText;	//Not needed but it is faster
	var str = "";
	
	var cs = el.childNodes;
	var l = cs.length;
	for (var i = 0; i < l; i++) {
		switch (cs[i].nodeType) {
			case 1: //ELEMENT_NODE
				str += ts_getInnerText(cs[i]);
				break;
			case 3:	//TEXT_NODE
				str += cs[i].nodeValue;
				break;
		}
	}
	return str;
}

function getParent(el, pTagName) {
  if (el == null) {
    return null;
  } else if (el.nodeType == 1 && 
	     el.tagName.toLowerCase() == pTagName.toLowerCase()) {
    return el;
  } else {
    return getParent(el.parentNode, pTagName);
  }
}

function getChild(el, cTagName) {
  if (el.tagName && el.tagName.toLowerCase() == cTagName.toLowerCase()) {
    return el;
  }
  for (var ci=0;ci<el.childNodes.length;ci++) {
    if (el.childNodes[ci].tagName && 
	el.childNodes[ci].tagName.toLowerCase() == cTagName.toLowerCase()) {
      return el.childNodes[ci];
    }
  }
}

function getChildById(el, cTagName) {
  for (var ci=0;ci<el.childNodes.length;ci++) {
    if (el.childNodes[ci].id && 
	el.childNodes[ci].id.toLowerCase() == cTagName) {
      return el.childNodes[ci];
    }
  }
}

function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+,  NS6 and Mozilla
// By Scott Andrew
{
  if (elm.addEventListener){
    elm.addEventListener(evType, fn, useCapture);
    return true;
  } else if (elm.attachEvent){
    var r = elm.attachEvent("on"+evType, fn);
    return r;
  } else {
    alert("Handler could not be removed");
  }
} 

function unsortable_conv(elt) {
  return 0;
}

function unsortable_cmp(a,b) {
  return 1;
}

function alpha_conv(elt) {
  if (elt.getAttribute('value')) {
    return elt.getAttribute('value');
  } else {
    return ts_getInnerText(elt);
  }
}

function alpha_cmp(a,b) {
  if (a>b) return 1;
  if (a<b) return -1;
  return 0;
}

function lower_conv(elt) {
  if (elt.getAttribute('value')) {
    return elt.getAttribute('value').toLowerCase();
  } else {
    return ts_getInnerText(elt).toLowerCase();
  }
}

function lower_cmp(a,b) {
  if (a>b) return 1;
  if (a<b) return -1;
  return 0;
}

function numeric_conv(elt) {
  if (elt.getAttribute('value')) {
    return parseFloat(elt.getAttribute('value'));
  } else {
    return parseFloat(ts_getInnerText(elt));
  }
}

function numeric_cmp(a,b) {
  var ret = a-b;
  if (isNaN(ret)) return 0;
  return ret;
}

function multi_sort(cmps,dirn) {
  return function(a,b) {
    ret = 0;
    for (var i=0;i<a.length;i++) {
      ret = cmps[i](a[i],b[i]);
      if (ret) {
	return ret*dirn[i];
      }
    }
  };
}




