/**
 * Support function for client side processing.
 *
 * @author     Herman Kuiper
 * @copyright  Frontier Information Technologies
 * @version    v1
 *
 * @package    fritz
 **/

/**
 * Variables to hold the current window size and body size
 * (ie viewport versus document size)
 */
var wWidth, wHeight, bWidth, bHeight;

/**
 * Get computed style for an element
 * @param oElm
 * @param strCssRule
 */
function getStyle(oElm, strCssRule)
{
   var strValue = "";
   if(document.defaultView && document.defaultView.getComputedStyle)
      strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
   else if(oElm.currentStyle)
   {
      strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1) {
         return p1.toUpperCase();
      });
      strValue = oElm.currentStyle[strCssRule];
   }
   return strValue;
}

/**
 * Determine the correct window size and the content size.
 * Store these values in some global variables.
 */
function getSizes()
{
   if(self.innerHeight) // all except Explorer
   {
      wWidth = self.innerWidth;
      wHeight= self.innerHeight;
   }
   else if(document.documentElement && document.documentElement.clientHeight) // Explorer 6 Strict Mode
   {
      wWidth = document.documentElement.clientWidth;
      wHeight= document.documentElement.clientHeight;
   }
   else if(document.body) // other Explorers
   {
      wWidth = document.body.clientWidth;
      wHeight= document.body.clientHeight;
   }

   var test1 = document.body.scrollHeight;
   var test2 = document.body.offsetHeight;
   if(test1 > test2) // All but Explorer Mac
   {
      bWidth = document.body.scrollWidth;
      bHeight= document.body.scrollHeight;
   }
   else // Explorer Mac; would also work in Explorer 6 Strict, Mozilla and Safari
   {
      bWidth = document.body.offsetWidth;
      bHeight= document.body.offsetHeight;
   }
}

/**
 * Resize a given iframe element to its optimal size.
 * This done by getting the scoll size and adding a bit
 * for possible scrollbars.
 *
 * @param object iframeWindow The window property of the iframe to resize
 * @param int reqWidth If we are a top window, resize the window itself to the given size
 * @param int reqHeight If we are a top window, resize the window itself to the given size
 */
function resize(iframeWindow, reqWidth, reqHeight)
{
   if(top == iframeWindow)
      resizeMain(reqWidth, reqHeight);
   else if(iframeWindow.document.height)
   {
      var iframeElement = document.getElementById(iframeWindow.name);
      iframeElement.style.height = (iframeWindow.document.height + 27) + 'px';
      iframeElement.style.width = (iframeWindow.document.width + 20) + 'px';
   }
   else if(document.all)
   {
      var width, height;

      if(iframeWindow.document.compatMode && iframeWindow.document.compatMode != 'BackCompat')
      {
         width = iframeWindow.document.documentElement.scrollWidth + 12 + 'px';
         height = iframeWindow.document.documentElement.scrollHeight + 12 + 'px';
      }
      else
      {
         width = iframeWindow.document.body.scrollWidth + 12 + 'px';
         height = iframeWindow.document.body.scrollHeight + 12 + 'px';
      }

      var iframeElement = document.all[iframeWindow.name];
      iframeElement.style.height = height;
      if(iframeElement.style.width.indexOf("%") == -1)
         iframeElement.style.width = width;
   }
}


/**
 * Resize a given iframe element containing an SVG to its optimal size.
 *
 * @param object iframeWindow The window property of the iframe to resize
 * @param object svg          The svg itself
 */
function svgResize(iframeWindow, svg)
{
  var width = svg.documentElement.getAttribute("width");
  var height = svg.documentElement.getAttribute("height");
  var iframeElement = document.all[iframeWindow.name];
  iframeElement.style.height = height;
  if(iframeElement.style.width.indexOf("%") == -1)
     iframeElement.style.width = width;
}

/**
 * Flag to indicate we are resizing the window ourselves, so do not store updated size
 */
var inJSResize;

/**
 * Resize a browser window top its optimal size, with a given
 * maximum. For browsers that support it, use sizeToContent,
 * else do a guestimate.
 */
function resizeMain(reqWidth, reqHeight)
{
   inJSResize = true;

   if(window.sizeToContent)
      window.sizeToContent();
   else
   {
      if(reqWidth > 0 && reqHeight > 0)
         window.resizeTo(reqWidth, reqHeight);
      else
      {
         getSizes();

         // At least *try* to get some margins accounted for. This assumes main
         // styling is on top element in template, not on body or form
         var m = 0;
         m += parseInt(getStyle(document.forms[0].childNodes[0], "margin-left"));
         m += parseInt(getStyle(document.forms[0].childNodes[0], "margin-right"));
         bWidth += m;

         reqWidth = Math.min(800, bWidth + 16);
         reqHeight = Math.min(600, bHeight + 16);
         window.resizeTo(reqWidth, reqHeight);
      }

      // Now check to see how much window space is occupied by scrollbars etc,
      // and accomodate for those

      // Create the checkpoint element
      var cp = document.createElement("div");
      cp.style.position = "absolute";
      cp.style.width = "0px";
      cp.style.height = "0px";
      cp.style.right = "0px";
      cp.style.bottom = "0px";

      // We can only read it's position after we insert it into the document
      document.body.appendChild(cp);

      // Here we get the actual client size
      var current_width = cp.offsetLeft;
      var current_height = cp.offsetTop;
      // Here we find out how much more we need in order to get to the
      // needed w x h size (or in other words, we compute the size of
      // window decorations: border, scroll bars, title)
      var dw = reqWidth - current_width;
      var dh = reqHeight - current_height;
      // And _finally_ we get what we need
      window.resizeBy(dw + document.body.scrollLeft, dh + document.body.scrollTop);

      // we can safely delete the checkpoint now
      document.body.removeChild(cp);
   }

   inJSResize = false;
}

/**
 * Store the current size of the window in two form variables, so that
 * the template engine can store those sizes later in a cookie.
 */
function storeResize()
{
   if(!inJSResize && checkSeparateWindow())
   {
      document.getElementById("wWidth").value = document.body.offsetWidth;
      document.getElementById("wHeight").value = document.body.offsetHeight;
   }
}

/**
 * Determine the left position of an object
 * @see http://www.oreillynet.com/pub/a/javascript/excerpt/JSDHTMLCkbk_chap13/index6.html
 */
function getElementPosition(node)
{
    var offsetTrail = node;
    var offsetLeft = 0;
    var offsetTop = 0;
    while (offsetTrail) {
        offsetLeft += offsetTrail.offsetLeft;
        offsetTop += offsetTrail.offsetTop;
        offsetTrail = offsetTrail.offsetParent;
    }
    if (navigator.userAgent.indexOf("Mac") != -1 &&
        typeof document.body.leftMargin != "undefined") {
        offsetLeft += document.body.leftMargin;
        offsetTop += document.body.topMargin;
    }
    return {left:offsetLeft, top:offsetTop};
}

/**
 * Let the user goto another child object in a master-detail
 * relationship (represented by a tabsheet).
 *
 * @param string id   Name of object for which this is a jump.
 * @param int    next ID of object to jump to, or -1 if a new object needs to be created
 */
function jumpObject(id, next)
{
   var i = document.getElementById("next_" + id);
   i.value = next;
   // Make sure the page reloads with the tabsheet in view
   document.forms['epaForm'].action += "#m_" + id;
   uploadForm();
}


/**
 * Global flag to indicate a form validation process is going on.
 */
var uploadFormValidate = false;
/**
 * Number of invalid form fields.
 */
var uploadFormInvalidCount = 0;

/**
 * Validate the current form.
 *
 * This done by calling any onchange handlers defined for each form element.
 * When there are multiple invalid fields, an alert is presented to
 * the user, else the onchange handler of the field is asked to display
 * an error.
 */
function validateForm()
{
   isControlledExit = true;

   if(!document.getElementsByTagName || uploadFormValidate)
      return true;

   uploadFormValidate = true;
   uploadFormInvalidCount = 0;
   var firstInvalid = null;

   var inputs = document.getElementsByTagName("INPUT");
   for(var i = 0; i < inputs.length; i++)
      if(inputs[i].onchange)
      {
         inputs[i].onchange();
         if(uploadFormInvalidCount > 0 && firstInvalid == null)
            firstInvalid = inputs[i];
      }

   if(uploadFormInvalidCount > 1)
   {
      alert("There are invalid values");
      firstInvalid.focus();
   }
   else if(uploadFormInvalidCount == 1)
   {
      uploadFormValidate = false;
      firstInvalid.onchange();
   }
   return (uploadFormInvalidCount == 0);
}

/**
 * Upload the current form to the server, first checking
 * if all values are valid. This variant does not close
 * the window if we are running in a separate window.
 *
 * @param $refer Optional argument, if set, it is passed as
 *    $_REQUEST[refer] and used as URL to go to
 * @return TRUE if form was valid.
 * @see uploadForm
 */
function uploadFormNoClose()
{
   var valid = validateForm();
   if(valid)
   {
      if(uploadFormNoClose.arguments.length > 0)
         document.getElementById("refer").value = uploadFormNoClose.arguments[0];
      document.forms['epaForm'].submit();
   }

   return (valid && uploadFormNoClose.arguments.length == 0);
}

/**
 * Upload the current form to the server, first checking
 * if all values are valid. If the current template is running
 * in a separate window, the window will be closed if the
 * upload has finished.
 *
 * @param $refer Optional argument, if set, it is passed as
 *    $_REQUEST[refer] and used as URL to go to
 * @return TRUE if form was valid.
 * @see uploadFormNoClose
 */
function uploadForm()
{
   if(typeof checkSeparateWindow != 'undefined' && checkSeparateWindow())
      document.forms['epaForm'].refer.value = 0;

   if(uploadForm.arguments.length > 0)
      return uploadFormNoClose(uploadForm.arguments[0]);
   else
      return uploadFormNoClose();
}

/**
 * As the form which handles an "elsewhere" redirected form
 * might not return an HTML page, reset URL so current page
 * keeps working.
 **/
var oldUrl;
function setOriginalURL()
{
   document.getElementById("url").value = oldUrl;
}

/**
 * Upload the current form, but also set the URL of the
 * page which should process the posted contents.
 *
 * @param string where URL of page which should receive the posted data
 */
function uploadElsewhere(where)
{
   oldUrl = document.getElementById("url").value;

   document.getElementById("url").value = where;
   var ret = uploadForm();

   setTimeout("setOriginalURL()", 500); // half a second later
   return ret;
}

/**
 * Re-load the form and add an additional input field for the given
 * attribute.
 *
 * @param string obj    Name of object for which an attribute input field should be added
 * @param string attr   Name of attribute to add input field for
 */
function addMultiple(obj,attr)
{
   document.getElementById("mO").value = obj;
   document.getElementById("mA").value = attr;
   document.forms['epaForm'].submit();
}

/**
 * Our parent form. When using a search for to add values to
 * another form, this field indicates which form to add the selected
 * values to.
 */
var parentForm;

/**
 * Load a form in a new window.
 *
 * @param string name   Name of target (frame/window) to load form in
 * @param string url    The &lt;a&gt; element which contains the URL to load into the frame, or
 *                      a string which contains the URL
 * @param string decoration Optional string for window decoration
 */
function loadAsSeparate(name, url)
{
   var l = url.href ? url.href : url;

   if(document.getElementById(name))
      document.getElementById(name).src = l;
   else
   {
      var d;
      if(loadAsSeparate.arguments.length > 2)
         d = loadAsSeparate.arguments[2];
      else
         d = (name[0] != '_' ? 'width=700,height=500,status=no,menubar=no,resizable=yes,scrollbars=yes' : '');

      if (name == '_parent')            // Mozilla fix
         parent.location.href = l;
      else
      {
         try
         {
            parent.frames[name].location.href = l;
         }
         catch(e)
         {
            var win = window.open(l, name, d);
            if(win.focus)
               win.focus();

            if(typeof top.windowList == "undefined")
               top.windowList = new Array();
            top.windowList[name] = win;
         }
      }
      parentForm = url.href ? url.parentNode : null;    // The div containing all found values
   }
   return false;
}

/**
 * Insert a selected value into the search form for which this was
 * a find.
 *
 * @param object div HTML element containing input element to store selected values in
 * @param string value Value to store
 * @param string label Label to show to user for the selected value
 */
function insertObject(div, value, label)
{
   // Get all input elements
   var inputs = div.getElementsByTagName("INPUT");

   // If there is just a single input field or type text, this is a "free text" search
   // and we need only to copy the label
   if(inputs.length == 1 && inputs[0].type == "text")
      inputs[0].value = label;
   else
   {
      // Multiple checkboxes; first check the items already in the list,
      // and set a checkmark if the current value is in the list already.
      for(var i = 0; i < inputs.length; i++)
         if(inputs[i].value == value)
         {
            inputs[i].checked = true;
            return;
         }

      // Are multiple values allowed? If so, copy a checkbox and append
      // to the parent.
      var newDiv;
      if(div.getAttribute("MULTIPLE") == "yes")
      {
         if(div.childNodes[1].style.visibility == "hidden")
            newDiv = div.childNodes[1];
         else
         {
            newDiv = div.lastChild.cloneNode(true);
            div.appendChild(newDiv);
         }
      }
      else
         newDiv = div;

      // Check the input element for the current value
      var input = newDiv.getElementsByTagName("INPUT")[0];
      input.value = value;
      input.checked = true;

      // If necessary, show the container with checkboxes
      newDiv.style.visibility = 'visible';
      if(div.getAttribute("MULTIPLE") == "yes")
         div.style.height = Math.max(100, (16 * div.childNodes.length)) + "px";

      // Set label for value
      var span = newDiv.getElementsByTagName("SPAN")[0];
      span.innerHTML = label;
   }
}

/**
 * Copy one or more values from a search result to another
 * input field.
 *
 * @param string name Name of object (not used)
 * @param string mode Specific mode for operation (not used)
 * @see _deleteObjects
 * @see _exportObjects
 */
function _copyObjects(name, mode)
{
   // Copy ignores mode (and the @what attribute of <action> as well)
   if(!opener.parentForm)
   {
      alert("The window for this search form as changed.\nPlease re-open another search form.");
      window.close();
      return;
   }

   var isMultiple = true;
   var inputs = document.getElementsByTagName("INPUT");
   for(var i = 0; i < inputs.length; i++)
      if(inputs[i].name == 'id[]' && inputs[i].checked)
      {
         // If only a single selection is allowed, close window after copy
         isMultiple = (inputs[i].type != "radio");
         // See if there is a label we should copy as well
         var hasCopy = inputs[i].parentNode.nextSibling.getElementsByTagName("COPY");
         if(hasCopy.length)
         {
            var val = hasCopy[0].parentNode.innerHTML;
            var p1 = val.toUpperCase().indexOf("<COPY>");
            var p2 = val.toUpperCase().indexOf("</COPY>");
            insertObject(opener.parentForm, inputs[i].value, val.substring(p1 + 6, p2));
         }
         else
            insertObject(opener.parentForm, inputs[i].value, inputs[i].parentNode.nextSibling.innerHTML);
      }

   if(!isMultiple)
      window.close();
}

/**
 * Export selected objects to Excel
 *
 * @param string name Name of object
 * @param string mode Specific mode for operation. If set to "auto"
 *                    supress object selector in export-objects.php
 * @see _copyObjects
 * @see _deleteObjects
 */
function _exportObjects(name, mode)
{
   var prevUrl = document.getElementById("url").value;
   document.getElementById("url").value = "export-objects.php";

   document.getElementById("action1").value = name;
   if(mode == "auto")
      document.getElementById("action2").value = 1;
   document.forms['epaForm'].submit();

   document.getElementById("url").value = prevUrl;
}

/**
 * Allow a custom PHP callback on an action
 *
 * @param string name Name of object
 * @param string mode Name of PHP function which should handle the IDs
 * @see _copyObjects
 * @see _exportObjects
 */
function _customObjects(name, mode)
{
   document.getElementById("action1").value = name;
   document.getElementById("action2").value = mode;
   document.forms['epaForm'].submit();
}

/**
 * Clear all visible input fields in the form.
 */
function clearSearchForm()
{
   var inputs = document.getElementsByTagName("INPUT");
   for(var i = 0; i < inputs.length; i++)
   {
      if(inputs[i].type != "hidden")
      {
         inputs[i].value = "";
         inputs[i].checked = false;;
      }
   }
}

/**
 * Toggle all checkboxes named 'id[]'
 */
function selectToggle()
{
   var inputs = document.getElementsByTagName("INPUT");
   for(var i = 0; i < inputs.length; i++)
      if(inputs[i].name == 'id[]')
         inputs[i].checked = !inputs[i].checked;
   return false;
}

/**
 * Validate a time input field, to see if it is in
 * hh:mm or hhmm format.
 *
 * @param string val    Value to check
 */
function validTime(val)
{
   if(val.length == 0)
      return true;
   if(val.length < 4 || val.length > 5)
      return false;
   var h = parseInt(val.substring(0, 2));
   var m = parseInt(val.substring(val.length == 4 ? 2 : 3));
   return (h != "NaN" && m != "NaN" && h >= 0 && h < 24 && m >= 0 && m < 60);
}

/**
 * Netscape 7.02 seemed to ignore the return false when enter was pressed in an input
 * element. So record any enters, and have the delete button check for enter (so that
 * an enter does not trigger a delete).
 */
var enterPressed;

/**
 * Confirm if the user really wants to delete an object.
 * Also ignores any enter keys pressed on the delete button.
 *
 * @param string str    Message to display to the user.
 */
function confirmButton(str)
{
   if(enterPressed)
      return false;
   else
      return confirm(str);
}

/**
 * Let the enter key not submit the form, but advance to the
 * next input field (only when in a regular input field)
 *
 * @param object field  The field for which this function was called
 * @param object event  Event object
 */
function handleEnter(field, event)
{
   var keyCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
   if(keyCode == 13)
   {
      var i;
      // First find the input field concerned
      for(i = 0; i < field.form.elements.length; i++)
         if(field == field.form.elements[i])
            break;

      // Only focus if the next element is not a hidden one
      i = (i + 1) % field.form.elements.length;
      if(field.form.elements[i].type != "hidden")
         field.form.elements[i].focus();

      enterPressed = true;
      return false;
   }
   else
   {
      enterPressed = false;
      return true;
   }
}

/**
 * Open a small window to show a description for an
 * attribute.
 *
 * @param string content String to display.
 */
function help(content)
{
   var win = window.open('', 'fritzHelp', 'width=250,height=250,status=no,menubar=no,resizable=yes,scrollbars=yes');
   win.document.open();
   win.document.write("<html><head><title>Help</title>");
   if(document.getElementById("css"))
   {
      var link = document.getElementById("css");
      win.document.write("<link rel='stylesheet' type='text/css' href='" + link.getAttribute("href") + "' />");
      win.document.write("<link rel='stylesheet' type='text/css' href='" + link.nextSibling.getAttribute("href") + "' />");
   }
   win.document.write("</head><body class='help'>");
   win.document.write("<h1>Help</h1>");
   win.document.write(content);
   win.document.write("<div style='margin-top: 1em; text-align: right; font-size: smaller'><a href='javascript:window.close()'>close this window</a></div>");
   win.document.write("</body></html>");
   win.document.close();

   win.focus();

   return false;
}

/**
 * Number of currently selected tab (e.g. for export-objects.php)
 */
var currentTab = 0;

/**
 * Deprecated! Allows to toggle tabs build 'by hand'. See tabsheet.js
 * for tabs generated using <tabsheet> tags.
 *
 * Show a specific tab from a tabsheet (e.g. from export-objects.php).
 * Expect <td id='t1_num'>[</td><td>label</td><td>]</td> for each tab
 * and a <div id='t2_num'> with the content for a tab. This function
 * will change the class of the table cell to indicate the new current
 * tab, and will hide/display the previous/current tab content.
 *
 * @param int num Number of tab to show
 */
function oldShowTab(num)
{
   var tab = document.getElementById("t1_" + currentTab);
   tab.className = 'tab-left';
   tab.nextSibling.className = 'tab tablabel';
   tab.nextSibling.nextSibling.className = 'tab-right';
   document.getElementById("t2_" + currentTab).style.display = 'none';

   currentTab = num;
   tab = document.getElementById("t1_" + num);
   tab.className = 'tabselected-left';
   tab.nextSibling.className = 'tabselected tablabel';
   tab.nextSibling.nextSibling.className = 'tabselected-right';
   document.getElementById("t2_" + num).style.display = 'block';

   return false;
}

/**
 * Initialize variables, etc. Called on onload.
 */
function init()
{
   // If we don't have activeElement (i.e. non-IE), fake it.
   if(typeof document.activeElement != "unknown")
   {
      if((!document.activeElement || typeof document.activeElement == "undefined") &&
         (document.body && typeof document.body != "undefined"))
      {
         document.activeElement = document.body;
         var all = document.body.getElementsByTagName('*');
         for(var i = 0; i < all.length; i++)
         {
            var functionBody = 'document.activeElement = this;';
            var oldOnFocus = all[i].getAttribute('onfocus');
            if(oldOnFocus)
               functionBody += oldOnFocus;
            all[i].onfocus = new Function('event', functionBody);
         }
      }
   }

   if(document.getElementById)
   {
      if(document.getElementById("focusme"))
         document.getElementById("focusme").focus();

      if(document.getElementById("showme"))
         document.getElementById("showme").scrollIntoView();
   }

   // If a subform, signal our loading is done, so cursor can return to normal
   if(parent.setNormal)
      parent.setNormal();

   // Kick-start keep alive script
   setTimeout('keepalive()', 1000 * 60 * 20);

   // If there is a paperclip, make it dance
   var clip = document.getElementById('paperclip');
   if (clip) {
      var delay = clip.getAttribute("delay");
      if (delay > 0)
         setTimeout('togglePaperclip(0)', delay);
      else
         togglePaperclip(0);
   }
}

/**
 * If present, toggle the paperclip container.
 * The paperclip should have attributes effect and action
 * which define what to do using which function.
 */
function togglePaperclip(state)
{
   var clip = document.getElementById('paperclip');
   if(clip == undefined) return;

   var action = clip.getAttribute("action");
   var effect = clip.getAttribute("effect");
   if(window[effect])
   {
      window[effect](clip, action == "expand", state);
      clip.setAttribute("action", action == "collapse" ? "expand" : "collapse");

      if(clip.onclick == undefined)
      {
         clip.style.cursor = "hand";
         clip.onclick = function(){togglePaperclip(1);};
      }
   }
}

/**
 * This variable keeps track if the user pressed one of our buttons to leave a page, or not.
 */
var isControlledExit = false;
var fieldsHaveChanged = false;

/**
 * A event handler which can be attached to onbeforeunload when using version control,
 * to remind the user that leaving a page without using OK or Cancel will result in
 * a scratch version remaining.
 *
 * In order to use this, add the following to your content:
 *
 *    <script type='text/javascript'>
 *       window.onbeforeunload=controlledExit;
 *    </script>
 */
function controlledExit()
{
   if(!isControlledExit)
      return "You should leave this page using the buttons or links on the form,\notherwise the form will remain locked for modification.";
}

/**
 * A event handler which can be attached to onbeforeunload when using version control,
 * to remind the user that leaving a page without using OK or Cancel will result in
 * a scratch version remaining.
 *
 * In order to use this, add the following to your content:
 *
 *    <script type='text/javascript'>
 *       window.onbeforeunload=noExitOnChange;
 *    </script>
 */
function noExitOnChange()
{
   if(!isControlledExit && fieldsHaveChanged)
      return "There are still unsaved changes on this page.";
}

/**
 * Keep track of modified input fields.
 *
 * Every generated input field calls this method onchange.
 * @param object node The input element which has changed
 */
function fieldChanged(node)
{
   fieldsHaveChanged = true;
   if(node.className == "default")
      node.className = "";
   if(!(typeof onAfterFieldChanged == 'undefined'))
      onAfterFieldChanged(node);
}

/**
 * This function will keep the connection to the webserver open such that
 * the session data will not expire while the user is out for coffee.
 */
function keepalive()
{
   if(document.forms['alive'])
   {
      isControlledExit = true;
      document.forms['alive'].submit();
      isControlledExit = false;
      setTimeout('keepalive()', 1000 * 60 * 20);      // re-submit every 20 minutes
   }
}

/**
 * This function will set the input name of a hidden input variable
 * to 'username', such that when submitting the form (which will be
 * the next step), the user is effectively logged out.
 */
function logout()
{
   document.getElementById('username').name = 'username';
}

/**
 * Number of child windows still loading.
 * The template will increment this counter for each subreport. These subreports call setNormal()
 * to get the cursor back to normal.
 */
var childCount = 0;

/**
 * Set the wait cursor for a page.
 */
function setWait()
{
   if(childCount > 0)
      document.body.style.cursor = 'wait';
}

/**
 * Try to return cursor to regular state. If childCount > 0,
 * nothing happens.
 */
function setNormal()
{
   if(childCount != 0)
   {
      if(childCount < 0)
         childCount = 0;
      else
         childCount--;
      if(childCount == 0)
         document.body.style.cursor = 'default';
   }
}

/**
 * Fix IE problem by moving an IFRAME just neath the DIV
 */
function setDivShim(show, element)
{
   if(navigator.appName == "Microsoft Internet Explorer" && document.getElementById)
   {
      var iframeRef = document.getElementById('DivShim');

      if (show)
      {
         iframeRef.style.width = element.offsetWidth;
         iframeRef.style.height = element.offsetHeight;
         iframeRef.style.top = element.offsetTop;
         iframeRef.style.left = element.offsetLeft;
         iframeRef.style.zIndex = element.style.zIndex - 1;
         iframeRef.style.display = "block";
      }
      else
      {
         iframeRef.style.display = "none";
      }
   }
}

/**
 * Toggle multiple selector dropdown visibility
 * Uses extra IFRAME to hide any SELECTs which might show through
 *
 * @param object DIV being previousSibling of box to toggle
 * @see From: http://dotnetjunkies.com/WebLog/jking/archive/2003/10/30/2975.aspx
 */
var lastDropdown;

function toggleDropdown(obj)
{
   if(lastDropdown != undefined && lastDropdown != obj)
   {
      var o = lastDropdown;
      lastDropdown = undefined;
      toggleDropdown(o);
   }

   var sibling = obj.nextSibling;
   if(!sibling)
      return;

   var show = sibling.style.display == "none";
   lastDropdown = show ? obj : undefined;
   sibling.style.display = (show ? "block" : "none");

   setDivShim(show, sibling); // Fix IE problem: cover IE selectors

   if(document.getElementsByTagName)
   {
      // Collect a string of selected values
      var label = "";
      var s = 0;
      var inputs = sibling.getElementsByTagName("INPUT");
      for(var i = 0; i < inputs.length; i++)
      {
         if(inputs[i].checked)
         {
            s++;
            if(inputs[i].nextSibling != null)
            {
               if(label != "") label += ",";
               label += inputs[i].nextSibling.nodeValue;
            }
         }
      }

      if(label == "")
         label = (typeof labelNone != "undefined" && labelNone != "") ? labelNone : "(none)";
      else if(s == inputs.length)
         label = (typeof labelAll != "undefined" && labelAll != "") ? labelAll : "(all)";
      else if(label.length > 25)
         label = label.substring(0,label.substring(0,22).lastIndexOf(',')) + ",...";

      // And now update the label to reflect new values
      obj.childNodes[0].innerHTML = label;
   }
}

/**
 * Toggle checkboxes in a multi-selector dropdown.
 * @param obj Image clicked on
 */
function toggleCheckboxes(obj)
{
    var toggle = obj.src.indexOf("toggle") != -1;
    var fixed = obj.src.indexOf("checked") != -1;

    var table = obj.parentNode.previousSibling;
    var inputs = table.getElementsByTagName("INPUT");
    for(var i = 0; i < inputs.length; i++)
       inputs[i].checked = toggle ? !inputs[i].checked : fixed;
}


/**
 * Find a given parent node
 * @param node Node to find parent for
 * @param name Name of node to find
 */
function findParent(node, name)
{
   while(node && node.parentNode)
      if(node.nodeName == name)
         return node;
      else
         node = node.parentNode;
}
/**
 * When a checkbox has changed value, see if this makes a
 * multiselector have all options checked, and if so,
 * set the _all variable.
 * @param node Node for the checkbox clicked upon
 */
function checkAll(node)
{
   var p = findParent(node, "DIV");
   var inputs = p.getElementsByTagName("INPUT");
   var cnt = 0;
   for(var i = 0; i < inputs.length; i++)
      if(inputs[i].checked)
         cnt++;

   var all = p.previousSibling.getElementsByTagName("INPUT")[0];
   if(all) all.value = (cnt == inputs.length) ? "_all" : "";
}

/**
 * Helper function to have a frame reload another frame.
 * @param string Name of frame to reload
 */
function reloadFrame(name)
{
   parent.frames[name].document.location.reload();
}

/**
 * Store the current amount of scroll for a window, so we can scroll to
 * the same position if we return (table edit)
 */
function storeScroll()
{
   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;

   // Store offset in a cookie
   var date = new Date();
   date.setTime(date.getTime() + 100000);
   document.cookie = "scrollOffset=" + y + "; expires=" + date.toGMTString() + "; path=/";

}

/**
 * Restore a previous stored scroll offset
 */
function restoreScroll()
{
   var ca = document.cookie.split(';');
   for(var i = 0; i < ca.length; i++)
   {
      var c = ca[i];
      while(c.charAt(0) == ' ')
         c = c.substring(1,c.length);

      if(c.indexOf("scrollOffset=") == 0)
      {
         var y = c.substring(13, c.length);

         if(self.pageYOffset)
            self.pageYOffset = y;
         else if(document.documentElement && document.documentElement.scrollTop)
            document.documentElement.scrollTop = y;
         else if(document.body)
            document.body.scrollTop = y;

         // Invalidate cookie
         document.cookie = "scrollOffset=; expires=Wed, 24 Nov 2004 01:23:45 UTC; path=/";
         return;
      }
   }
}

/**
 * Hightlight the row the mouse is over
 */
function hiRow(row)
{
   row.oldClass = row.className;
   row.className = 'selectedrow';
}

/**
 * Reset the row when mouse leaves
 */
function lowRow(row)
{
   row.className = row.oldClass;
}

/**
 * Toggle FCK editor / file upload selector
 */
function toggleFCK(node, which)
{
   var n1 = node.parentNode.nextSibling;
   var n2 = n1.nextSibling;

   n1.style.display = which == 0 ? "block" : "none";
   n2.style.display = which == 0 ? "none" : "block";
}


