/* rsn_misc.js
 * a place for miscellaneous functions, variables, constants and data 
 * structures that have no better home
 *
 * Dependencies
 * this module requires rsn_global.js
 *
 * Version 1.8 - modified openWindow(): added a 4th param so window options 
 *               are customizable by the caller
 * Version 1.7 - form submission prevented in hideNextBeforeOnload(), 
 *               hideNext(), and explicitly enabled in showNext()
 * Version 1.6 - added hideNextBeforeOnload() and autoNextBeforeOnload()
 * Version 1.5 - showInlineErrorMessage() now uses scrollTo()
 * Version 1.4 - added autoNext()
 * Version 1.3 - added openWindow()
 * Version 1.2 - added trimOpens() and trim()
 * Version 1.1 - added showInlineErrorMessage(), insertHiddenInput(), 
 *               getWindowSize(), maximizeWindow(). These latter 2 for Baby 
 *               Milk survey.
 * Version 1.0 - original version
 *
 * Copyright (2006) Research Now Plc.
 */


/*** functions for hiding and showing HTML elements ***/

/* hides HTML element with id == "forwardbutton" as soon as it loads and 
 * prevents form submission. It's safe to call this function before it or 
 * the DOM has loaded because it keeps polling for its availability.
 */
function hideNextBeforeOnload() {
  var elem = document.getElementById("forwardbutton");
  if (elem == null)
    
    // poll for forwardbutton's presence every 50 milliseconds
    window.setTimeout("hideNextBeforeOnload()", 50);
  else {
    elem.style.visibility = "hidden";
    doOnSubmit( "hideNext", function() { return false; } );
  }
}

/* hides HTML element with id == "forwardbutton" and mechanically prevents 
 * form submission
 */
function hideNext() {
  var elem = document.getElementById("forwardbutton");
  if (elem != null) {
    elem.style.visibility = "hidden";
    doOnSubmit( "hideNext", function() { return false; } );
  }
}

/* ensures HTML element with id == "forwardbutton" is visible and that form 
 * submission will succeed
 */
function showNext() {
  var elem = document.getElementById("forwardbutton");
  if (elem != null) {
    elem.style.visibility = "visible";
    revokeOnSubmit("hideNext");
  }
}

/* hides HTML element with id == "forwardbutton" for a duration of numSecs 
 * seconds
 */
function hideThenShowNext(numSecs) {
  hideNext();
  window.setTimeout( "showNext()", numSecs * 1000 );
}

/* automatically submits the Confirmit ctlform after numSecs has elapsed
 */
function autoNext(numSecs) {
  window.setTimeout( "document.ctlform.submit()", numSecs * 1000 );
}

/* submits the Confirmit ctlform ASAP. It's safe to call this function before 
 * the ctlform or DOM has fully loaded because their presence is continually 
 * polled for.
 */
function autoNextBeforeOnload() {
  try {
    document.ctlform.submit()
  }
  catch (e) { window.setTimeout("autoNextBeforeOnload()", 50); }
}

/* hides arbitrary HTML elements given the value of their id attr
 *
 * idList - a space and/or comma separated string of ids of elements to hide 
 *         (e.g. "q1_2, q5, q22_3")
 */
function hideElementsById(idList) {
  var elems = idList.split( /, */ );
  for (var i = 0; i < elems.length; i++) {
    var elem = document.getElementById( elems[i] );
    if (elem != null)
      elem.style.display = "none";
  }
}


/*** functions for client detection (e.g. JavaScript, Java, Flash) ***/

/* allows Confirmit or some server side app to detect if the client has 
 * JavaScript capability: we use JavaScript to generate and send a name=value 
 * form pair via GET or POST. If this pair doesn't reach the server side, we 
 * assume the client lacked JavaScript.
 */
function detectJavaScript() {
  insertHiddenInput("hasJavaScript", "yes");
}

/* writes the client's color depth, screen size and window size to a bunch of 
 * hidden form elements, allowing a server side app to pick them up
 */
function detectDisplayDetails() {
  insertHiddenInput( "colorDepth", screen.colorDepth );
  insertHiddenInput( "screenSize", screen.width + "x" + screen.height );
  insertHiddenInput( "windowSize", getWindowSize() );
}

/* returns the dimensions of the usable space of the browser, the space a web 
 * site can occupy (i.e. the whole window minus the browser toolbar and 
 * status bar etc.)
 *
 * Returns a string of the form "WxH" (e.g. "1003x491")
 */
function getWindowSize() {

  // Gecko browsers
  if (self.innerWidth)
    return self.innerWidth + "x" + self.innerHeight;

  // IE6 with a DOCTYPE
  else if (document.documentElement && document.documentElement.clientWidth)
    return document.documentElement.clientWidth + "x" 
  		+ document.documentElement.clientHeight;

  // IE5 or IE6 without a DOCTYPE
  else if (document.body)
    return document.body.clientWidth + "x" + document.body.clientHeight;
}


/*** truly miscellaneous functions ***/

/* emulates a Confirmit error message (orange text, top of page) without 
 * refreshing the page
 *
 * msg - the text of the error message to show
 */
function showInlineErrorMessage(msg) {
  var bodyDiv             = document.getElementById("body");
  var errDiv              = document.createElement("div");
  errDiv.className        = "errorMessage";
  errDiv.style.marginTop  = "8px";
  errDiv.style.color      = "#ff6600";
  errDiv.style.fontWeight = "bold";
  errDiv.appendChild( document.createTextNode(msg) );
  
  // erase previous error message if there was one
  if (bodyDiv.firstChild.className == "errorMessage")
    //bodyDiv.replaceChild(errDiv, bodyDiv.firstChild);
    bodyDiv.firstChild.style.display = "none";
  
  bodyDiv.insertBefore(errDiv, bodyDiv.firstChild);
  
  /* jump to error message so it's visible on user's screen. We could also 
   * use errDiv.scrollIntoView() so the window will scroll up just enough to 
   * reveal errDiv
   */
  //location.href = "#top";
  self.scrollTo(0, 0);
}

/* inserts a hidden input element (<input type="hidden">) at the beginning of 
 * Confirmit's form (document.ctlform)
 *
 * name  - name and id of the input element (value for the name and id 
 *         attributes
 * value - value of the input element (value for the value attr)
 *
 * returns a reference to the newly created input element after it's been 
 * attached to the DOM
 */
function insertHiddenInput(name, value) {
  var form     = document.ctlform;
  var newInput = document.createElement("input");
  newInput.setAttribute("type", "hidden");
  newInput.setAttribute("name", name);
  newInput.setAttribute("id", name);		// or newInput.id = name
  if (value != null)
    newInput.setAttribute("value", value);
  return form.insertBefore(newInput, form.firstChild);	// returns newInput
}

/* maximizes the browser window 
 */
function maximizeWindow() {
  top.window.moveTo(0, 0);
  if (isIE)
    top.window.resizeTo(screen.availWidth, screen.availHeight);
  else {
    top.window.outerHeight = top.screen.availHeight;
    top.window.outerWidth  = top.screen.availWidth;  
  }
}

/* opens url in a new popup window, named "popup", with dimensions w x h. 
 * Returns a reference to the new window.
 *
 * url     - URL of a resource to load in the new popup window
 * w       - width in pixels to make the new popup
 * h       - height in pixels to make the new popup
 * options - a string of options specifying characteristics for the new 
 *           popup. E.g. pass "menubar=no,scrollbars=no,status=yes". See 
 *           JavaScript documentation for the 3rd param of window.open()
 */
function openWindow(url, w, h, options) {

  // if optionsStr isn't empty, prefix it with a comma
  if (options != null && options.length > 0)
    options = "," + options;
  else
    options = "";
  
  return window.open(url, "popup", "width=" + w + ",height=" + h + options);
}


/*** functions for trimming whitespace ***/

/* discovers every open-end element in Confirmit's ctlform (i.e. input 
 * elements with type == "text" and textarea elements), and trims leading and 
 * trailing whitespace from the values in each. See trim().
 *
 * Returns void.
 */
function trimOpens() {
  var formControls = document.ctlform.elements;
  for (var i = 0; i < formControls.length; i++) {
    var formControl = formControls[i];

    // faster than /^text/.test(formControl.type) and case sensitive :-/
    if (formControl.type.indexOf("text") == 0)
      formControl.value = trim(formControl.value);
  }
}

/* trims leading and trailing whitespace from str and returns it. E.g. given 
 * "  chewing gum   weekend ", returns "chewing gum   weekend". Interior 
 * spacing is obviously preserved.
 *
 * str - a string to be trimmed
 *
 * returns a copy of str with whitespace trimmed
 *
 * Refactoring note - regular expressions are created on each invocation: 
 * slightly inefficient, performance wise. They should persist, entailing a 
 * more global lexical scope, but that kinda breaks the function's 
 * encapsulation.
 */
function trim(str) {
  var re1 = /^\s+/;	// leading whitespace
  var re2 = /\s+$/;	// trailing whitespace
  return str.replace(re1, "").replace(re2, "");
}
