// @cvs-id $Id: lib.js,v 1.4 2007/11/13 04:10:29 nsadmin Exp $ $Name: bridge-release-2_7_0 $
// Copyright 2004-2007 MedTouch LLC

// Cross-browser utilities

// Browser/OS detection
var agt = navigator.userAgent.toLowerCase();
// These definitely need to be cleaned up a little
var isMac = (agt.indexOf("mac") != -1);
var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1);
var isOpera = (agt.indexOf("opera") != -1);
var isNs = (navigator.appName.indexOf("Netscape") != -1);
var isGecko = (agt.indexOf("gecko") != -1);
var isKonqueror = (agt.indexOf("konqueror") != -1);
var isSafari = (agt.indexOf("safari") != -1);
var isIE = ((agt.indexOf("msie") != -1) && !isOpera && (agt.indexOf("webtv") == -1)); 
// An alternative version.  Which is better?
// var isIE  = (navigator.appVersion.indexOf("MSIE") != -1);
var is_ie = isIE;
var ieP = isIE;
// Deprecated definition, shouldn't be a problem
// var ieP = document.all;

// doc can be empty (default to current document), a document object, or a 
// string to be evaluated to get a document object
function getByID( id, doc ) {
  if (!doc)
    doc = document;
  else if (typeof(doc) == "string")
    doc = eval(doc);		// Parse the string

  if (doc.getElementById) {
    // Newer browsers
    return doc.getElementById(id);
  } else if (doc.all) {
    // IE4
    return doc.all[id];
  } else if (doc.layers) {
    // NS4
    return doc.layers[id];
  } else {
    alert( 'We couldn\'t recognize your browser.  Please use a different one or upgrade to the newest version.' );
    window.close();
  }
  return "";
}

// Just in case we don't know for sure if we have an ID or an object reference
function maybeGetByID( maybeId, doc ) {
  if (typeof(maybeId) == "string")
    return getByID(maybeID, doc); // Assuming we didin't pass in a string object
  else
    return maybeId;		// It's not an ID, so we figure it's an object
}


// Within a given element, find an element with that ID and type
function getObjElementById(obj, element_id, type) {
  var elements = obj.getElementsByTagName(type);
  for (i = 0; i < elements.length; i++)
    if (elements[i].id== element_id)
      return elements[i];
}


// Sometimes it's easier to access a form element by its name rather than
// its ID
function getFormInputsByName (form, inputName) {
  var inputs = new Array();
  for (var i = 0; i < form.length; i++)
    if (form.elements[i].name == inputName)
      inputs.push(form.elements[i]);
  return inputs;
}


function getStyleObject(objectId) {
  if (document.getElementById && document.getElementById(objectId))
    return document.getElementById(objectId).style;
  else if (document.all && document.all(objectId))
    return document.all(objectId).style;
  else
    return false;
}

// Stylesheet fun

function getRules(stylesheet) {
  if (stylesheet.cssRules)
    return stylesheet.cssRules;
  else
    return stylesheet.rules;
}
 
function findStylesheetRules(selector) {
  var sheetList = document.styleSheets;
  var ruleList;
  var i, j;
  var matches = new Array();
    
  /* look through stylesheets in reverse order that
  they appear in the document */
  for (i=sheetList.length-1; i >= 0; i--) {
    ruleList = getRules(sheetList[i]);
    for (j=0; j<ruleList.length; j++) {
      // Case conversion could cause errors, but I know for a fact that
      // IE's case conversion for tag names is a problem.
      if (ruleList[j].selectorText.toLowerCase() == selector.toLowerCase())
        matches.push(ruleList[j]);
    }
  }
 
  return matches;
}

function getXMLRequest () {
  if (window.ActiveXObject  && !isMac)
    return new window.ActiveXObject("Msxml2.XMLHTTP");
  else if (window.XMLHttpRequest)
    return new XMLHttpRequest();
}
// onSubmit handlers for double-click protection
 
function refuseDoubleClick() {
  alert('It looks like this form has already been submitted.  In order to prevent duplicate or broken data, we are refusing this submission.  You may re-load this page to re-submit');
  return false;
}
 
function testDoubleClick(){
  return confirm('It looks like this form has already been submitted. If you re-submit it it could result in duplicate, or even broken, data.  Do you wish to proceed?');
}

var doubleClickProtect = false;

// If submitted once, use one of the above functions.
function checkDoubleClick( force ) {
  if ( !doubleClickProtect ) {
    doubleClickProtect = true;
    return true;
  } else if ( force ) {
    return refuseDoubleClick();
  } else {
    return testDoubleClick();
  }
}

// Useful for creating a pop-up notification of some sort

function newWindow(url, name, width, height) {
  var newwin = window.open(url,name,
			   (width ? 'width=' + width + ',' : '') +
			   (height ? 'height=' + height + ',' : '') +
			   'resizable=yes, titlebar=no,toolbar=no,location=no,scrollbars=yes,status=no');
  newwin.focus();
  return newwin;
}

// Used to show or hide
function changeDiv(the_div, the_change) {
  var the_style = getStyleObject(the_div);
  if (the_style)
    the_style.display = the_change;
}

function toggle2(objid) {
  var obj = getByID(objid);
  if (obj.style.display == "none")
    obj.style.display = '';
  else
    obj.style.display = "none";
}
		
function show_div (id) {
  getByID(id).style.display = '';
}
function hide_div(id) {
  getByID(id).style.display = 'none';
}


// Useful color changing functions to highlight changed data or fields that
// need to be changed

function changeColor( id, color ) {
  var tag = getByID( id );
  if (tag.style)
    tag.style.backgroundColor = color;
  else if (tag.document && tag.document.bgColor)
    tag.document.bgColor = color;
}
 
var changedColor = '#ffddee';
var unchangedColor = 'white';

function markChanged( id ) {
  changeColor('row.'+id, changedColor);
} 

function markUnchanged( id ) {
  changeColor('row.'+id, unchangedColor);
} 

// Utilities for making alternating colors
var colorchanger = 0;

// These are deprecated due to poor naming, but the wrappers remain for legacy applications
function makeCol (Color1, Color2) {
  createNextColorRow(Color1, Color2);
}
function lastmakeCol (Color1, Color2) {
  createColorRow(Color1, Color2);
}

function createColorRow(Color1, Color2) {
  if (colorchanger % 2 == 0) {
    colorchanger = 0;
    document.write ("<TR bgcolor = "+ Color1 + ">");
  } else {
    document.write ("<TR bgcolor = "+ Color2 + ">");
  }
}

function createNextColorRow(Color1, Color2) {
  colorchanger++;
  createColorRow(Color1, Color2);
}

// Form validation (by paulm@oho.com)

// Set the id for an input that only has a name
function set_id (item_name, id, thisform) {
  if (!thisform[item_name].id)
    thisform[item_name].id = id;
}

function testItemByName (item_name, thisform) {
  return (testItem(thisform[item_name]));
}


function testItem (item) {
  var i;

  // Apply different tests based on the type of input
  if (item.type == "text" || item.type == "textarea" || item.type=="password")
    return (item.value != "");
  else if (item.type == "checkbox" || item.type == "radio")
    return item.checked;
  else if (item.type == "select-one")
    return (item[item.selectedIndex].value != "");
  else if (item.type == "select-multiple")
    if (item.selectedIndex == -1)
      return false;
    else
      return (item[item.selectedIndex].value != "");
  else
    for (i = 0; i < item.length; i++) 
      if (testItem(item[i]))
	return true;
  return false;
}

function testItems (thisform) {
  var i;	
  var emptyitems = "";
  for (i=0; i < thisform.length; i++) {
    // If the input id ends in "rq" it is required
    if (thisform[i].id != "" && thisform[i].id.substring(thisform[i].id.length - 2) == "rq" ) {
      if (!testItemByName (thisform[i].name, thisform)) {
	if (thisform[i].id) {
	  changeColor (thisform[i].id, changedColor);
	  thisform[i].onfocus=function onfocus(event) {
	    changeColor(this.id,unchangedColor);
	  };
	  emptyitems += thisform[i].id.substring(0, thisform[i].id.length - 2);
	} else {
	  emptyitems += thisform[i].name;
	}
	emptyitems += "\n";
      }
    }
  }
  if (emptyitems != "") {
    alert ("You need to enter information for the following items: \n\n" + emptyitems);
    return false;
  } else {
    return true;
  }
}

// wrapper for legacy purposes
function test_items (thisform) {
  return testItems(thisform);
}


// radioGetVal

function radioGetVal(form, fieldName) {
  var radio = form[fieldName];
  var buttons = radio.length;
  var i = 0;
  var selection;
  while (i < buttons)  {
    if (radio[i].checked) {
      selection = radio[i].value;
      break;
    }
    i++;
  }
  return selection;
}

// Select the option with the given value in the select

function selectByValue(select, value) {
  var i = 0;
  while (i < select.options.length)
    if (select.options[i].value == value) {
      select.selectedIndex = i;
      return i;
    } else i++;
  return null;
}

function getSelectedValue(select) {
  return select.options[select.selectedIndex].value;
}


// Encode the values of the fields listed in an array into a URLstring

function fieldsToQuery (arr) {
  var query = "";
  var field;
  for (var i = 0; i < arr.length; i++) {
    field = getByID(arr[i]);
    if (field.type != "checkbox" || field.checked) {
      value = field.value;
    } else {
      value = "";
    }
    if (i > 0) query += "&";
    query += encodeURIComponent(arr[i]) + "=" + encodeURIComponent(value);
  }
  return query;
}


// This closure is very general in terms of dealing with arguments, but might run
// afoul of circular references which would make garbage collection difficult.
// If you can, use safeClosure instead.

Function.prototype.makeClosure = function() {
  var f = this;
  var a = arguments;
  // Fill in all the defined arguments and return a function that
  // only requires the remaining arguments

  return function() {
    var a2 = new Array();
    var i = 0;
    var j = 0;
    while (i < a.length || j < arguments.length) {
      if (typeof a[i] != "undefined")
	a2.push(a[i]);
      else
	a2.push(arguments[j++]);
      i++;
    }

    return f.apply(this, a2);
  }
}

// To cure memory leakage due to circular references in closures in IE.
// Useful for dynamically adding handlers which use "this"
// (Found at http://laurens.vd.oever.nl/weblog/items2005/closures/)

Function.prototype.safeClosure = function(obj) {
  // Init object storage.
  if (!window.__objs)
    window.__objs = [];

  // Init closure storage.
  if (!this.__closureFuncs)
    this.__closureFuncs = [];

  // Make sure the object has an id and is stored in the object store.
  var objId = obj.__closureObjId;
  if (!objId)
    __objs[objId = obj.__closureObjId = __objs.length] = obj;

  // See if we previously created a closure for this object/function pair.
  var closureFunc = this.__closureFuncs[objId];
  if (closureFunc)
    return closureFunc;

  // Clear reference to keep the object out of the closure scope.
  obj = null;

  // Create the closure, store in cache and return result.
  var me = this;
  return this.__closureFuncs[objId] = function()
  {
    return me.apply(__objs[objId], arguments);
  };
}

// Store functions that are dynamically created, but repeated over and over

var functionStore;

function getStoredFunction(body) {
  if (!functionStore) functionStore = new Object();
  if (!functionStore[body])
    functionStore[body] = new Function(body);
  return functionStore[body];
}





// DOM Utilities

function removeMe(node) {
  if (node.parentNode)
    node.parentNode.removeChild(node);
}

function insertAfter(newNode, refNode) {
  if (refNode.nextSibling)
    refNode.parentNode.insertBefore(newNode, refNode.nextSibling);
  else
    refNode.parentNode.appendChild(newNode);
 
  return newNode;
}

// Display the source of the document (including everything that has been
// written into it via DHTML)
// tigre@ybos.net 2004-12-17

function showCurrentSource (doc) {
  if (!doc) doc = document;
  var newWin = newWindow(null, 'source_view', 800, 600);
  newWin.document.write('<code><pre>\n'+doc.body.innerHTML.replace(/</g, '&lt;')+'</pre></code>');
  return newWin;
}

// Writing error messages to the console (without interrupting execution)
// for tracing purposes.  Messages don't always show up in chronological order.
 
function writeError (message) {
  setTimeout ("writeError_inner('" + message + "')", 0);
}
function writeError_inner (message) {
  throw Error(message);
}
 
// An alert that allows you to interrupt operations by hitting "Cancel"

function myAlert(msg) {
  if (!confirm(msg))
    throw new Error('Abort on '+msg);
}


// Snagged these two functions from http://www.quirksmode.com/js/findpos.html

function findPosX(obj) {
  var curleft = 0;
  if (obj.offsetParent)
    while (obj.offsetParent) {
      curleft += obj.offsetLeft
	obj = obj.offsetParent;
    }
  else if (obj.x)
    curleft += obj.x;
  return curleft;
}

function findPosY(obj)
{
  var curtop = 0;
  if (obj.offsetParent)
    while (obj.offsetParent) {
      curtop += obj.offsetTop
	obj = obj.offsetParent;
    }
  else if (obj.y)
    curtop += obj.y;
  return curtop;
}

// For testing purposes, you can dump the location info into the title

function findPosYx(obj)
{	
  var curtop = 0;
  var title = "";

  if (obj.offsetParent) {
    while (obj.offsetParent) {
      if (title != "")
	title += ", ";
      title += obj.tagName;
      if (obj.id)
	title += "(" + obj.id + ")";
      else if (obj.className)
	title += "{" + obj.className + "}";	
      title += " = " + obj.offsetTop;
      curtop += obj.offsetTop;
      obj = obj.offsetParent;
      if (!obj.offsetParent)
	if (obj.style.position == "relative" || obj.style.position == "absolute" ) {
	      
	}
    }
    curtop += obj.offsetTop;
    title += " --- " + obj.tagName;
    title += " = " + obj.offsetTop;
	     
  }
  else if (obj.y) {
    curtop += obj.y;
  }
  title += " curtop = " + curtop;
  document.title = title;
  return curtop;
}

// Find out how wide the window is

function getClientWidth () {
  if (!isIE && document.documentElement &&
      (de = document.documentElement.clientWidth) != window.innerWidth)
    return de;
  else
    return document.body.clientWidth;
}

// Auto-resizing for iframes. Found on dhtmlnirvana.com

// Default to fitting the height, but not the width
//
function autofitIframe(id, fitMode) {
  if (!fitMode)
    fitMode = "height";
  if (fitMode == "height" || fitMode == "both")
    parent.document.getElementById(id).style.height="";
  if (fitMode == "width" || fitMode == "both")
    parent.document.getElementById(id).style.width="";

  setTimeout("autofitIframe2('" + id + "','" + fitMode + "')", 0);
}

function autofitIframe2(id,fitMode) {
  // For IE
  if (!window.opera && !document.mimeType && document.all &&
      document.getElementById){
    if (fitMode == "height" || fitMode == "both")
      parent.document.getElementById(id).style.height = (10 + this.document.body.offsetHeight)+"px";
    if (fitMode == "width" || fitMode == "both")
      parent.document.getElementById(id).style.width = (10 + this.document.body.offsetWidth)+"px";

  }
  // Other browsers seem to prefer scrollHeight/Width
  else if(document.getElementById) {
    if (fitMode == "height" || fitMode == "both")
      parent.document.getElementById(id).style.height = (10 + (this.document.body.scrollHeight))+"px";
    if (fitMode == "width" || fitMode == "both")
      parent.document.getElementById(id).style.width = (10 + (this.document.body.scrollWidth))+"px";
  }
}

// A scrolling function by Paul Meisel, anchors a div to a certain location
// in the browser window regardless of scrolling

var last_offset = "-2000px;"
function pmscroll () {
  var obj_id = "loading_message";
  var thetop = 100;
  var Y = isNs ? pageYOffset : document.documentElement.scrollTop;
  if (Y != last_offset) {
    var thediv = getByID("loading_message");

    if (thediv) {
      thediv.style.top=(Y+thetop) + "px";
    }
  }
//      last_offset = Y;
}
                                                                                
// More scrolling
 
var last_offset2 = "-2000px;"
function pmscroll2 (obj_id, thetop) {
  var Y = isNs ? pageYOffset : document.documentElement.scrollTop;
  Y -= 9;
  if (Y != last_offset2 && getByID(obj_id)) {
    var new_top = 0;
 
    if (Y < thetop) {
      new_top = thetop;
    } else {
      new_top = Y;
    }
    var thediv = getByID(obj_id);
 
    if (thediv) {
      thediv.style.top=new_top + "px";
    }
  }
  //      last_offset2 = Y;
}

// Scroll to an element
 
function jumpToId(anchor, modify) {
  var y = findPosY(getByID(anchor));
  scrollTo(0, y + modify);
}

// Smooth scrolling

var elementsToScroll;

function scrollElement(element, endScroll) {
    var startScroll = element.scrollTop;
    var incr = (endScroll - startScroll) * .01;
    if (!elementsToScroll) elementsToScroll = new Array();
    var elementIndex = elementsToScroll.push(element) - 1;

    element.scrollTop += Math.round(incr);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 3),
	       50);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 6),
	       100);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 10),
	       150);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 20),
	       200);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 40),
	       250);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 60),
	       300);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 80),
	       350);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 90),
	       400);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 94),
	       450);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 97),
	       500);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + 
	       Math.round(startScroll + incr * 99),
	       550);
    setTimeout('elementsToScroll['+elementIndex+'].scrollTop = ' + endScroll,
	       600);
}


// Mostly useful for creating closures, namely a generic function for writing
// something in particular to any object passed to it.
 
function rewriteInnerHTML(html, object) {
  object.innerHTML = html;
}

// Add an on* handler in good cross-browser fashion

function addOnHandler (object, event, script) {
  object[event] = script;
  if (ieP)
    object.attachEvent(event, getStoredFunction(script).safeClosure(object));
  else
    object.setAttribute(event, script);
}


// Dynamically load JavaScript even after the page is finished loading
if (ieP) {
  document.write('<script type="text/javascript" id="scriptLoader"></script>');

  function loadJsFile(url) {
    getByID("scriptLoader").src = url;
  }
} else {
  function loadJsFile(url) {
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
  }
}

// Take text and make it friendly to HTML/XML attributes

function escapeTextAttribute(text) {
  return text.toString().replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/\'/g, '&apos;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

function hasAttribute(attribute,obj) {
  var out = false;
  var counter;
  if(obj.attributes.length)
    for(counter = 0; counter < obj.attributes.length; counter++)
      if(obj.attributes[counter].name==attribute) {
	out = true;
	break;
      }
  return out;
}

// Get a GMT time string (usually for cookies) xDays into the future	
function getGMT(xDays) {
  var exp = new Date();
  exp.setTime(exp.getTime() + (xDays * 24 * 60 * 60 * 1000));
  return exp.toGMTString();
}

// Functions from MacroMedia Dreamweaver for preloading and swapping rollovers

function MM_swapImgRestore() { //v3.0
  var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}

function MM_preloadImages() { //v3.0
  var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}

function MM_findObj(n, d) { //v4.01
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && d.getElementById) x=d.getElementById(n); return x;
}

function MM_swapImage() { //v3.0
  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
   if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}

function MM_showHideLayers() { //v6.0
  var i,p,v,obj,args=MM_showHideLayers.arguments;
  for (i=0; i<(args.length-2); i+=3) if ((obj=MM_findObj(args[i]))!=null) { v=args[i+2];
    if (obj.style) { obj=obj.style; v=(v=='show')?'visible':(v=='hide')?'hidden':v; }
    obj.visibility=v; }
}