// This is a file of (mostly) study-independant functions that are used in both validatecrf and form-visibility

// Debug is a fairly standard-issue debugging flag, it causes annoying messages to come-up constantly
// Mostly when a non-existent element is checked in some way.
var debug = true;


// inc_save stands for Incomplete Save. I.e. when they hit the save button and not the submit button
// The system will go through the usual edit checks, except the usual mandatory errors are ignored.
// Invalid data will still evoke an error message and prevent saving, however, such as putting text
// in a numerical field. (As stuff like this would cause the DB to crash.)
// It is set by the onClick methods of the buttons on the index.asp page, and is not modified anywhere
// else, and is accessed in several places.
var inc_save = false;
var dev_edits = "";

function resetRadioButton(el_name){
   var opts = getElement( el_name.name );
   for(var i =0; i < opts.length; i++){
      opts[i].checked = 0;
   }
}

function expandSeasonInfo(seasonNum){
   var seasonInfo = getElement("seasonInfo"+seasonNum);
   var expandDisplay = getElement("expandDisplay"+seasonNum);
   if( seasonInfo.style.visibility == 'hidden' ){
      seasonInfo.style.visibility = 'visible';
      seasonInfo.style.display = '';
      expandDisplay.innerHTML = "-";
   }else{
      seasonInfo.style.visibility = 'hidden';
      seasonInfo.style.display = 'none';
      expandDisplay.innerHTML = "+";
   }
}

function vote(form){
   if( !check_value('voteResult') ){
      alert("You must select a Option before Voting for this survey");
      return false;
   }else{
      return true;
   }
}

function updatePlayersForEvent(form, script) {
	set_value("updateEvent","");
   set_value("loadEvent",1);
	form.action = script;
	form.submit();
}

function updateEventPlayers(form) {
	set_value("loadEvent","");
   set_value("updateEvent",1);
	form.submit();
}

function validateNewEvent(form) {
	if(!valid("seasonNum","Season #",false,false)){ return false; }
    if(!valid("eventNum","Event #",false,false)){ return false; }
    form.submit();
}

function validateEditEvent(form) {
	if(!valid("editSeasonNum","Season #",false,false)){ return false; }
    if(!valid("editEventNum","Event #",false,false)){ return false; }
    form.submit();
}

function init_object() {
   alert_debug("sajax_init_object() called..")
   try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
   try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
   try { return new XMLHttpRequest(); } catch(e) {}
   alert_debug("XMLHttpRequest not supported");
   return null;
}

function server_request(func_name, uri, args) {
   if (uri.indexOf("?") == -1) { uri += "?"; }
   for(var key in args) {
      uri += escape(key) + "=" + escape(args[key]) + "&";
   }
   uri = uri.substring(0,uri.lastIndexOf('&'));
   var xmlHttp = XmlHttp.create();
   var async = true;
   xmlHttp.open("GET", uri, async);
   xmlHttp.onreadystatechange = function () {
      if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
         if(func_name == "addTableRow") {
            addTableRow(args.nested_table, xmlHttp.responseXML.documentElement);
         }else if( func_name == 'statusUpdate' ){
         }
      }
   }
   xmlHttp.send(null);
}

function addRow(table_name) {
   var add_button    = getElement("add_row_" + table_name);
   var inact_button  = getElement("inact_row_" + table_name);
   var react_button  = getElement("react_row_" + table_name);
   var update_button = getElement("update_row_" + table_name);
   
   if(add_button    != null)add_button.disabled    = 1;
   if(inact_button  != null)inact_button.disabled  = 1;
   if(react_button  != null)react_button.disabled  = 1;
   if(update_button != null)update_button.disabled = 1;
   
   var args = new Object();
   args.section_id      = document.fm.section_id.value;
   args.tab_id          = document.fm.tab_id.value;
   args.keyid           = document.fm.keyid.value;
   args.sub_keyid       = document.fm.sub_keyid.value;
   args.parent_keyid    = document.fm.parent_keyid.value;
   args.select_audit_id = document.fm.select_audit_id.value;
   args.nested_table    = table_name;
   args.nested_row      = getElement("nested-nextrow-"+table_name).value;
   args.num_inact       = getElement("inact-count-"+table_name).value;
   
   server_request("addTableRow","/study/crf/nested.asp",args);
   

}

function addTableRow(table_name, tr) {
   var table    = document.getElementById("nested-" + table_name);
   
   if(tr.tagName == "error") {
      //the return result is an error message
      //rather than a new row... looks like they hit the row limit
      alert(tr.firstChild.nodeValue);
   } else {
      var tbody    = table.lastChild;
      var lastRow  = tbody.lastChild;
      
      tbody.insertBefore(changeXmlIntoHtml(tr),lastRow);
      alterNextRowVar(table_name,1);
      checkVisibility();
   }
   
   var add_button    = getElement("add_row_" + table_name);
   var inact_button  = getElement("inact_row_" + table_name);
   var react_button  = getElement("react_row_" + table_name);
   var update_button = getElement("update_row_" + table_name);
   
   if(add_button    != null)add_button.disabled    = 0;
   if(inact_button  != null)inact_button.disabled  = 0;
   if(react_button  != null)react_button.disabled  = 0;
   if(update_button != null)update_button.disabled = 0;
}

function alterNextRowVar(table_name, val) {
   var nextrow = getElement("nested-nextrow-"+table_name);
   nextrow.value = "" + (parseInt(nextrow.value) + val);
}

function alterInactCount(table_name) {
   var inactcount = getElement("inact-count-"+table_name);
   var count = 0;
   
   for(var i = parseInt(getElement("nested-nextrow-" + table_name).value) - 1; i >= 1; i--) {
      var row_ind  = getElement(table_name + ".INACT1A.ROWID1N." + i);
      if(row_ind != null && row_ind.value == 't') {
         count++;
      }
   }
   
   inactcount.value = count + parseInt(getElement("inact-count-base-" + table_name).value);
}

function changeXmlIntoHtml(element) {
   if(element.nodeType == 3) {
      var text = element.nodeValue;
      text = text.replace(/^\s*|\s*$/g,"");
      var new_element = document.createTextNode(text);
      return new_element;
   } else  if(element.nodeType == 1) {
      //create new html element from xml element
      
      var new_element;
      
      if(document.all) {
         var create_string = "<" + element.tagName;
         
         if(element.getAttribute("id") != '') {
            create_string += " style=\"" + element.getAttribute("id") + "\" ";
         }
         if(element.getAttribute("style") != '') {
            create_string += " style=\"" + element.getAttribute("style") + "\" ";
         }
         
         //copy attributes
         if(element.attributes) {
            for(var index = 0; index < element.attributes.length; index++) {
               var att = element.attributes[index];
               create_string += " " + att.name + "=\"" + att.value + "\" ";
            }
         }
         
         create_string += " >";
         
         new_element = document.createElement(create_string);
         
         //copy style
         if(element.style) {
            new_element.style = element.style;
         }
      } else {
         new_element = document.createElement(element.tagName);
         
         //copy attributes
         if(element.attributes) {
            for(var index = 0; index < element.attributes.length; index++) {
               var att = element.attributes[index];
               new_element.setAttribute(att.name,att.value);
            }
         }
      }
      
      
      //copy children
      if(element.hasChildNodes()) {
         for(var index = 0; index < element.childNodes.length; index++) {
            var child = changeXmlIntoHtml(element.childNodes[index]);
            
            if(child != null) {
               new_element.appendChild(child);
            }
         }
      }
      
      return new_element;
   }
   return null;
}

function updateRowStatus(table_name) {
   for(var i = parseInt(getElement("nested-nextrow-" + table_name).value) - 1; i >= 1; i--) {
      var rowcheck = getElement("markrow_" + i + "_" + table_name);
      var row_ind  = getElement(table_name + ".INACT1A.ROWID1N." + i);
      if(rowcheck != null && rowcheck.checked && row_ind != null && row_ind.value == 't'){
         reactRow(table_name,i);
         row_ind.value = "f";
         rowcheck.checked = 0;
      }
      if(rowcheck != null && rowcheck.checked && row_ind != null && row_ind.value == 'f'){
         inactRow(table_name,i);
         row_ind.value = "t";
         rowcheck.checked = 0;
      } else if(getElement("new_" + i + "_" + table_name) != null && row_ind != null && row_ind.value == 't') {
         inactRow(table_name,i);
         row_ind.value = "t";
         rowcheck.checked = 0;
      }
   }
   alterInactCount(table_name);
}

function inactRows(table_name) {
   for(var i = parseInt(getElement("nested-nextrow-" + table_name).value) - 1; i >= 1; i--) {
      var rowcheck = getElement("markrow_" + i + "_" + table_name);
      var row_ind  = getElement(table_name + ".INACT1A.ROWID1N." + i);
      if((rowcheck != null && rowcheck.checked) || (row_ind != null && row_ind.value == 't')) {
         inactRow(table_name,i);
         if(row_ind != null) row_ind.value = "t";
         if(rowcheck != null) rowcheck.checked = 0;
      } else if(getElement("new_" + i + "_" + table_name) != null && row_ind != null && row_ind.value == 't') {
         inactRow(table_name,i);
         row_ind.value = "t";
         rowcheck.checked = 0;
      }
   }
   alterInactCount(table_name);
}

function reactRows(table_name) {
   for(var i = 1; i < parseInt(getElement("nested-nextrow-"+table_name).value) - 1; i++) {
      var rowcheck = getElement("markrow_" + i + "_" + table_name);
      var row_ind  = getElement(table_name + ".INACT1A.ROWID1N." + i);
      if((rowcheck != null && rowcheck.checked) || (row_ind != null && row_ind.value == 'f')){
         reactRow(table_name,i);
         row_ind.value = "f";
         rowcheck.checked = 0;
      }
   }
   alterInactCount(table_name);
}

function  inactRow(table_name, rownum) {
   var has_never_been_saved = getElement("new_" + rownum + "_" + table_name);
   
   if(has_never_been_saved == null) {
      var row = getElement("row_" + rownum + "_" + table_name);
      row.style.background = "#bbbbbb";
      changeChildrenActiveStatus(row,1);
   } else {
      var row     = getElement("row_" + rownum + "_" + table_name);
      var control = getElement("control-" + table_name);
      
      if(row.nextSibling == control) {
         var tbody = row.parentNode;
         tbody.removeChild(row);
         alterNextRowVar(table_name,-1);
      } else {
         var rowcheck = getElement("markrow_" + rownum + "_" + table_name);
         if(rowcheck.checked)  //only throw this warning once the actual deactivation has been requested
            alert('Row number ' + rownum + ' is new and has other new rows after it.\nIt will not be removed, but it will be marked as inactive.\nTo remove this row, please remove all other rows after it.');
         row.style.background = "#bbbbbb";
         changeChildrenActiveStatus(row,1);
      }
   }
}

function  reactRow(table_name, rownum) {
   var row = getElement("row_" + rownum + "_" + table_name);
   row.style.background = "#ffffff";
   changeChildrenActiveStatus(row,0);
}

function changeChildrenActiveStatus(element,disabled) {
   if(element.hasChildNodes()) {
      for(var index = 0; index < element.childNodes.length; index++) {
         var child = element.childNodes[index];
         if(child.nodeType == 1) { 
            var tagname = child.tagName.toLowerCase();
            var type    = child.getAttribute("type");
            var nameAtt = child.attributes["name"];
            
            if(type != "hidden" && (nameAtt == null || nameAtt.value.substring(0,8) != "markrow_")) {
               if(tagname == "input" || tagname == "textarea" || tagname == "select" || tagname == "button"){
                  child.disabled = disabled;
               } else {
                  changeChildrenActiveStatus(child,disabled);
               }
            }
         }
      }
   }
}

function changeChildrenSelectDisplay(element, hide, all_selects) {
   
   if(!hide){
      hide = "hide";
   }
   
   if(!all_selects) {
      all_selects = 'all';
   }
   
   if(element.hasChildNodes()) {
      for(var index = 0; index < element.childNodes.length; index++) {
         var child = element.childNodes[index];
         if(child.nodeType == 1) { 
            var tagname = child.tagName.toLowerCase();
            var type    = child.getAttribute("type");
            var nameAtt = child.attributes["name"];
            if(tagname == "select"){
               if(hide == "hide") {
                  if(all_selects == 'all' || detectCollision(child)) {
                     child.style.visibility = "hidden";
                  }
               } else {
                  child.style.visibility = "visible";
               }
            } else {
               changeChildrenSelectDisplay(child, hide, all_selects);
            }
         }
      }
   }
}

function detectCollision(element) {
   var tooltip = document.getElementById('tooltip');
   
   var elem  = new Object();
   elem.xMin = findPosX(element);
   elem.yMin = findPosY(element);
   elem.xMax = elem.xMin + element.clientWidth;
   elem.yMax = elem.yMin + element.clientHeight;
   
   var tt  = new Object();
   tt.xMin = findPosX(tooltip);
   tt.yMin = findPosY(tooltip);
   tt.xMax = tt.xMin + tooltip.clientWidth;
   tt.yMax = tt.yMin + tooltip.clientHeight;
   
   if ( elem.xMin > tt.xMax
      || tt.xMin > elem.xMax
      || elem.yMin > tt.yMax
      || tt.yMin > elem.yMax
   )      return false;
   else   return true;
}

//These functions will find an elements absolute x and y position
//in a document
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;
}

// This is the onReset Handler
// It will always return false, and that's the way I like it.
// It needs to call checkVisiblity() AFTER the reset, as it needs to
function check_reset() {
  if (confirm("Are you sure you want to reset this form?")) {
     document.fm.reset();
     checkVisibility();
     reset_backgrounds();
     return false;
  } else {
     return false;
  }

}

function check_click(href) {
   if(getElement('form_changed') && check_value('form_changed') == 'true') {
      if (!confirm('Are you sure you want to leave this form? \n\nAny unsaved changes will be lost.')) {
         
         if(!href) {
            return false;
         } else {
            return;
         }
      }
   }
   
   if(href) {
      window.location.href = href
   } else {
      return true;
   }
}

function printButton() {
   document.fm.action = "print-record.asp";
   document.fm.submit();
}



// -----------------------------------------------------------
//   View query pop-up
//
//   This opens a little pop-up window that displays some
//   critical-info about the query_id passed in.
// -----------------------------------------------------------
function query_view_popup(query_id,table_id,printable) {

   var height = window.screen.height, width = window.screen.width;
   var pop_height = Math.round(height / 2 );
   var pop_width  = Math.round(width  / 2 );
   var pop_top    = Math.round(height * 1 / 4);
   var pop_left   = Math.round(width  * 1 / 4);
   var pop_size_str = "width=" +pop_width +", height=" + pop_height +", top=" + pop_top + " left=" + pop_left;

   var table = (table_id  != null) ? "&table_id="+table_id:"";
   var print = (printable != null) ? "&print="   +table_id:"";
   
   var catalog = window.open("/study/query/query_view.asp?pop_up=true&query_list_id=" + query_id+table+print,
                             "query_popup_" + query_id, pop_size_str + " scrollbars, resizeable");
}





// This function just loops through all of the elements in the form, and resets the background color to white/Transparent.
function reset_backgrounds() {
   var el = document.fm.elements;

   for (var i = 0; i<el.length; i++) {
       //  This just 'resets' the element background color from red back to white,
       //  if any elements should be red, the rest of this function should fix that.
       if (el[i].style.backgroundColor == "red"){
           if ( el[i].type == 'radio') {
             el[i].style.backgroundColor = "transparent";
           } else if ( el[i].type == 'text' || thisElement.type == 'select-one' ||  thisElement.type == 'textarea' ||  thisElement.type == 'password') {
             el[i].style.backgroundColor = "white";
           } else if ( el[i].type == 'checkbox') {
             el[i].style.backgroundColor = "transparent";
           }
       }
   }

   return true;
}

// This function is called when the "save" button is pushed, it does a bunch of cool stuff
function incSaveButton() {
   inc_save = true;
   if ( validateForm(fm)) {
      show_save_layer(); //display MM saying that we are saving the info
      changeChildrenActiveStatus(getElement("fm"),0);
      document.fm.submit();
      return true;
   } else {
      return false;
   }
}


function SaveButton(form) {
   inc_save = false;
   if (validateForm(form)) {
      show_save_layer(); //display MM saying that we are saving the info
      changeChildrenActiveStatus(getElement("fm"),0);
      document.fm.submit();
      return true;
   } else {
      return false;
   }
}

var managedEvents = new Object();
function updateEventToManage(row, keyid, skeyid, href) {
   var eventID = keyid + "-" + skeyid + "-" + row;
   
   if(check_checked( "managed" + row ) == 0 ){
      managedEvents[eventID] = true;
      set_value("event_to_manage",eventID);
      set_value("reference", href );
   }else{
      managedEvents[eventID] = false;
      set_value("event_to_manage",'');
      set_value("reference",'');
   }
}

function statusUpdates(trkid,name){
   var evtsUpdated = 0;
   for(var key in managedEvents) {
       if( managedEvents[key] == true ){
          evtsUpdated++;
          var args = new Object();
          var temp = new Array();
          temp = key.split("-");
          var keyid = temp[0];
          var skeyid = temp[1];
          var row = temp[2];
          args.keyid = keyid;
          args.sub_keyid = skeyid;
          args.evt_status = trkid;
          server_request("statusUpdate","/study/reports/statusUpdate.asp",args);
          var eventRow = document.getElementById("event" + row);
          var tbody = eventRow.parentNode;
          tbody.removeChild(eventRow);
          managedEvents[key] = false;
       }
   }
}


function manage_event(form) {
   
   var eventToManage;
   var evnts = 0;
   for(var key in managedEvents) {
      //uri += escape(key) + "=" + escape(args[key]) + "&";
      if( managedEvents[key] == true ){
         eventToManage = key;
         evnts++;
      }
   }
   
   var height = window.screen.height, width = window.screen.width;
   var pop_height = Math.round(675);
   var pop_width  = Math.round(800);
   var pop_top    = Math.round(height * 1 / 4);
   var pop_left   = Math.round(width  * 1 / 4);
   var pop_size_str = "width=" +pop_width +", height=" + pop_height +", top=" + pop_top + " left=" + pop_left;
   
   if( eventToManage ){
      if( evnts > 1 ){
         alert("You have selected more than one event.  Only one event can be managed at a time.");
      }else{
         top.frames['adjudicateFrame'].location.href = "/study/reports/manage_event.asp?event=" + eventToManage + "&event_status=" + check_value("event_status") + "&event_type=" + check_value("event_type");
      }
   }else{
      alert("You must select an Event to Manage");
   }
}

function adjudicate_event(form,keyid,skeyid) {
   var eventToManage;
   var evnts = 0;
   for(var key in managedEvents) {
      //uri += escape(key) + "=" + escape(args[key]) + "&";
      if( managedEvents[key] == true ){
         eventToManage = key;
         evnts++;
      }
   }
   if( eventToManage ){
      if( evnts > 1 ){
         alert("You have selected more than one event.  Only one event can be Adjudicated at a time.");
      }else{
         var temp = new Array();
         temp = eventToManage.split("-");
         keyid = temp[0];
         skeyid = temp[1];
         top.frames['adjudicateFrame'].location.href = 'adjudicate.asp?adjudicateEvent=1&keyid=' + keyid + "&sub_keyid=" + skeyid;
      }
   }else{
      alert("You must select an Event to Adjudicate");
   }
}

function mmr_event(form,keyid,skeyid) {
   var eventToManage;
   var evnts = 0;
   for(var key in managedEvents) {
      //uri += escape(key) + "=" + escape(args[key]) + "&";
      if( managedEvents[key] == true ){
         eventToManage = key;
         evnts++;
      }
   }
   if( eventToManage ){
      if( evnts > 1 ){
         alert("You have selected more than one event.  Only one event can have a Medical Monitor Review at a time.");
      }else{
         var temp = new Array();
         temp = eventToManage.split("-");
         keyid = temp[0];
         skeyid = temp[1];
         top.frames['adjudicateFrame'].location.href = '../crf/adjsys_index.asp?section_id=2&tab_id=1&keyid=' + keyid + "&sub_keyid=" + skeyid;
      }
   }else{
      alert("You must select an Event to Medical Monitor Review");
   }
}

function display_event_detail(pat_id) {
   var height = window.screen.height, width = window.screen.width;
   var pop_height = Math.round(650);
   var pop_width  = Math.round(950);
   var pop_top    = Math.round(height * 1 / 4);
   var pop_left   = Math.round(width  * 1 / 4);
   var pop_size_str = "width=" +pop_width +", height=" + pop_height +", top=" + pop_top + " left=" + pop_left;

   var href = '/study/crf/adjsys_index.asp?section_id=1&tab_id=3&keyid=' + pat_id;
   var catalog = window.open(href,"manage_event", pop_size_str + " scrollbars");
}

function checkDocType( ){
   var element = getElement("newDocType");
   if( element && element.value == 2 ){
      unhide("newsTable");
   }else{
      hide("newsTable");
      set_value("newNewsMonth","");
      set_value("newNewsYear","");
   }
}

function deleteStudyDocument( doc_id, form ){
   var docName = getElement('doc_name' + doc_id);
   if( !confirm("Are you sure you want to Delete the Document: " + docName.value )){
      return false;
   }
   set_value("deleteDoc" + doc_id, 1);
   form.submit();
}

function documentTypeUpdate( type_id, form ){
   if( !valid("update_type_name" + type_id, "Document Type Name")){ return false; };
   if( !valid("update_doc_loc" + type_id, "Document Type Location")){ return false; };
   var doc_loc = check_value( "update_doc_loc" + type_id );
   if( !doc_loc.match(/^\/.*$/)){
      alert("Document Type Location must begin with a '/' character");
      tag("update_doc_loc" + type_id);
      return false;
   }
   form.submit();
}

function documentTypeInsert( form ){
   if( !valid("insert_type_name", "Document Type Name")){ return false; };
   if( !valid("insert_doc_loc", "Document Type Location")){ return false; };
   var doc_loc = check_value( "insert_doc_loc" );
   if( !doc_loc.match(/^\/.*$/)){
      alert("Document Type Location must begin with a '/' character");
      tag("insert_doc_loc");
      return false;
   }
   form.submit();
}

function updateStudyDocument( doc_id, form ){
   var type = getElement('doc_type' + doc_id);
   if( !valid("doc_name" + doc_id, "Document Title")) { return false };
   if(type.value == 2 ){
      //Uploading a Newsletter
      if( !valid_num( "newsMonth" + doc_id, "Newsletter Month", 2, false, null, null, true )){ return false };
      var month = getElement('newsMonth' + doc_id);
      if( month.value > 12 || month.value < 1 ){ 
         alert("Newsletter Month Invalid: Month must be between 1 and 12");
         tag("newsMonth" + doc_id);
         return false;
      }
      var monthVal = month.value;
      if( !monthVal.match(/\d\d/) ){
         alert("Newsletter Month must be specified as a 2-Digit Month");
         tag("newsMonth" + doc_id);
         return false;
      }
      if( !valid_num( "newsYear" + doc_id, "Newsletter Year", 4, false, null, null, true )){ return false };
      var year = getElement('newsYear' + doc_id);
      var yearVal = year.value;
      if( !yearVal.match(/\d\d\d\d/) ){
         alert("Newsletter Year must be specified as a 4-Digit Year");
         tag("newsYear" + doc_id);
         return false;
      }
      if ( year.value < 2005 ){
         alert("Newsletter Year Invalid: Year must be after 2005");
         tag("newsYear" + doc_id);
         return false;
      }
   }
   if( getElement("group_map" + doc_id).value == '') { 
      alert("You must specify a Group to update this Study Document");
      tag('group_map' + doc_id);
      return false
   };
   form.submit();
}

function newDocumentUpload( form ){
   var type = getElement('newDocType');
   if( !valid("newDocType", "Document Type")){ return false; };
   if( !valid("newDocName", "Document Title")) { return false };
   if(type.value == 2 ){
      //Uploading a Newsletter
      if( !valid_num( "newNewsMonth", "Newsletter Month", 2, false, null, null, true )){ return false };
      var month = getElement('newNewsMonth');
      if( month.value > 12 || month.value < 1 ){ 
         alert("Newsletter Month Invalid: Month must be between 1 and 12");
         tag("newNewsMonth");
         return false;
      }
      var monthVal = month.value;
      if( !monthVal.match(/\d\d/) ){
         alert("Newsletter Month must be specified as a 2-Digit Month");
         tag("newNewsMonth");
         return false;
      }
      if( !valid_num( "newNewsYear", "Newsletter Year", 4, false, null, null, true )){ return false };
      var year = getElement('newNewsYear');
      var yearVal = year.value;
      if( !yearVal.match(/\d\d\d\d/) ){
         alert("Newsletter Year must be specified as a 4-Digit Year");
         tag("newNewsYear");
         return false;
      }
      if ( year.value < 2005 ){
         alert("Newsletter Year Invalid: Year must be after 2005");
         tag("newNewsYear");
         return false;
      }
      var order = getElement('newOrder');
      if( order.value == '' ){
         alert("Order is required for Newsletter Documents");
         tag('newOrder');
         return false;
      }
   }
   if( getElement("group_map").value == '') { 
      alert("You must specify a Group for the New Study Document");
      tag('group_map');
      return false
   };
   
   var file = getElement('new_upload_file');
   if( file.value == '' ){
      alert("Study Document File Invalid: You must specify a file to upload");
      tag('new_upload_file');
      return false;
   }
   form.submit();
}

function resetDocForm( ){
   hide("newsTable");
}

function definitionPopup(theURL, winName, features) {
  window.open(theURL,winName,features);
}

function updateEventStatus(form, keyid, sub_keyid){
   set_value("doUpdateStatus",1);
   set_value("evt_status",check_value("staChange_track"));
   set_value("evt_type", check_value("staChange_type"));
   form.submit();
}

function openIFrame(IFrameID, URL){
   
   frames[IFrameID].location.href = URL;
   //ifId=gmobj(IFrameID);
   //ifId.location.href=URL; // Opera Bug Fix. ifId.src=URL
}

function ajaxRequestHTML(el_id, url, data) {
    $.ajax({
        "type": "GET",
        "context": document.getElementById(el_id),
        "url": url,
        "data": data,
        "dataType": "json",
        "contentType": "application/json",
        "success": function( data, textStatus, obj) {
            if(data.success == 1 ) {
                $(this).html(data.html);
            } else {
                $(this).html("An Error occurred with the request: " . data.message);
            }
        },
        "timeout": 100000,
        "error": function (XMLHttpRequest, textStatus, errorThrown) {
            alert("ERROR: " . errorThrown);
            $(this).html("An Error occurred with the request: " . errorThrown);
        }
    });
}


function getElement(name) {
   var list = document.getElementsByName(name);
   
   if(list && list.length > 0) {
      if(list.length == 1) { 
         return list[0];
      } else {
         return list;
      }
   } else {
      return document.getElementById(name);
   }
}


function stackTrace(f_name) {
   if(debug) {
      var trace = (!document.all)?stackTraceFF():stackTraceIE(f_name);
      formatStackTrace(trace);
   }
}

function stackTraceFF() {
   var e = new Error('force an error for a trace');
   
   var lines = e.stack.split("\n");
   
   var output = new Array();
   var count = 0;
   for(var i = 0; i < lines.length; i++) {
      var details = new Array();
      
      if(lines[i].indexOf("Error") == 0) continue;
      if(lines[i].indexOf("@:0") == 0) continue;
      if(lines[i] == "") continue;
      
      var func_details = lines[i].split("@");
      var url          = func_details[1].substring(0,func_details[1].lastIndexOf(':'));
      var line_number  = func_details[1].substring(func_details[1].lastIndexOf(':')+1);
      
      var reg = new RegExp("([A-Za-z_]+)\\s*\\((.*?)\\)");
      var matches = reg.exec(func_details[0]);
      
      var function_name = matches[1];
      var function_args = matches[2];
      
      var args = function_args.split(",");
      for(var j = 0; j < args.length; j++) {
         var quoted = new RegExp("\"(.*?)\"");
         
         var q_m = quoted.exec(args[j])
         if(q_m) {
            args[j] = q_m[1];
         }
      }
      
      details[0] = function_name;
      details[1] = args;
      details[2] = line_number;
      details[3] = url;
      output[count++]  = details;
   }
   return output;
}

function stackTraceIE(f_name) {
   var callers = new Array();
   
   /*
   **
   **  Collect the stack trace 
   **
   */
   var i = 1;
   do {
      f_name += ".caller";
      var caller = eval(f_name);
      
      if(caller != null) {
         var reg = new RegExp("function\\s+([A-Za-z_]+)\\s*\\(");
         var matches = reg.exec(caller.toString());
         
         if(matches != null){
            var tds = new Array;
            var args = new Array;
            
            for(var j = 0; j < caller.arguments.length; j++) {
               args[j] = caller.arguments[j];
            }
            
            tds[0] = matches[1];
            tds[1] = args;
            
            callers[i++] = tds;
         }
      }
   } while(caller != null);
   
   if(stackTraceIE.caller != null) {
      var args = new Array;
      for(var j = 0; j < stackTraceIE.caller.arguments.length; j++) {
         args[j] = stackTraceIE.caller.arguments[j];
      }
      
      var reg = new RegExp("function\\s+([A-Za-z_]+)\\s*\\(");
      var matches = reg.exec(stackTraceIE.caller.toString());
      var tds = new Array;
      tds[0] = matches[1];
      tds[1] = args;
      callers[0] = tds;
   }
   return callers;
}

function formatStackTrace(callers) {
   /*
   **
   **  Format the stack trace
   **
   */
   var alert_str = "";
   for(var j = 0; j < callers.length; j++) {
      var previous = (j < (callers.length - 1))?callers[j+1][0]:"root";
      
      var arguments = new String;
      for(var k = 0; k < callers[j][1].length; k++) {
         if(arguments == "") {
            arguments = '<font color="#FF0000">"' + callers[j][1][k] + '"</font>';
         } else {
            arguments += " , " + '<font color="#FF0000">"' + callers[j][1][k] + '"</font>';
         }
      }
      
      /*
      **  are there line numbers?
      */
      var line_number = "";
      if(callers[j].length >= 3 && j < (callers.length - 1)) {
         line_number = '&nbsp;&nbsp;At Line:&nbsp;&nbsp;<font color="#FF0000">' + callers[j+1][2] + '</font>';
      }
      var file = "";
      if(callers[j].length == 4 && j < (callers.length - 1)) {
         var file_name = (callers[j+1][3] == "")?"html file":callers[j+1][3];
         file = '<br />in the file: <font color="#FF0000">' + file_name + '</font>';
      }
      
      var function_call = '<font color="#FFFF00">' + callers[j][0] + "</font>(" + arguments + ") " + line_number + file;
      
      alert_str = '<tr><td bgcolor="#8899CC">' + previous + '</td>' + 
            '<td bgcolor="#AAAAAA" >called: </td>' + 
            '<td bgcolor="#999999">' + function_call + "</td></tr>" + 
            alert_str;
   }
   
   alert_str  = "<table>" + alert_str + "</table>";
   
   
   /*
   **
   ** Write the stack trace to the debugging window
   **
   */
   write_debug(alert_str);
}

var debug_window;
function write_debug(information, clear) {
   if(debug_window == null || debug_window.closed) {
     debug_window = window.open("","");
     debug_window.document.write('<html><body><span id="1">');
   }
   if (clear) {
      debug_window.document.getElementById("1").innerHTML = '';
   }
   debug_window.document.write("<br /><hr/><br />");
   debug_window.document.write(information);
}

//------------------------------------------------------------------------
//      This function checks to see if the Deviation Master actually
//      deviated the form
//------------------------------------------------------------------------

function check_For_Deviation() {   
   var deviation_master = check_value("DEVIATION_MASTER");
   if( deviation_master == 1 ){
      if( check_value("DEV_EDITS") ){
         if(!confirm("You are a Deviation Master\nThe following edits were by-passed\n\n" + check_value('DEV_EDITS') )) {
            set_value('DEV_EDITS','');
            return true;
         }
         if(check_value('DEV_SPONSOR') == ''){
            alert("You must specify the Sponsor who approved this deviation");
            return true;
         }
         if(check_value('DEV_REASON') == ''){
            alert("You must specify the Reason for this deviation");
            return true;
         }
         if(document.all['DEV_REASON'].value.length > 1000){
            alert("The reason for deviation has a maximum length of 1000 characters.\n" +
            "You have entered " + document.all['DEV_REASON'].value.length + " characters\n\n" +
            "Please reduce the Reason for Deviation length");
            return true;
         }
         return false;
      }else{
         alert("You are a Deviation Master\n\nNo edits were by-passed\n\nPlease have the site re-enter their data");
         return true;
      }
   }else{
      return false;
   }
}


// Tag causes the element to be highlighted red, and then focus() it.
function tag( el_name) {
  if ( !getElement(el_name) && debug ) {
     alert("Element: " + el_name + " Does NOT exist!!!");
     return null;
  }
  if ( !getElement(el_name).type &&  getElement(el_name)[0].type == "radio" ) {
     var radios = getElement(el_name);
     
     for (var i=0; i < radios.length; i++) {
        radios[i].style.backgroundColor = "red";
     }
     
     radios[0].focus();
  } else {
    getElement(el_name).style.backgroundColor = "red";
    getElement(el_name).focus();
  }
  return true;
}


function valid_time( name, desc, mand  ) {
  if(is_hidden(name)) return true;
  
  if (mandatory == null) {
     mandatory = false;
  }
  
  if ( getElement(el_name).value == '') {
     if (inc_save || !mand) {
        return true;
     }
  }
  
  // This function checks for military time format in an input element.
  if (!validate_required(name,desc)) return false;

  var value = getElement(name).value;
  var err_msg = "";

 
  // Grab the question text if it was not specified.
  if (!desc) {
      desc = getQuestionDesc(name);
  }

  if ( value.length != 5) {
     err_msg = "Time Format not Recognized, please use: HH:MM and 24-hour time.";
  } else {
     var time = value.split(":", 2);
     var hour = time[0];
     var min  = time[1];

     if (isNaN( parseInt(hour) ) || isNaN( parseInt(min))) {
             err_msg = "Time Format not Recognized, please use: HH:MM and 24-hour time. For example: 14:35 ";
     } else {
         var hours = parseInt(hour);
         var mins = parseInt(min);
         if ( hours >= 24 || hours < 0)
             err_msg = "Hours must be between 0 - 23 ";
         else
            if ( mins >= 60 || mins < 0)
                 err_msg = "Minutes must be between 0 - 59 ";
            else
                if ( time.length != 2 )
                     err_msg = "Please use a ':' between the minutes and hours";
     }
  }

  if (err_msg != "" ) {
     alert( desc + ": " + err_msg );
     getElement(name).style.backgroundColor = "red";
     getElement(name).focus();
     return false;
  }

  return true;
}

function valid_three_date(el_name, el_desc, mandatory, format) {
   if (!el_desc) {
       el_desc = getQuestionDesc(el_name);
   }
   
   var day   = el_name + "_DAY";
   var month = el_name + "_MONTH";
   var year  = el_name + "_YEAR";
   
   if(is_hidden(day) && is_hidden(month) && is_hidden(year)) return true;
   
   if(!valid_num(day,"The day entry for " + el_desc,2,false,null,null,mandatory)) return false;
   if(!valid_num(month,"The month entry for " + el_desc,2,false,null,null,mandatory)) return false;
   if(!valid_num(year,"The year entry for " + el_desc,4,false,null,null,mandatory)) return false;
   var months   = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
   
   if(check_value(day) != "" || check_value(month) != "" || check_value(year) != "") {
      set_value(el_name, check_value(day) + "-" + months[parseInt(check_value(month)) - 1] + "-" + check_value(year));
   }
   
   return valid_date(el_name, el_desc,mandatory, format, true);
   return true;
}


function three_date_focus(shift, shift_from, shift_to) {
   //if(getElement(shift_from).value.length == shift) {
   //   getElement(shift_to).focus();
   //   getElement(shift_to).select();
   //}
}

function mark_all_red(group, prefix) {
   for (var i = 0; i < group.length; i++) {
      getElement(prefix + group[i]).style.background = "red";
   }
   getElement(prefix + group[0]).focus();
}

//------------------------------------------------------------------------
//      This other Data validation function calls DateFormat
//      and highlights bad data in red.
//      DateFormat generates its own error messages, so we only need to tag
//      the offending element.
//      valid_date will also convert the date to the standard DD-MON-YYYY
//      format, using the value returned by DateFormat.
//------------------------------------------------------------------------

var error_msg = "";

function valid_date(el_name, el_desc, mandatory, format, three_date, future, deviation) {
   if(is_hidden(el_name)) return true;

   if (!el_desc) {
       el_desc = getQuestionDesc(el_name);
   }

   if ( getElement(el_name).value == '') {
      if (mandatory != false) {
          if (inc_save) {
             return true;
          }
          if( deviation == 1){
             dev_edits = check_value('DEV_EDITS') + el_desc + " was not filled out\n";
             set_value('DEV_EDITS', dev_edits);
             return true;
          }          

          alert(el_desc + " still needs to be filled-out");
          tag(el_name);
          return false;
      } else {
          return true;
      }
   } else {

        var new_date = DateFormat( getElement(el_name).value, el_desc, format, three_date, future );

        if (new_date == false || typeof new_date == 'undefined' || new_date == "") {
            alert(error_msg);
            error_msg = "";
            
            if(three_date) {
               mark_all_red(["_DAY","_MONTH","_YEAR"],el_name);
               
            } else {
               tag(el_name);
            }
            return false;
        } else {
            getElement(el_name).value = new_date;
        }

   }
   return true;
}

// This function checks if the UNKNOWN checkbox has been checked, and if not,
// it will validate the Date field as normal
// This should ONLY be called on a date field with an _UNK sub-question checkbox.

function valid_date_with_unk(el_name, el_desc, mandatory, format, unk_name, three_date, future, deviation_master) {
   if (unk_name == null) {
      unk_name = el_name + "_UNK";
   }
   
   if(is_hidden(el_name) && is_hidden(unk_name)) return true;
   
   if (!el_desc) {
      el_desc = getQuestionDesc(el_name);
   }
   
   
   if(check_checked(unk_name) == 0) {
      // "Unknown" has been checked, so we don't need to validate the date,
      // however, if the date has been filled-out, there's a problem,
      // We'll need to warn the user, and we should probably prevent the
      // saving of this form until it is fixed
      
      if (check_value(el_name) != "") {
         alert(el_desc + " : 'Unknown' has been checked for this field, but the field has been filled-out, please verify ");
         tag(el_name);
         return false;
      }
      
      return true;
      
   } else {
      return valid_date(el_name, el_desc, mandatory, format, three_date, future, deviation_master);
   }
}





// This will return the number of days between the two dates.
// It takes in the element names of the two dates.
// If it is passed the string 'NOW' for date1, the system will default
// to the current date.
// In the case that either of the dates are blank,
// this will return null.

function compare_dates( date1, date2, days ) {
   //-------------------------------------------------------------------
   // If date1 is later than date2, this will return a positive number
   // In other words, if:
   // date1 => Now
   // date2 => Then
   // then compare_dates( date1, date2 ) will return a positive number.
   //-------------------------------------------------------------------
   
   var date_str1 = new String;
   if ( date1 == "NOW" ) {
      date_str1 = getElement("today").value;
   } else {
      date_str1 = fix_date(date1);
   }
  
	var numberDays = 1000 * 60 * 60 * 24;
	
	if( days ){
		numberDays = numberDays * days;
	}
	
   var date_str2 = new String;
   if ( date2 == "NOW" ) {
      date_str1 = getElement("today").value;
   } else {
      date_str2 = fix_date( date2 );
   }
   
   // Turn the milliseconds to days.
   var days_between = (Date.parse( date_str1 ) - Date.parse( date_str2 )) / numberDays;
	
   return days_between;
}


function verify_initials( element, mandatory ){
   
   var initials = getElement( element ).value;
   if( mandatory ){
      if( initials.match( /[a-zA-Z][a-zA-Z\-][a-zA-Z]/ ) ){
         return true;
      }
      return false;
   }
   if( initials != "" ){
      if( initials.match( /[a-zA-Z][a-zA-Z\-][a-zA-Z]/ ) ){
         return true;
      }
      return false;
   }
   return true;   
}

// fix_date prepares any valid_date so it can be accepted by Javascript's Date.parse routine.
// I.e. (DD MON YYYY) (no dashes)
// This mean whacking off the dashes and/or adding Months and days so it matches.
function fix_date(date_value) {

    // Ok, we need to allow dates with ONLY YYYY for the date.  to
    // the year to make it compatible with javascript's dates.

    var no_day_or_month = date_value.match(/^\W*[0-9][0-9][0-9][0-9]\W*$/);

    var no_day   = date_value.match(/^\W*[a-zA-Z]+\W+[0-9][0-9][0-9][0-9]/);

    if (no_day_or_month) {
       // In this case, we add January 1st
       date_value = '1 JAN ' + date_value;

    } else if (no_day) {
       // In this case, just add the first.
       date_value = date_value.replace('-', ' ');
       date_value = '1  ' + date_value;

    } else {
       date_value = date_value.replace('-', ' ');
       date_value = date_value.replace('-', ' ');
    }

    if (debug && Date.parse( date_value ) == NaN) {
       alert("BADDD Fix-Date : " + date_value);
    }

   return date_value;
}


function adj_date(date1,time,type) {
   
   var date_str;
   
   if(date1 == "NOW") {
      date_str = getElement("today").value;
   } else {
      date_str = fix_date(date1);
   }
   
   var date = new Date(date_str);
   
   if(type == "month" || type == "months") {
      date.setMonth(date.getMonth() + time);
   } else if(type == "day" || type == "days") {
      date.setDate(date.getDate() + time);
   } else if(type == "year" || type == "years") {
      date.setYear(date.getYear() + time);
   }
   
   var strMonthArray = new Array(12);
   strMonthArray[0] = "JAN";
   strMonthArray[1] = "FEB";
   strMonthArray[2] = "MAR";
   strMonthArray[3] = "APR";
   strMonthArray[4] = "MAY";
   strMonthArray[5] = "JUN";
   strMonthArray[6] = "JUL";
   strMonthArray[7] = "AUG";
   strMonthArray[8] = "SEP";
   strMonthArray[9] = "OCT";
   strMonthArray[10] = "NOV";
   strMonthArray[11] = "DEC";
   
   return "" + date.getDate() + "-" + strMonthArray[date.getMonth()] + "-" + date.getFullYear();
}




function after(date1, date2, same, days) {
   // If date1 is AFTER date2 this returns true,
   // if same is set to true, it will return true if the dates are AFTER,
   // or if they are equivalent.
   // if either date is left blank, it will return null

   if (same == null) {
      same = false;
   }

   diff = compare_dates(date1, date2, days);
   //I hope I didn't obfuscate the next statement too much...

   return ((diff > 0 && !days) || (diff == 0 && same && !days) || (diff >= 1 && days));
}



function validateNumber(parmElement, parmDesc, length, decimal, negative) {
//-----------------------------------------------------------------------------
//  Edit the value to be a number containing digit(s) 0 through 9 and no more
//  than one decimal.
//
//  parmElement - array element name with index
//  parmDesc - text description of the element for the error msg display
//  decimal - indicates the number contains a decimal (true) or not (false)
//-----------------------------------------------------------------------------
   
   // ***** Get The Number To Validate and Length Of String
   var num = parmElement.value;
   var len = num.length;

   // ***** Setup Loop To Validate
   var found_decimal = false;
   var error_flag = false;
   var count = 0;

   if (negative == null)
       negative = false;

   // These next two boolean are set if the number
   var bad_decimal = false;
   var bad_neg = false;
   var bad_decimal_num = false;
   var bad_integer = false;
   
   var result = true;
   
   if(length == null) {
      length = parmElement.maxlength;
   }
   
   if(!negative && num < 0) {
      error_flag = true;
      bad_neg = true;
   }
   
   //if decimal is more than zero, is not a boolean, and there is a decimal point in the entry
   if(decimal && num.indexOf('.') != -1) {
      if(!num.match("^[-]?\\d{1," + (length-decimal) + "}(\\.\\d{1," + decimal + "})?$")) {
         error_flag = true;
         bad_decimal_num = true;
      }
   } else {
      if(decimal < 0) {decimal = 0;}
      
      if( num.indexOf('-') == 0 ){
         num = num.substring(1);
      }
      var number_reg = new RegExp(/([^\d])/);
      var results = number_reg.exec(num);
      if(results) {
         count = num.indexOf(results[1]) + 1;
         error_flag = true;
      }else if(!num.match("^[-]?\\d{1," + length + "}$")) {
         error_flag = true;
         bad_integer = true;
      }
   }
   
   // ***** Check For Error
   if ( error_flag ) {

      if (bad_decimal) {
         alert(parmDesc + " - This field does not accept decimals. \n \n -- Please enter an integer number only! --");
      } else if (bad_decimal_num) {
         alert(parmDesc + " - This field accepts decimal numbers with up to " + (length - decimal) + " numbers before the decimal\nand " + decimal + " or fewer numbers after the decimal.");
      } else if (bad_neg) {
         alert(parmDesc + " - This field does not accept negative numbers. \n \n -- Please enter a positive number only! --");
      } else if(bad_integer) {
         alert(parmDesc + " - This field may only be " + length + " numbers in length.");
      }
      else {
         alert(parmDesc + "\n - This field only accepts numbers, and not letters or other non-numeric characters. " +
               "\n\nAn illegal non-numeric character exists at position #" + count  + ". \n " + " -- Please enter only numbers into this field -- ");
      }
      result = false;
   }

   return result;
}



//---------------------------------------------------------------------------
//  A middle-tier function, this checks if a number-field is filled-out
//  and then checks if it is in the specified range
//  It calls validateNumber to do the real heavy-lifting.
//---------------------------------------------------------------------------

function valid_num(el_name, el_desc, length, decimal, low, high, mandatory, negative, deviation) {
   if(is_hidden(el_name)) return true;
   
   if (mandatory == null) {
      mandatory = true;
   }

   if (!el_desc) {
       el_desc = getQuestionDesc(el_name);
   }

   if ( getElement(el_name).value == '') {
        if (inc_save || !mandatory) {
           return true;
        }
        if( deviation == 1){
           dev_edits = check_value('DEV_EDITS') + el_desc + " was not filled out\n";
           set_value('DEV_EDITS', dev_edits);
           return true;
        }        
        getElement(el_name).style.backgroundColor = "red";
        alert(el_desc + " still needs to be filled-out");
        getElement(el_name).focus();
        return false;
   } else {
       if ( !validateNumber(getElement(el_name), el_desc, length, decimal, negative)) {
           getElement(el_name).style.backgroundColor = "red";
          getElement(el_name).focus();
           return false;
       } else {
	       if ( low != null )
	       if( getElement(el_name).value < low ){
		       getElement(el_name).style.backgroundColor = "red";
		       alert(el_desc + " must be >= to :" + low);
		       getElement(el_name).focus();
		       return false;
	       }
	       if ( high != null )
	       if ( getElement(el_name).value > high ) {
		       getElement(el_name).style.backgroundColor = "red";
		       alert(el_desc + " must be <= to :" + high);
		       getElement(el_name).focus();
             return false;
	       }
       }
   }

   return true;
}



// This function is for the onblur edit-checks. It does most of what valid_num does, exept it
// doesn't do the annoying focus() changes. I.e. it will warn the user, but not pester them.
function inline_valid_num(touched_el_name, el_name, el_desc, length, decimal, low, high, mandatory, negative) {

   // touched_el_name is the element name that has just been blurred.
   if (touched_el_name != el_name) {
      return true;
   }

   if (!el_desc) {
       el_desc = getQuestionDesc(el_name);
   }

   if (mandatory == null) {
      mandatory = false;
   }

   if ( getElement(el_name).value == '') {
        if (!mandatory) {
           return true;
        }
        getElement(el_name).style.backgroundColor = "red";
        alert(el_desc + " still needs to be filled-out");
        return false;
   } else {
       if ( !validateNumber(getElement(el_name), el_desc, length, decimal, negative)) {
           getElement(el_name).style.backgroundColor = "red";
           return false;
       } else {
           if ( low != null && high != null )
              if ( getElement(el_name).value > high || getElement(el_name).value < low) {
                   getElement(el_name).style.backgroundColor = "red";
                   alert(el_desc + " must be between :" + low + " and " + high);
                   return false;
              }
       }
   }

   return true;
}



// This function checks if the UNKNOWN checkbox has been checked, and if not,
// it will validate the Date field as normal
// This should ONLY be called for a number field with an _UNK sub-question checkbox.

function valid_num_with_unk(el_name, el_desc, length, decimal, low, high, mandatory, unk_name, negative) {
    if (unk_name == null) {
       unk_name = el_name + "_UNK";
    }
    if(is_hidden(el_name) && is_hidden(unk_name)) return true;

   if (!el_desc) {
       el_desc = getQuestionDesc(el_name);
   }

    if(check_checked(unk_name) == 0) {
        // Unknown has been checked, so we don't need to validate the number,
        // however, if the number feild has been filled-out, there's a problem,
        // We'll need to warn the user, and we should probably prevent the
        // saving of this form untill it is fixed

        if (check_value(el_name) != "") {
           alert(el_desc + " : 'Unknown' has been checked for this field, but the field has been filled-out, please verify ");
           tag(el_name);
           return false;
        }

        return true;

    } else {
        return valid_num(el_name, el_desc, length, decimal, low, high, mandatory, negative);
    }
}


function valid_num_with_nd(el_name, el_desc, length, decimal, low, high, mandatory, nd_name, negative) {
   if (nd_name == null) {
      nd_name = el_name + "_ND";
   }
   if(is_hidden(el_name) && is_hidden(nd_name)) return true;
   
   if (!el_desc) {
      el_desc = getQuestionDesc(el_name);
   }
   
   if(check_checked(nd_name) == 0) {
      // Unknown has been checked, so we don't need to validate the number,
      // however, if the number feild has been filled-out, there's a problem,
      // We'll need to warn the user, and we should probably prevent the
      // saving of this form untill it is fixed
      
      if (check_value(el_name) != "") {
         alert(el_desc + " : 'Not Done' has been checked for this field, but the field has been filled-out, please verify ");
         tag(el_name);
         return false;
      }
      
      return true;
      
   } else {
      return valid_num(el_name, el_desc, length, decimal, low, high, mandatory, negative);
   }
}






// ----------------------------------------------------------------------------
//  This checks if the radio button exists in this study, and if so, it will
//  make sure it is answered.
// ----------------------------------------------------------------------------
function valid_radio(el_name, desc, mandatory, deviation) {
   if(is_hidden(el_name)) return true;
   
   if(inc_save) return true;
   if(mandatory == null) {
      mandatory = true;
   }


   if (!desc) {
       desc = getQuestionDesc(el_name);
   }

   if ( getElement(el_name) ) {
      for ( var i = 0; getElement(el_name)[i]; i++) {
          if (getElement(el_name)[i].checked )
              return true;
      }
      if( deviation == 1){
         dev_edits = check_value('DEV_EDITS') + desc + " was not filled out\n";
         set_value('DEV_EDITS', dev_edits);
         return true;
      }

      tag(el_name);
      alert( desc + ": is a required field and must be filled-out");
      return false;

   } else {
      if (debug) {
        alert("valid_radio non-element :" + name);
      }
      return true;
   }
}


// This function takes in an arbitrary string, and through a series of pattern matches
// it can detiermine if the string looks like an email address.
// It does not actually test the address, it simply applies a few patterns to it
// and returns true/false based on whether it passed the checks or not.
function valid_email(suspect_email) {
   
   if (suspect_email.match(/.+\@.+/) ) {
       var email_parts = suspect_email.split(/\@/);

       if (email_parts[0].match( /[\(\)\<\>\@\,\;\:\\ \"\[\]]/)  || email_parts[1].match(/[\(\)\<\>\@\,\;\:\\ \"\[\]]/ ) ) {

          return false;
       } else {

          if (email_parts[1].match(/.+\..+/)) {
            return true;
          } else {
            return false;
          }

       }
   } else {
       return false;
   }
}

function valid_emails( suspect_emails ) {
   var emails = suspect_emails.split(';');
   
   for(var i = 0; i < emails.length; i++) {
      
      var str = "";
      
      if(i != 0) {
         str = emails[i].replace(/^\s*|\s*$/g,"");
      } else {
         str = emails[i].replace(/\s*$/g,"");
      }
      if(!valid_email(str)) {
         alert('Validation failed on the following email address: ' + str);
         return false;
      }
   }
   
   return true;
}

function validate_required(el_name, desc, deviation) {
   if(is_hidden(el_name)) return true;
   result = true;

   if ( getElement(el_name).value == "" && !inc_save) {
      if( deviation == 1){
         dev_edits = check_value('DEV_EDITS') + desc + ": was not filled out\n";
         set_value('DEV_EDITS', dev_edits);
         return true;
      }
      alert(desc + ":  This is a required field and must be filled out\n");
      tag(el_name);
      result = false;
   }

   return result;
}



function valid_comment(el_name, mandatory, max_length, desc) {
   if(is_hidden(el_name)) return true;
   
   if (mandatory == null) {
       mandatory = true
   }

   if (max_length == null) {
      max_length = 4000;
   }


   if (!desc) {
       desc = getQuestionDesc(el_name);
   }

   if ( getElement(el_name).value == "" && !inc_save && mandatory) {
      alert(desc + ":  This is a required field and must be filled out\n");
      tag(el_name);
      return false;
   }

	var field_length = getElement(el_name).value.length;
   if ( field_length > max_length) {
      alert(desc + ":  The text you have entered is too long for this field (" + field_length + " chars)\n\n" +
            " This field can hold a maximum of " + max_length + " characters, please reduce the size of your text");
      tag(el_name);
      return false;

   }
   return true;

}




//-------------------------------------------------------------------------------------------------
// This is a fairly standard 'mandatory' edit check. It will test the type of the element,
// and call the appropriate edit-check function. It does not return the value of anything, nor
// the selectedIndex or anything like that. Simply true/false
// It also saves on typing.
//-------------------------------------------------------------------------------------------------
function valid(name, desc, deviation) {
   if(is_hidden(name)) {return true;}
   var type = check_type(name);

   if (type == 'text' || type  == 'textarea' || type == 'hidden' || type == 'password') {
     // I'm not quite sure if anyone will want to call valid() on a
     // hidden field, but it's there just in case.
     return validate_required(name, desc, deviation);
   } else  if (type == 'radio') {
     return valid_radio(name, desc, deviation);
   } else if (type == 'select-one') {
     return valid_select(name, desc, deviation);
   } else if (type == 'checkbox') {
     // There probably shouldn't be too many instances of checkbox here,
     // But if there were a case where one particular checkbox MUST be checked,
     // this will tell you if it has been.
     return valid_checkbox(name, desc, deviation);
   }
}


// This does the standard check-for-unknown checked checks that every other _with_unk
// function does.
function valid_with_unk(name, desc, unk_name) {
   if (unk_name == null) {
       unk_name = name + "_UNK";
    }

    if(is_hidden(name) && is_hidden(unk_name)) return true;
    
    if(check_checked(unk_name) == 0) {
        // Unknown has been checked, so we don't need to validate the number,
        // however, if the number feild has been filled-out, there's a problem,
        // We'll need to warn the user, and we should probably prevent the
        // saving of this form untill it is fixed

        if (check_value(name) != "") {
           alert(desc + " : 'Unknown' has been checked for this field, but the field has been filled-out, please verify ");
           tag(name);
           return false;
        }

        return true;

    } else {
        return valid(name, desc);
    }

}

//-------------------------------------------------------------------------------------------------
//  This is a fairly standard element and sub_element edit-check,
//  it's to edit-checks as hide_on_no() is to visiblity-checks.
//
//  If "select" is checked/selected, we call valid() on sub_name.
//  It will also call valid() on name, if desc is not null.
//  Note: select will default to 0 (i.e. "Yes" for most radio buttons)
//  explicitly passed-in.
//  Also, if sub_names, and sub_descs (note the 's') are valid arrays,
//  valid_on will call valid on each element in the arrays.
//  This allows the programer to validate an entire group of sub-questions
//  in one function call. Damn me, I'm smart.
//
//-------------------------------------------------------------------------------------------------
function valid_on(name, desc, sub_name, sub_desc, select, sub_names, sub_descs, form) {
   if (select == null)
      select = 0;

   if (desc != null) {
      if (!valid(name, desc)) return false;
   }

   if (check_checked(name) == select && getElement(sub_name)) {
      if (getElement(sub_name)) {
        if (!valid(sub_name, sub_desc)) return false;
      }

      if (sub_names) {
        for( var i=0; i<sub_names.length; i++) {
             if (!valid(form + sub_names[i], sub_descs[i])) return false;
        }
      }
   }
   return true;
}



function valid_on_short(name, sub_name, select, sub_names) {
   if (select == null)
      select = 0;

   if (!valid(name)) return false;

   // Grab the question text.
   var desc = getQuestionDesc(name);
   
   if (check_checked(name) == select) {

      if (sub_name) {
         // Grab the sub-question text, and tack-on the parent-question text.
         var sub_desc = desc + ": " + getQuestionDesc(sub_name).value;
         if (!valid(sub_name, sub_desc)) return false;
      }

      if (sub_names) {
         // Check all the feilds in sub_names
         var i = 0;
         while (sub_names[i]) {
            if (!valid(sub_names[i])) return false;
            i++;
         }
      }
   }
   return true;
}


//-----------------------------------------------------------------------------
//  Check what was selected,
//  Display an error msg if nothing was selected
//-----------------------------------------------------------------------------
function valid_select(el_name, parmDesc, deviation) {
   if(is_hidden(el_name)) return true;
   var result = check_selected(el_name);

   if ( (result == -1 || result == 0) && !inc_save) {
      if (!parmDesc) {
          parmDesc = getQuestionDesc(el_name);
      }
      if( deviation == 1){
         dev_edits = check_value('DEV_EDITS') + parmDesc + ": does not have one of the options selected\n";
         set_value('DEV_EDITS', dev_edits);
         return true;
      }
      alert(parmDesc + ":  This is a required field and must have one of the options selected.\n");
      tag(el_name);
      return false;
   }
   return true;
}


function valid_checkbox(name, parmDesc, deviation) {
   if(is_hidden(name)) return true;
   if (check_checked(name) != 0 && !inc_save) {
      if (!parmDesc) {
          parmDesc = getQuestionDesc(el_name);
      }
      if( deviation == 1 ){
         dev_edits = check_value('DEV_EDITS') + parmDesc + " was not checked\n";
         set_value('DEV_EDITS', dev_edits);
         return true;
      }
      alert(parmDesc + ":  This is a required field and must have one of the options selected.\n");
      tag(name);
      return false;
   }
   return true;
}


//-----------------------------------------------------------------------------------------------------------
//   This sets the value, selectedIndex,
//   or it will check radio button at position: value
//
//   If value is passed in as "", and the element is a radio or a select,
//   set_value will uncheck all of the radio buttons, or set the
//   selectedIndex to -1, as this is the equivelent of setting them as blank.
//   (This was mainly done so it could work with hide_on_no() for clearing sub-elements)
//-------------------------------------------------------------------------------------------------

function set_value( name, value) {

     var type;

     if (!getElement(name)) {
        alert("Bad check-type : " + name);
     }

     if (getElement(name).type )
        type = getElement(name).type;
     else
        type = getElement(name)[0].type;

     if(type == "text" || type == "textarea" || type == "hidden" || type == "password") {
         getElement(name).value = value;
        // return getElement(name).value;

     } else if (type == "select-one") {
           if (value == "") {
              //This is a select, which cannot have a value of "", so set the selectedIndex to -1;
              value = -1;
           }

           getElement(name).selectedIndex = value;
           //return getElement(name).selectedIndex;
     } else if (type == "radio"){
          uncheck_all(name);

          if (value != "" && value != -1)
             if (getElement(name)[value]) {
                getElement(name)[value].checked = true;
             }

          //return check_checked(name);

     } else if (type == "checkbox") {
          if (value != "" && value != -1)
             getElement(name).checked = true;
          else
             getElement(name).checked = false;

          //return check_checked(name);

     } else {
          if (debug) {
            alert("Unknown type :" + name + " : " + type );
          }
          //return null;
     }
}


// This returns the type of the element, it is quite usefull as it can get the
// type of a radio button without causing an error
function check_type( name ) {
   if (debug && !getElement(name)) {
      alert("Bad check-type!!! " + name);
      return false;
   }


   if (getElement(name).type )
       return getElement(name).type;
   else
   {
       return getElement(name)[0].type;
   }
}

function check_value( name ) {
      var type = check_type(name);

      if ( type == "text" || type == "textarea" || type == "hidden" || type == "password")
          return getElement(name).value;
      else if ( type == "checkbox") {
         var checked = check_checked(name);
         if (checked == -1)
            return "";
         else
            return "1";
      } else if ( type == "radio") {
           var checked = check_checked(name);
           if (checked == -1)
               return "";
           else
               return getElement(name)[ checked ].value;
       } else if (type == "select-one") {
          var selected = check_selected(name);
          if (selected == -1)
               return "";
           else
               return getElement(name)[selected].value;
       } else {
          if (debug) {
            alert("Unknown type :" + name + " : " + type );
          }
          return null;
       }
}


function check_checked( name ) {
  // check_checked returns the position of the checked answer.
  // Or -1 if nothing has been answered, or null if it doesn't exist.
  // Note that this function does work on a select element,

  var type;
  if(!getElement(name)) {
     alert(name);
     type = document.fm[name].type;
  } else {
     if(getElement(name).type )
        type = getElement(name).type;
     else
        type = getElement(name)[0].type;
  }
  
  if ( type == "radio") {
     var radios = getElement(name);
     for(i = 0; i < radios.length; i++) {
        if (radios[i].checked)
          return i;
     }

     return -1;

  } else if ( type == "checkbox") {
     //Its a one-item checkbox
     if (getElement(name).checked)
        return 0;
     else
        return -1;
  } else if (type == "select-one") {
      return getElement(name).selectedIndex;
  } else {
      if (debug) {
          alert("Unknown type :" + name + " : " + type );
      }
      return null;
  }
}

function check_selected( name ) {
    return getElement(name).selectedIndex;
}

function is_one_checked(form, el_names, err_txt, el_name, selected) {

  if (selected == null) {
     selected = 0;
  }

  var is_one_checked = false;
  for (var i = 0; i < el_names.length; i++) {
     if (check_checked(form + el_names[i]) == selected) {
         is_one_checked = true;
     }
  }

  if (!is_one_checked && !inc_save) {
     alert(err_txt);
     tag( el_name );
     if(getElement( el_name )){
        getElement( el_name )[0].focus();
     }
     return false;
  }
  return true;

}

function are_all_checked(form, el_names, selected) {

  if (selected == null) {
     selected = 0;
  }

  var are_all_checked = true;
  for (var i = 0; i < el_names.length; i++) {
     if (check_checked(form + el_names[i]) != selected) {
         are_all_checked = false;
     }
  }

  return are_all_checked;

}


// Dude, I should really write a valid_group() that just calls valid()

function valid_radio_group(form, el_names, descs) {

  for (var i = 0; i < el_names.length; i++) {
     if (!valid_radio(form + el_names[i], descs[i]) && !is_hidden(form + el_names[i]))
           return false;
  }

  return true;
}


// -----------------------------------------------------------
//   Open Previous Lesion table
//
//   This currently won't work on nested tables, but it
//   should work just about everywhere else.
//
// -----------------------------------------------------------
function open_prev_lesions(el_name) {
   var form;
   var keyid = fm.keyid.value;

   if (getElement("SI_CRIT_EVENTS_FORM.EVENT_DATE")) {
     var event_date = getElement("SI_CRIT_EVENTS_FORM.EVENT_DATE").value;
     event_date = DateFormat( event_date, "Date of Adverse Event" );
     var parent_keyid = "";

     if (event_date == false) {
	alert("The Date of Adverse Event is invalid, please correct this before continuing");
	tag("SI_CRIT_EVENTS_FORM.EVENT_DATE");
        return false;
     }


   } else {
     var parent_keyid = fm.parent_keyid.value;
     var event_date = "";
   }



   var height = window.screen.height, width = window.screen.width;
   var pop_height = Math.round(height / 2 );
   var pop_width  = Math.round(width  / 2 );
   var pop_top    = Math.round(height * 1 / 4);
   var pop_left   = Math.round(width  * 1 / 4);
   var pop_size_str = "width=" +pop_width +", height=" + pop_height +", top=" + pop_top + " left=" + pop_left;
   var results = el_name.match(/(\w+)\.(\w+)/);
   form = results[1];
   el_name = results[2];

   var catalog = window.open("/study/etc/prev_lesion.asp?keyid=" + keyid + "&name=" + el_name +
                             "&form=" + form + "&parent_keyid=" + parent_keyid + "&current_date=" + event_date,
                             "prev_les", pop_size_str + " scrollbars, resizeable");
}



function uncheck_all( el_name ) {
      //This might not make sense, but setting the first button to true will unselect everything else,
      //and then unselecting the first one will make the whole thing unselected.
       getElement(el_name)[0].checked = true;
       getElement(el_name)[0].checked = false;
}

function uncheck_all_array( names, type, form ) {
  if (type == "radio") {
    var i = 0;
    while (names[i]) {
        if (!getElement(form + names[i])) {alert("BAD: " + form + names[i]); }

        getElement(form + names[i])[0].checked = true;
        getElement(form + names[i])[0].checked = false;
        i++;
    }
  } else if (type == "checkbox") {
    var i = 0;
    while (names[i]) {
        if (!getElement(form + names[i])) {alert("BAD: " + form + names[i]); }
        getElement(form + names[i]).checked = false;
        i++;
    }

  }
}

function check_is_one_checked(form, names, selected, type) {

  if (selected == null) {
     selected = 0;
  }

  if (type == null) {
     type = "radio";
  }

  if (inc_save) return true;

  var is_one_checked = false;
  var i = 0;


  if (type == "radio") {
    while (getElement(form + names[i])) {
      if (getElement(form + names[i])[selected].checked == true ) {
          is_one_checked = true;
      }
      i++;
    }
  } else if (type == "checkbox") {
    while (getElement(form + names[i])) {
      if (getElement(form + names[i]).checked == true ) {
          is_one_checked = true;
      }
      i++;
    }
  }

  return is_one_checked;
}


function check_num_checked(form, names, selected, type) {

  if (selected == null) {
     selected = 0;
  }

  var num_checked = 0;
  var i = 0;


  if (type == "radio") {
    while (getElement(form + names[i])) {
      if (getElement(form + names[i])[selected].checked == true ) {
          num_checked++;
      }
      i++;
    }
  } else if (type == "checkbox") {
    while (getElement(form + names[i])) {
      if (getElement(form + names[i]).checked == true ) {
          num_checked++;
      }
      i++;
    }
  }
  return num_checked;
}


var vis_field_state = new Object();
function hide( name ) {
   if(getElement(name) == null) {alert("no visfield found: " + name); stackTrace("hide");}
   if(getElement(name).style == null) {alert("no visfield found: " + name); stackTrace("hide");}
  getElement(name).style.visibility = "hidden";
  getElement(name).style.display = "none";
  vis_field_state[name] = false;
  
  return;
}

function unhide( name ) {
  getElement(name).style.visibility = "visible";
  getElement(name).style.display = "";
  vis_field_state[name] = true;
  return;
}

function hide_all(names) {
   if(names instanceof Array)
   {
      for(var i in names)
      {
         hide_fields(get_hide_field_and_children(names[i]));
      }
   } else {
      hide_fields(get_hide_field_and_children(names));
   }
}

function unhide_all(names) {
   if(names instanceof Array)
   {
      for(var i in names)
      {
         unhide(names[i]);
      }
   } else {
      unhide(names);
   }
}

// This function is for a fairly standard visibility check: i.e. a sub-question controled by a parent-question.
// If the second answer on the parent question is checked (usualy a "No" answer), then section will be unhidden.
// If not, the section is hidden and sub_name's value, if sub_name exists, is cleared.
// If sub_names is a valid array, it will loop through each array element and call set_value() with "" on that element.
//
// el_name is a variable for the name of the html element that has just been changed, i.e. thisElement from changeVisibility
// it is used to decide if the function should actualy hide/unhide things or just return checked.
//

function hide_on_yes(el_name, name, section, sub_name, sub_names, form) {

  var checked = check_checked( name );

  // If this isn't the element just clicked-on, we don't need to really change anything.
  // el_name == null means we should do ALL of the set-up, regardless of what was clicked-on.
  if(el_name != null && el_name != name)
     return checked;

  if( checked == 1 ) {
      unhide( section );
  } else if ( checked != null ) {
      hide( section );

      if (sub_name != null ) {
         set_value(sub_name, "");
      }

      if (sub_names != null) {
         var i= 0;
         while(sub_names[i]) {
             set_value(form + sub_names[i], "");
             i++;
         }
      }
  }

  return checked;
}



//////////////////////////////////////////////////////////////////////////////////////////////////
// It's the New and Improved  hide_on Function!!
//////////////////////////////////////////////////////////////////////////////////////////////////
// el_name: is the name of the just-clicked-on element - this is often passed-in as null, like in the case of
//          the first time the form loads.
// triggering_names: is a list of elements, that if el_name is any one of them,
//                   the hiding should be triggered.
// control_element: is the name of the element that controls the hiding-unhiding of section
//                  If this is passed-in as null, the first-element of triggering_names will be used.
// selects: is another list of options that when check_checked(control_element) equals any one of them,
//          it will trigger the hidding.
// sections: is the actual groups that will be hidden/unhidden; they are in the html as <span class="hidden" id="pcard"> </span>
//           tags
// sub_names: is a list of sub-elements that will be set_value to ""; I.e. these are the elements that are hidden,
//            and thus, they need to be made blank.
// form: is an optional param, if set, it will be added to each of the sub_names. This allows
//       us to pass-in a nice-looking list of sub-elements without the form string messing things up.
//////////////////////////////////////////////////////////////////////////////////////////////////

function hide_on(el_name, triggering_names, codes, sections) {
  var trigger = false;
  var i = 0;
  var control_element;

  // PART 1, check if we should be triggering a hide/unhide.
  // currently the hide/unhide calls are kinda slow, so if el_name isn't part of
  // triggering_names we can just return check_checked.

  if (triggering_names instanceof Array) {

     var i = 0;
     while(triggering_names[i]) {
          if (triggering_names[i] == el_name)
             trigger = true;
          i++;
     }

     control_element = triggering_names[0];
  } else {

     if (triggering_names == el_name)
         trigger = true;

     control_element = triggering_names;
  }

  var value = check_value( control_element );

  // If the element just clicked-on is not part of triggering_names, we don't need to really change anything.
  // el_name == null means we should do ALL of the set-up, regardless of what was clicked-on.
  if((el_name != null && !trigger) || value == null) {
      return value;
  }

  // PART 2, figure-out if we should hide or unhide the sections
  // We just need to check if checked is in codes, i.e. the checked index
  // of the checked element is within the list of hiding elements

  var do_the_hide = false;
  if (codes instanceof Array) {
     if (value == "") {
        do_the_hide = true;
        i = 0;
        while (codes[i]) {
           if(codes[i] == "") {
              do_the_hide = false;
           }
           i++;
        }
     } else {
        i = 0;
        while (codes[i]) {
           if (codes[i] == value) {
              do_the_hide = true;
           } 
           i++;
        }
     }
  } else {
     if ( value != codes && value != "") {
       do_the_hide = false;
     } else {
        if(codes == "" && value == codes) {
           do_the_hide = false;
        } else {
           do_the_hide = true;
        }
     }
  }

  i = 0;

  // PART 3 Do the actual hiding/unhiding
  // If do_the_hide then we hide everything in sections
  // otherwise we unhide everything in sections; simple right?
  if( !do_the_hide ) {
     // As with selects, sections can be a list, or just a variable.
     if (sections instanceof Array) {
        for(i = 0; i < sections.length; i++) {
           if(!is_any_parent_hidden(sections[i])) {
              unhide( sections[i] );
           }
           i++;
        }
     } else {
        if(!is_any_parent_hidden(sections)) {
           unhide(sections);
        }
     }
  } else {
     if (sections instanceof Array) {
        for(i = 0; i < sections.length; i++) {
           hide_fields(get_hide_field_and_children(sections[i]));
        }
     } else {
        hide_fields(get_hide_field_and_children(sections));
     }
  }

  // Finally, return the checked-value,
  // This is done mostly out of convience,
  // since we already have it, might as well return something.
  return value;
}

function hide_fields(field_list) {
   for(var i = 0; i < field_list.length; i++) {
      hide( field_list[i] );
      hide_section_elements(field_list[i]);
   }
}


var sub_table_match    = RegExp(/(.*?_)(\d+)$/);
var sub_question_match = RegExp(/(.*?\.ROWID1N\.)(\d+)$/);
var inc_sub_question   = RegExp(/.*?\.ROWID1N\.$/);

function get_vis_map(key) {
   var return_object = get_vis_object(vis_map,key,sub_table_match);
   
   //we need to test to see if a visibility covered an entire
   //nested table, if so we need to modify the return to address 
   //each row
   if(return_object) {
      for(var i in return_object) {
         var results = inc_sub_question.exec(return_object[i]);
         
         if(results) {
            
            var j = 2;
            while(getElement(return_object[i] + j) != null) {
               return_object.push(return_object[i] + j);
               j++;
            }
            
            if(getElement(return_object[i] + '1') != null) {
               return_object[i] += '1';
            } else {
               //this nested table does not have 
               //elements yet... return immediatly
               return [];
            }
         }
      }
   }
   return return_object;
}

function get_vis_parent(key) {
   return get_vis_object(vis_parent,key,sub_table_match);
}

function get_vis_child(key) {
   return get_vis_object(vis_child,key,sub_table_match);
}

function get_question_visfields(key) {
   return get_vis_object(question_visfields,key,sub_question_match);
}

function get_vis_object(map,key,matcher) {
   var return_object = map[key];
   
   if(!return_object || return_object == 'undefined' || return_object == null) {
      var results = matcher.exec(key);
      
      if(results) {
         var temp_object = map[results[1]];
         return_object = new Object();
         
         for(var i in temp_object) {
            return_object[i] = temp_object[i] + results[2];
         }
      }
   }
   
   return return_object;
}

function get_hide_field_and_children(vis) {
   var child = get_vis_child(vis);
   var hide_children = new Array(vis);
   if(child == null || child == "") {
      return hide_children;
   } else {
      
      for(var i in child) {
         hide_children.push(child[i]);
      }
      
      //hide_children = hide_children.concat(child);
      return hide_children;
   } 
}

function hide_section_elements(section) {
   var hidden_elements = get_vis_map(section);
   if(!hidden_elements) {return;}  //in this case there are no elements to hide (vischeck probably hides/unhides a label)
   
   var i = 0;
   while(hidden_elements[i]) {
      set_value(hidden_elements[i], "");
      i++;
   }
}

function is_hidden( name ) {
   //if we are not on the CRF
   //then we do not have VIS_FIELDS and the element
   //has to be checked the old fashioned way
   if(!document.fm) {
      return (getElement(name).style.visibility == "hidden");
   }
   
   var visfields = get_question_visfields(name);
   
   if(visfields != null) {
      for(var i = 0; i < visfields.length; i++) {
         if(!vis_field_state[visfields[i]]) {
            return true;
         }
      }
   }
   
   return false;
}

function is_any_parent_hidden(vis,nonroot) {
   var parents = vis_parent[vis];
   
   if(parents != null) {
      var hidden = false;
      for(var parent in parents) {
         hidden = hidden && is_any_parent_hidden(parents[parent],true);
      }
      return hidden;
   } else {
      if(nonroot) {
         return vis_field_state[vis];
      } else {
         return false;
      }
   }
}


function auto_fill_bmi(height, height_units, weight, weight_units, form) {
    // This function assumes Meters and Kg, unless otherwise listed in the _units params

   // Convert height and weight to meters and kg:

   if(height_units == 2159283) {
   	// Height in Inches
   	height = height * 2.54 / 100
   } else if(height_units == 2159282) {
     	// Height in cm
     	height = height / 100;
   }

   if(weight_units == 2159285) {
     	// Weight in Pounds
     	weight = weight * 0.45359237;
   }


   if(height != '' && weight != '' && height != null && weight != null && height_units != -1 && weight_units != -1 ) {
      var bmi = weight / (height * height) * 10;
      bmi = Math.round(bmi);
      bmi = bmi / 10;
      set_value(form + "BMI", bmi );
      
      if (bmi > 30)
         getElement(form + "OBESITY").value = "Yes";
      else
         getElement(form + "OBESITY").value = "No";
   }else{
      set_value(form + "BMI", "");
   }

   return;
}



function mark_white(thisElement) {
  getElement(thisElement.name).style.background = "white";
  return true;
}


function mark_radio_white(thisElement) {
     for (var i = 0; getElement(thisElement.name)[i] != null; i++) {
         getElement(thisElement.name)[i].style.backgroundColor = "transparent";
     }
}

function mark_all_white(thisElement, group, form) {
   form += ".";
   
   // is_in_array
   var in_array = false;
   for (var i = 0; i < group.length; i++) {
      if(thisElement.name == form + group[i]) {
         in_array = true;
      }
   }
   
   if(!in_array) {
      return;
   }
   else {
      for (var i = 0; i < group.length; i++) {
            getElement(form + group[i]).style.background = "white";
      }
   }
}

function multi_date_comparison( element, element_desc, elements, descriptions, before_after, same){
   if(!inc_save){
      for(var i = 0; i < elements.length; i++){
         
         if(!getElement(elements[i])) continue;
         
         if( before_after == "before"){
            if(check_value(elements[i]) && (check_value(element) != "") && !after(elements[i], element,same)){
               if(same){
                  alert(element_desc + " must be on or " + before_after + " " +descriptions[i] + " (" + check_value(elements[i]) + ")");
               }else{
                  alert(element_desc + " must be " + before_after + " " +descriptions[i] + " (" + check_value(elements[i]) + ")");
               }
               tag(element);
               return false;
            }
         }else{
            if(check_value(element) && (check_value(elements[i]) != "") && (!after(element, elements[i], same))){
               if(same){
                  alert(element_desc + " must be on or " + before_after + " " +descriptions[i] + " (" + check_value(elements[i]) + ")");
               }else{
                  alert(element_desc + " must be " + before_after + " " +descriptions[i] + " (" + check_value(elements[i]) + ")");
               }
               tag(element);
               return false;
            }
         }
      }
   }
   return true;
}

function match_re_pattern( el_name, desc, pattern, pattern_desc ) {
   var text = check_value(el_name);
   var reg_exp = new RegExp(pattern);
   
   if(!inc_save && !text.match(reg_exp)) {
      if (!desc) {
         desc = getQuestionDesc(el_name);
      }
      
      if(!pattern_desc) {
         alert(desc + " did not match the proper format");
      } else {
         alert(desc + " did not match the proper format of: " + pattern_desc);
      }
      tag(el_name);
      return false;
   }
   
   return true;
}

// compare_times returns the number of hours between time_str1 and time_str2
// This generaly assumes the time strings have been validated with valid_time already,
// if the time format is invalid, the data parser will be unhappy.
function compare_times( time_str1, time_str2) {
   // If time1 is later than time2, this will return a positive number  
   // if not, this will return a negative number, (or 0 if the times are equal)
   // time1 => Now
   // time2 => Then will return a positive.
  
   var time1 = time_str1.split(":", 2);
   var time2 = time_str2.split(":", 2);

   // make two Dates, and set the time portion of each to time_str1 and 2
   var date1 = new Date();

   var date2 = new Date();

   date1.setHours(time1[0]);
   date2.setHours(time2[0]);

   date1.setMinutes(time1[1]);
   date2.setMinutes(time2[1]);

   //alert(date1.toString() + " :: " + date2.toString() + " || " + time_str1 + " :: " + time_str2);

   // Get the difference of time, and then convert the milliseconds to hours.
   var hours = (date1.getTime() - date2.getTime()) / 3600000;
  
   if (isNaN(hours)) {
       alert("Time format not recognized! Please use HH:MM ");
       return NaN;
   }

   return hours;
}

function after_time(subject, time) {
   if(!valid_time(subject)) return false;
   if(!valid_time(time)) return false;
   
   subject = check_value(subject);
   time    = check_value(time);   

   return (compare_times(subject, time) > 0);
}

function show_logout_menu(onOff) {
   var menuNum = getMenuByName("logout_menu");
   _m[menuNum][10] = onOff;//turn keepalive onOff  
   if (onOff == 1) {
      popup("logout_menu");//show logout menu
   }
   else {
      //show the menu again and then hide it right away
      //don't agrue, just trust me!
      popup("logout_menu");//show menu
      setTimeout('menuDisplay('+menuNum+',0)', 2);//hide menu after 2 milliseconds
   }
}

//#session logout methods
session_start = new Date();
var buffered_refresh = false;
var timeout_counter, timeout_id2, timeout_id;

function prepare_logout() {
   timeout_counter = 60;
   show_logout_menu(1);
   document.getElementById('timeout_span').innerHTML = timeout_counter;//reset counter to 60
   timeout_id2 = setTimeout('logout_interval()', 1000);//start counter within the logout menu
   if(buffered_refresh) {force_refresh_session();}
   timeout_id = setTimeout('really_logout()', 60000);
}

function logout_interval() {
   timeout_counter--;
   document.getElementById('timeout_span').innerHTML = timeout_counter;
   timeout_id2 = setTimeout('logout_interval()', 1000);
}

function initalize_logout() {
  timeout_id = setTimeout('prepare_logout()',get_logout_time() * 1000 * 60);
  setInterval('check_buffered_refresh()', 1000 * 60);
}

function reset_timer() {
  clearTimeout(timeout_id);
  clearTimeout(timeout_id2);
  timeout_id = setTimeout('prepare_logout()',get_logout_time() * 1000 * 60);
  refresh_session();
}

function reset_logout() {
  clearTimeout(timeout_id);
  clearTimeout(timeout_id2);
  timeout_id = setTimeout('prepare_logout()',get_logout_time() * 1000 * 60);
  setTimeout('force_refresh_session()',200);
  show_logout_menu(0);
}

function really_logout() {location = "/register/logout.asp";}

function check_buffered_refresh() {
   if(buffered_refresh) {force_refresh_session();}
}

function refresh_session() {
   var now = new Date();
   if((now.getMinutes() - session_start.getMinutes()) <= 1) {buffered_refresh = true; return;}
   force_refresh_session()
}

function force_refresh_session() {
   var args = new Object();
   args.refresh = "refresh";
   server_request("refresh",'/index.asp',args);
   session_start = new Date();
   buffered_refresh = false;
}

function show_save_layer() {
   var overDiv = document.createElement("div");
   overDiv.innerHTML = "<table style='width: " + document.body.offsetWidth + "; height: " + window.screen.availHeight + "' border=0><tr valign='center' align='center'><td><h2><b style='color: black;'>Please wait while the information is being saved</b><br>" + createBar(400,40,'transparent',0,'black','#8363A7',60,6,'','') + "</td></tr></table>";
   overDiv.style.background = "#E2DBE9";
   overDiv.style.left     = 0;
   overDiv.style.top      = getCoordFromTop();
   overDiv.style.width    = document.body.offsetWidth + 'px';
   overDiv.style.height   = getPageHeightLeft() + 'px';
   overDiv.style.zindex   = 100;
   overDiv.style.position = 'absolute';
   overDiv.style.display  = 'block';
   overDiv.style.overflow = 'hidden';
   overDiv.style.opacity  = 0.75;
   overDiv.style.filter   = 'alpha(opacity=75)';
   overDiv.id = 'overDiv';
   document.body.appendChild(overDiv);
   
   //turn off the milonic menus so they cannot click on them
   //var menuNum1 = getMenuByName('Horizontal Main Menu');
   //if(menuNum1){
   //   _m[menuNum1][7] = false;
   //}
   //var menuNum2 = getMenuByName('Vertical Main Menu');
   //if(menuNum2){
   //   _m[menuNum2][7] = false;
   //}
   
   //setTimeout('menuDisplay('+menuNum1+',0)', 2);
   //setTimeout('menuDisplay('+menuNum2+',0)', 2);
   
   window.onscroll = function() {
      overDiv.style.top    = getCoordFromTop() + 'px';
      overDiv.style.height = getPageHeightLeft() + 'px';
   }
   
   if(navigator.appName == "Netscape") {
      window.addEventListener('DOMMouseScroll', function(){setTimeout('mozillaScrollFix()',50)}, false);
      window.onkeyup = function() {overDiv.style.top = getCoordFromTop() + 'px'; overDiv.style.height = getPageHeightLeft() + 'px';}
   }
   
   overDiv.style.visibility = "visible";
   
   startBarObj();
   changeChildrenSelectDisplay(getElement("fm"));
}

function mozillaScrollFix() {
   //mozilla fires the DOMMouseScroll event before it finishes the webpage scroll
   //so we need to delay the div redraw to calculate the proper offset height
   var overDiv = document.getElementById("overDiv");
   overDiv.style.top = getCoordFromTop() + 'px'; overDiv.style.height = getPageHeightLeft() + 'px';
}

function getPageHeightLeft() {
   var y;
   if (self.innerHeight) // all except Explorer
   {
      y = self.innerHeight;
   }
   else if (document.documentElement && document.documentElement.clientHeight)
      // Explorer 6 Strict Mode
   {
      y = document.documentElement.clientHeight;
   }
   else if (document.body) // other Explorers
   {
      y = document.body.clientHeight;
   }
   
   return Math.min(window.screen.availHeight,y);
}

function getCoordFromTop() {
   var y;
   if (self.pageYOffset) // all except Explorer
   {
      y = self.pageYOffset;
   }
   else if (document.documentElement && document.documentElement.scrollTop) // Explorer 6 Strict
   {
      y = document.documentElement.scrollTop;
   }
   else if (document.body) // all other Explorers
   {
      y = document.body.scrollTop;
   }
   return y;
}

var tooltip_timeout;

/*right now this is only used in study/reports/error_page_log.asp but hopefully it will be used elsewhere soon.*/
function show_tooltip(msg, height) {
   if (!msg) {return;}
   clearTimeout(tooltip_timeout);
   /*THIS IS NOW IE AND FF COMPATIBLE!
   WINDOW.EVENT IS IE, FOR FF WE JUST RESORT TO FOLLOWING SCROLL AND DON'T WORRY ABOUT EXACT POSITION*/
   var x = window.event ? event.clientX + document.body.scrollLeft : 20 + document.body.scrollLeft;
   var y = window.event ? event.clientY + document.body.scrollTop : 20 + document.body.scrollTop;
   var tt;
   if (document.getElementById('tooltip')) {
      tt = document.getElementById('tooltip');
   } else {
      tt = document.createElement("DIV");
      tt.id = 'tooltip';
      document.body.appendChild(tt);
   }
   tt.innerHTML = msg;
   tt.style.left = x;
   tt.style.top  = y;
   tt.style.overflow = "auto";
   tt.style.visibility = "visible";
   
   if(height) {
      tt.style.height = height + 'px';
   }
   
   tt.onmouseover = function() {
      clearTimeout(tooltip_timeout);
   }
   tt.onmouseout = function() {
      hide_tooltip();
   }
   
   changeChildrenSelectDisplay(document.body,'hide','collisions');
}

function hide_tooltip() {
   tooltip_timeout = setTimeout('really_hide_tooltip()',1000);
}

function really_hide_tooltip() {
   var tooltip = document.getElementById('tooltip');
   if(tooltip != null) {
      document.getElementById('tooltip').style.visibility = "hidden";
      changeChildrenSelectDisplay(document.body,"unhide");
      document.getElementById('tooltip').innderHTML = '';
   }
}

function print_r(obj) {
   for (var prop in obj) {
      if (obj[prop]) {
         write_debug(prop + " => " + obj[prop]);
      }
   }
   write_debug("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}

