/* Copyright 2005 - 2007 Spring Layout Development Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var LAYOUT = new Object();
/**
 * Variables available to get the browser type
 */
var is_ie = ( /msie/i.test(navigator.userAgent) && !(/opera/i.test(navigator.userAgent)) );
var is_ie5 = ( is_ie && (/msie 5\.0/i.test(navigator.userAgent)) );

/**
 * Function to allow events to be added to dom objects works for both Mozilla and IE
 * @param obj the DOM object to attach the event to
 * @param type the type of event (do not include the 'on', ie 'onclick' should be passed in as 'click')
 * @param fn the function to add.
 * @param noCache indicates if the function should be cached for cleaning up on page unload
 */
function addEvent( obj, type, fn, noCache ) {
   if ( obj.attachEvent ) {
     obj['e'+type+fn] = fn;
     obj[type+fn] = function(){obj['e'+type+fn]( window.event );}.closure(obj);
     obj.attachEvent( 'on'+type, obj[type+fn] );
   } else
   {
     obj.addEventListener( type, fn, false );
   }
   /* Implementing EventCache for all event systems this will help prevent memory
    * leaks, particularly in IE 
    */
    if(noCache == null || noCache == false)
    {
      EventCache.add(obj, type, obj[type+fn], false);
    }
 }
 
 /**
 * Function to allow event Listeners to be removed from dom objects works for both Mozilla and IE
 * @param obj the DOM object to remove the eventListener from
 * @param type the type of event (do not include the 'on', ie 'onclick' should be passed in as 'click')
 * @param fn the function to remove.
 */
 function removeEvent( obj, type, fn ) 
 {
   try
   {
      if ( obj.detachEvent ) 
      {
        obj.detachEvent( 'on'+type, obj[type+fn] );
        obj[type+fn] = null;
      } 
      else
      {
        obj.removeEventListener( type, fn, false );
      }
   }
   catch(exception){}
}

/*
 * Function to add a 'method' parameter to the request and submit the form indicated by 
 * the formName given.
 * @param formName the form name to append to
 * @param action the action or method to call in the controller
 * @param unpositioned [optional] specifiy true if you do not wish for the page to reposition itself (scroll) to     
 *                                                   the location it was before submitting. By default the page will reposition
*/
function performAction(formName, action, unpositioned) 
{
   if(unpositioned == null)
   {
      registerScreenPosition(formName);
   }
   addParameter(formName, "method", action);

   if(action.match('delete')!= null ) 
   {
      var agree=confirm('Delete this record, are you sure?');
      if (agree) 
      {
         confirmOnClose = false;
         if(showLoadingMessage)
         {
               popupLoadingMessage(302, 20);
         }
         document.forms[formName].submit();
      }
   }
   else 
   {
         confirmOnClose = false;
      if(showLoadingMessage)
      {
            popupLoadingMessage(302, 20);
      }
      document.forms[formName].submit();
   }
   return false;
}


/**
 * Adds field name/value pair to the named form. If the field already exists then
 * the value is over-written.
 */
function addParameter(formName, fieldName, fieldValue)
{
   var field = document.forms[formName][fieldName];
   if(fieldName != "method" && field != null)
   {
      field.value = fieldValue;
   }
   else
   {
       var existingMethod = document.getElementsByName("method");   
      if(fieldName == "method" &&  existingMethod != null && existingMethod.length > 0)
      {
         existingMethod[0].value = fieldValue;         
      }
      else
      {
         var input = document.createElement("INPUT");
        input.type = "hidden";
        input.name = fieldName;
        input.value = fieldValue;
        document.forms[formName].appendChild(input);
      }
   }
   //alert("Added " + fieldName + " : " + fieldValue);
   return field;
}


/*
*Registers the position of the screen in the 'screenPosition' field 
* for reference after a postback.
* @param formName the name of the form to add the screen position field to
*/
function registerScreenPosition(formName) {
   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;
   }
   addParameter(formName, 'screenPosition', y);
}

/*
* Checks for the screenPosition variable and if present,
* scolls the screen to the vertical position specified
*/
function positionScreen(screenPosition) {
   window.scrollTo(0, screenPosition);
}


function getApplicationUrlPath()
{
   return appPath;
}

/*
 * Simple rollover image changer. Requires an onload event to preload the
 * images for the mouseover and mouseout events.
 */
function over(image, imageName)
{
   if(document.images)
   {
      image.src = document.imageCache[imageName + "Over"].src;
   }

   image.style.cursor = "pointer";
   image.style.cursor = "hand";
   
   return true;
}

function out(image,imageName)
{
   if(document.images)
   {
      image.src = document.imageCache[imageName + "Off"].src;
   }

   image.style.cursor = "auto";
   return true;
}

function giveFocus()
{
   form = document.forms[0];
   if(form != null)
   {
      for(var ii = 0; ii < form.elements.length; ii++)
      {
         if((form.elements[ii].type == "text" || form.elements[ii].type == "textarea") && form.elements[ii].disabled == false)
         {
            form.elements[ii].focus();
            break;
         }
      }
   }
}

/**
 * Code below taken from - http://www.evolt.org/article/document_body_doctype_switching_and_more/17/30655/
 *
 * Modified 4/22/04 to work with Opera/Moz (by webmaster at subimage dot com)
 *
 * Gets the full width/height because it's different for most browsers.
 */
function getViewportHeight() {
   if (window.innerHeight!=window.undefined) return window.innerHeight;
   if (document.compatMode=='CSS1Compat') return document.documentElement.clientHeight;
   if (document.body) return document.body.clientHeight; 
   return window.undefined; 
}
function getViewportWidth() {
   if (window.innerWidth!=window.undefined) return window.innerWidth; 
   if (document.compatMode=='CSS1Compat') return document.documentElement.clientWidth; 
   if (document.body) return document.body.clientWidth; 
   return window.undefined; 
}

function loadIconImages()
{
   if(document.images)
    {
       calIconOff = new Image();
       calIconOff.src = "../images/icon_calendar.gif";
       calIconOver = new Image();
       calIconOver.src = "../images/icon_calendar_roll.gif";
    }
   
}

/*
* Replaces the specified class with the new one.  Only replaces the specified portion of the 
* className attribute so other specified classes are unchanged.
* @param element the html element to modify
* @param fromClass the name of the class to find
* @param toClass the name of the class to replace with
*/
function swapClass(element, fromClass, toClass) 
{
         var currentClasses = element.className;
         if(currentClasses != null)
         {
            var newClasses = currentClasses.replace(fromClass, toClass);
            element.className = newClasses;
         }
}

function modalMessage(message, title, func) {
   showPopWin("noUrl", 400, 150, func, message, title);
}

/**
 * Validate the field and add error class to field and label and page top as
 * appropriate. Is called onChange of each field and called by validateDependentField.
 * @param {Object} field the field to be validated
 * @param {Object} validateDependents true or false to indicate if dependents should be validated
 * @param {Object} alerts true or false to indicate if alerts should be shown for errors
 * @param {Object} validatingAsDependent
 */
LAYOUT.validate = function(field, validateDependents, alerts, validatingAsDependent)
{
   var label = $(field.fieldLabelsForError);

   LAYOUT.applyMandatoryStatus(field, label);
   LAYOUT.applyValidationStatus(field, label, alerts);
   if(validateDependents)
   {
      LAYOUT.validateDependentFields(field);
      if(isValidateMode())
      {
         checkAllMandatories();
      }
   }
}

LAYOUT.applyMandatoryStatus = function(field, labels)
{
   if(typeof labels != 'undefined')
   {
      for(var i = 0; i < labels.length; i++)
      {
         if (labels[i] != null)
         {
            if (LAYOUT.calculateLabelMandatoryStatus($(labels[i])))
            {
               if(!Element.hasClassName(labels[i], 'mandatory'))
                  Element.addClassName(labels[i], 'mandatory');
   
            }
            else
            {
               if(Element.hasClassName(labels[i], 'mandatory'))
                  Element.removeClassName(labels[i], 'mandatory');
            }
         }
      }
   }
      
   if(field.isMandatory(field))
   {
      if(!Element.hasClassName(field, 'mandatory'))
         Element.addClassName(field, 'mandatory');
     
   }
   else
   {
      if(Element.hasClassName(field, 'mandatory'))
         Element.removeClassName(field, 'mandatory');
   }
}

LAYOUT.applyValidationStatus = function(field, labels, alerts)
{
   if(typeof labels != 'undefined')
   {
      for(var i = 0; i < labels.length; i++)
      {
         if (labels[i] != null)
         {
            if (! LAYOUT.calculateLabelValidationStatus($(labels[i])))
            {
               if(!Element.hasClassName(labels[i], 'error'))
                  Element.addClassName(labels[i], 'error');
            }
            else
            {
               if(Element.hasClassName(labels[i], 'error'))
                  Element.removeClassName(labels[i], 'error');
            }
         }
      }
   }

   if(field.isValid(field, alerts))
   {
      if(Element.hasClassName(field, 'error'))
         Element.removeClassName(field, 'error');
      removeFromInvalidFields(field);
   }
   else
   {
      if(!Element.hasClassName(field, 'error'))
         Element.addClassName(field, 'error');
      addToInvalidFields(field);
   }
}

/* Calculates the mandatory status of this label from its set of dependant fields
 * returns a boolean, returns true if any field is mandatory, false otherwise
 */
LAYOUT.calculateLabelMandatoryStatus = function(label)
{
   if (label == undefined || label.dependents == undefined)
      return false;
   for(var ii = 0; ii < label.dependents.length; ii++)
   {
      var field = $(label.dependents[ii]);
      if (field.isMandatory(field))
         return true;
   }
   return false;
   
}

/* Calculates the validation status of this label from its set of dependant fields
 * returns a boolean, false if any field is invalid, true otherwise
 */
LAYOUT.calculateLabelValidationStatus = function(label, alerts)
{
   if (label == undefined || label.dependents == undefined)
      return true;
   for(var ii = 0; ii < label.dependents.length; ii++)
   {
      var field = $(label.dependents[ii]);
      if (! field.isValid(field, alerts))
         return false;
   }
   return true;
}

LAYOUT.validateDependentFields = function(field)
{
   if (field.dependents == undefined)
      return;
   for(var ii = 0; ii < field.dependents.length; ii++)
   {
      LAYOUT.validate(field.dependents[ii], false, false, true);
   }
}

/**
 * Adds a field form the 'invalidFields' array which is checked whenever 
 * doValidation() is called.
 * @param fieldId to add to the fieldNames list.
 */
function addToInvalidFields(field)
{
   for(var ii = 0; ii < invalidFields.length; ii++)
   {
      if(invalidFields[ii] == field)
      {
         return;
      }
   }

   invalidFields[invalidFields.length] = field;
}


/**
 * Removes a field form the 'invalidFields' array which is checked whenever 
 * doValidation() is called.
 * @param fieldId of the field to remove mandatory status from.
 */
function removeFromInvalidFields(field)
{
   if (invalidFields != null)
   {
      for(var ii = 0; ii < invalidFields.length; ii++)
      {
         if(invalidFields[ii].name == field.name)
         {
            invalidFields = invalidFields.without(invalidFields[ii]);
            break;
         }
      }
   }
}

function deferCheckAllMandatories(time)
{
   if(time == null)
      time = 20;
   setTimeout(checkAllMandatories, time);
}

/**
 * Checks the size of the 'invalidFields' array to . If it is not empty it sets the page 
 * top red else it sets the page top blue.
 */
function checkAllMandatories()
{
   if(typeof globalErrorDisplayElement == 'undefined')
      return;

   if(invalidFields.length == 0)//make sure page top is not in error state
   {
      globalErrorDisplayElement.className = "";
      try
      {
         if(secondarySelectedTab != null && secondaryErrorDisplayElement != null)
         {
            secondaryErrorDisplayElement.className = "";
            Element.removeClassName(secondarySelectedTab, "error");
         }
      }
      catch(exception) 
      {
         //do nothing these variables may never have been defined
      }
      var tab = document.getElementsByClassName('tab currentError');
      if(tab.length > 0)
      {
         //alert("tab: " + tab[0].className);
         swapClass(tab[0], "currentError", "current");
      }
   }
   else // put page top in error state
   {
      globalErrorDisplayElement.className = "error";
      try
      {
         if(secondarySelectedTab != null && secondaryErrorDisplayElement != null)
         {
            secondaryErrorDisplayElement.className = "error";
            Element.addClassName(secondarySelectedTab, "error");
         }
      }
      catch(exception) 
      {
         //do nothing these variables may never have been defined
      }
      var tab = document.getElementsByClassName('tab current');
      if(tab.length > 0)
      {
         //alert("tab: " + tab[0].className);
         swapClass(tab[0], "current", "currentError");
      }
   }
}
/**
 * This function will set the field  rpovided to disabled or enabled depending on
 * the flag provided. It will also give the field and it's associated label the
 * class 'disabled'.
 * @param fieldOrId either the field or the id of the field to disable or enable
 * @param disabled status to set the field to.
 */
function setDisabled(fieldOrId, disabled)
{
   var field = $(fieldOrId);
   var label = $(field.id + '_label');
   //alert("setting disabled = " + disabled + " on " + field.id);
   field.disabled = disabled;
   if (disabled)
   {
      if(!Element.hasClassName(field, 'disabled'))
         Element.addClassName(field, 'disabled');
      if (label != null)
      {
         if(!Element.hasClassName(label, 'disabled'))
            Element.addClassName(label, 'disabled');
      }
      //If field is put of a unique select group in a datagrid it must do some extra work
      if(field.previouslySelected)
         manageDisable(field);
   }
   else
   {
      if(Element.hasClassName(field, 'disabled'))
         Element.removeClassName(field, 'disabled');
      if (label != null)
      {
         if(Element.hasClassName(label, 'disabled'))
            Element.removeClassName(label, 'disabled');
      }
   }

   //Date fields need their calendars disabled or re-enabled
   if(Element.hasClassName(field, 'dateField'))
   {
      var calendar = $('calendar_' + field.id);
      if (calendar != null)
      {
         var ctx = calendar.src.substring(0, calendar.src.lastIndexOf("/"));
         if(!disabled)
         {
            calendar.src = ctx + "/icon_calendar.gif";
            YAHOO.util.Event.addListener(calendar, 'click', showCalendarForIcon);
            YAHOO.util.Event.addListener(calendar, 'mouseover', function(){over(this, 'calIcon');});
            YAHOO.util.Event.addListener(calendar, 'mouseout', function(){out(this, 'calIcon');});
         }
         else
         {
            YAHOO.util.Event.removeListener(calendar, 'click', showCalendarForIcon);
            YAHOO.util.Event.removeListener(calendar, 'mouseover');
            YAHOO.util.Event.removeListener(calendar, 'mouseout');
            calendar.src = ctx + "/icon_calendar_roll.gif";
         }
      }
   }
   
   //Any field which has context sensitive help needs it disabled or re-enabled
   if(hasHelp(field))
   {
      var icon = $('help_' + field.id);
      var ctx = icon.src.substring(0, icon.src.lastIndexOf("/"));
      if(!disabled)
      {
         icon.src = ctx + "/icon_help.gif";
         YAHOO.util.Event.addListener(icon, 'click', showHelp);
         YAHOO.util.Event.addListener(icon, 'mouseover', function(){over(this, 'helpIcon');});
         YAHOO.util.Event.addListener(icon, 'mouseout', function(){out(this, 'helpIcon');});
      }
      else
      {
         YAHOO.util.Event.removeListener(icon, 'click', showHelp);
         YAHOO.util.Event.removeListener(icon, 'mouseover');
         YAHOO.util.Event.removeListener(icon, 'mouseout');
         icon.src = ctx + "/icon_help_roll.gif";
      }
   }
}

/*
* Disables a field label without regard for a field
* @disable true or false depending on whether to disable or enable
*/
function disableLabel(fieldLabelName, disable)
{

     var label = $(fieldLabelName);
      if (label != null)
      {
         if(disable)
        {
            if(!Element.hasClassName(label, 'disabled'))
            {
               Element.addClassName(label, 'disabled');
         }
      }
      else
      {
         if(Element.hasClassName(label, 'disabled'))
         {
               Element.removeClassName(label, 'disabled');
            }
      }
   }
}

/**
 * This function will set the field  rpovided to disabled. It will also give the 
 * field and it's associated label the class 'disabled' and clear any values 
 * in the field.
 * @param fieldId of the field to disable and clear.
 */
function disableAndClear(fieldId)
{
   clear(fieldId);
   setDisabled(fieldId,true);
}

/**
 * Clears the field provided.
 */
function clear(fieldId)
{
   var field = $(fieldId);
   
   if(field.type == "checkbox"){
      field.checked = false;
   }
   else if(field.type == "button") {
   }
   else {
      Field.clear(fieldId);
   }
}

/**
* Fires an event for an element. 
* @param name the event name to fire (do not include the "on" prefix) 
* @param target the target element to fire the event on
*/
function triggerEvent(name, target) 
{
   //Ready: create a generic event 
   if(target.fireEvent) //IE
   {
      var evtObj = document.createEventObject();
      evtObj.cancelBubble = true;
      target.fireEvent("on" + name, evtObj);
   }
   else
   {
      var evt = document.createEvent("Events")
      evt.initEvent(name, false, true); //true for can bubble, true for cancelable
      target.dispatchEvent(evt);
   }
}

/**
* Sets a field value and sets the commandDirty flag to true.
* This function should be used for setting all fields in javascript as a preference over setting
* field values directly.
* This event will fire the onchange event for the field
* @param fieldname        the id of the field to set (not the field name, although they should be the same)
* @param value            the new value
* @param suppressOnChange an optional argument specifying whether
*                         onchange event firing should be suppressed. 
*                         Think twice before you suppress the onchange
*                         event, since in almost all cases onchange firing
*                         is the correct behavior.
*/
function setFieldValue(fieldName, value, suppressOnChange)
{
   try {
      $(fieldName).value = value;
      
      if (suppressOnChange == null || suppressOnChange == false)
      {
         triggerEvent("change", $(fieldName));
      }
   }
   catch (e) {
      dump ("LayoutResources\layout.js: " + fieldName +" " + value +" " + e);
      throw(e);
   }
}

function markCommandDirty()
{
   setFieldValue('commandDirty', '1');
}

/*
* shows the loading message centered based on the window size
*/
function popupLoadingMessage(width, height)
{
   //These try to get the divs from the parent window, if they can't be found in the current window
   //This fixes a bug with an iFrame in the current window.
   var fullHeight = getViewportHeight();
   var fullWidth = getViewportWidth();
   var theBody = document.documentElement;
   var loadingMsgMask = document.getElementById("loadingMsgMask");
//   if (loadingMsgMask == null) {
//      initLoadingMessage();
//      }

   loadingMsgMask = document.getElementById("loadingMsgMask");
   var loadingMsgContainer = document.getElementById("loadingMsgContainer");
   
   loadingMsgMask.style.display = "block";
   loadingMsgContainer.style.display = "block";

   loadingMsgMask.style.width = fullWidth;
   loadingMsgMask.style.height = fullHeight;

   var scTop = parseInt(theBody.scrollTop,10);
   var scLeft = parseInt(theBody.scrollLeft,10);
   
   loadingMsgMask.style.top = scTop;
   loadingMsgMask.style.left = scLeft;
   
   var loadingMessage = document.getElementById("loadingMessage");
   if (loadingMessage == null) {
      loadingMessage = parent.document.getElementById("loadingMessage");
      }

   loadingMessage.style.top = (scTop + ((fullHeight - (height)) / 2)) + "px";
   loadingMessage.style.left =  (scLeft + ((fullWidth - (width)) / 2)) + "px";
   
   loadingMessage.style.display = "block";
   
}

/*
 * Function to add a 'targetPanel' parameter to the request and submit the form indicated by 
 * the formName given.  Then passes to the performAction method.
 * @param formName the form name to append to
 * @param targetPanel the index of the target panel to redirect to after posting
*/
function changePanel(formName, targetPanel) 
{
   addParameter(formName, "targetPanel", targetPanel);
   return performAction(formName, "changePanel", true);
}

/**
 * Limits the length of the control's value to <code>maxlength</code>.
 */
function limitLength(element, maxlength)
{
   if($(element).value.length > maxlength)
   {
      var tmp = $(element).value.substring(0, maxlength);
      setFieldValue(element, tmp);
   }
}



///////////////////////////////////////////////////////
////////// Taken from html/ElementWrapper.js //////////
///////////////////////////////////////////////////////

function prependEventHandler(obj, event, eventHandler) {
  event = "on" + event;

  var oldHandler = eval("obj." + event);
  var newHandler;
  if(!isVoid(oldHandler)) {
    // Using the normal way, handlers are executed with 'window' as
    // the owner
    // the expected behaviour is to execute the handlers using the
    // corresponding DOM element as its owner
    newHandler = function(e) {
        eventHandler.call(this, e);
        return oldHandler.call(this, e);
        };
  }
  else {
    newHandler = eventHandler;
  }
    eval("obj." + event + " = newHandler");
  /* Implementing EventCache for all event systems this will help prevent memory
    * leaks, particularly in IE 
    */
   EventCache.add(obj, event, newHandler, false);
}

/* Loads icons for calendar*/
function loadCalendarIcons() 
{
   
   document.imageCache = new Array()
   document.imageCache["calIconOff"] = new Image();
   document.imageCache["calIconOff"].src = getApplicationUrlPath() + "/resources/layout/images/icon_calendar.gif";
   document.imageCache["calIconOver"] = new Image();
   document.imageCache["calIconOver"].src = getApplicationUrlPath() + "/resources/layout/images/icon_calendar_roll.gif";
   document.imageCache["helpIconOff"] = new Image();
   document.imageCache["helpIconOff"].src = getApplicationUrlPath() + "/resources/layout/images/icon_help.gif";
   document.imageCache["helpIconOver"] = new Image();
   document.imageCache["helpIconOver"].src = getApplicationUrlPath() + "/resources/layout/images/icon_help_roll.gif";
}



/////////////////////////////////////////////
////////// Taken from util/Type.js //////////
/////////////////////////////////////////////

/**
 * note that this only checks whether a variable has been initialized
 * a variable with null value is still considered 'defined'
 */
function isDefined(value) {
  return ("undefined" != (typeof value));
}

function isVoid(value) {
  return (!isDefined(value) || value == null);
}

/**
 * @return true if the page is currently in validate mode otherwise false.
 */
function isValidateMode()
{
   try
   {
      var validateField = $('validateMode');
      if(validateField != null && validateField.value == 1)
         return true;
   }
   catch(exception)
   {
      //validate field does not exist
   }
   return false; 
}

/**
 * @return true if the page is currently in edit mode otherwise false.
 */
function isEditMode()
{
   try
   {
      var editField = $('e');
      if(editField != null && editField.value == 1)
         return true;
   }
   catch(exception)
   {
      //edit field does not exist
   }
   return false; 
}

/*
 * takes an anchor name (eg 'top') and replaces the current location with that
 * this allows 'back' to still take you back to the previous page, rather than the previous bookmark
 */
function gotoAnchor(anchor)
{
   var newLocation =window.location.href;
   if (newLocation.indexOf('#')!=-1) {
      window.location.replace(newLocation.replace('#*',"#"+anchor));
   } 
   else
   {
      window.location.replace(newLocation+"#"+anchor);
   }
}

/*
* Get a query string parameter by name.  
*/
function getQueryStringParam(paramName)
{
   var queryString = window.location.href.split("?")[1];
   if(queryString)
   {
      var queryParams = queryString.toQueryParams();
      var value = queryParams[paramName];
      if(value)
      {
         return value;
      }
   }
   
   return null;
}

function swapToEditMode(e,baseFieldId, noBlur)
{
   if(typeof baseFieldId == 'undefined')
      var baseFieldId = e;

   var control = $(baseFieldId);
   var readDiv = $(baseFieldId + '_read');
   var editDiv = $(baseFieldId + '_edit');
   var containerDiv = $(baseFieldId + '_container');
   readDiv.style.display = 'none';
   editDiv.style.display = 'block';
   containerDiv.onclick = null;
   if(typeof noBlur == 'undefined')
   {
      YAHOO.util.Event.addListener(control, 'blur', swapToReadMode, baseFieldId);
      control.focus();
   }
}

function swapToReadMode(e,baseFieldId)
{
   if(typeof baseFieldId == 'undefined')
      baseFieldId = e;
      
   var control = $(baseFieldId);
   var readDiv = $(baseFieldId + '_read');
   var editDiv = $(baseFieldId + '_edit');
   var containerDiv = $(baseFieldId + '_container');
   readDiv.style.display = 'block';
   editDiv.style.display = 'none';
   var value = $F(control);
   if(value == "")
      value="&nbsp;";
   readDiv.innerHTML = value;
   YAHOO.util.Event.removeListener(control, 'blur', swapToReadMode);
   YAHOO.util.Event.addListener(containerDiv, 'click', swapToEditMode, baseFieldId);
}

LAYOUT.masterFields = new Array();
LAYOUT.dependentFields = new Array();

/**
 * TODO: explain what this function does.
 * <p>
 * To prevent memory leak in IE due to circular references, the two variables
 * above are populated. They will be used on page unload for nulling out
 * references.
 *
 * @param masterField the field to register a dependent field to
 * @param dependentField the dependent field to register
 */
function registerFieldAsMandatoryDependent(masterField, dependentField)
{
   LAYOUT.masterFields.push(masterField);
   LAYOUT.dependentFields.push(dependentField);

   if(typeof masterField.dependents == 'undefined')
      masterField.dependents = new Array();
   masterField.dependents.push(dependentField);
   
   if(typeof dependentField.registeredAsDependents == 'undefined')
   {
      dependentField.registeredAsDependents = new Array();
   }
   else
   {
      for(var ii = 0; ii < dependentField.registeredAsDependents.length; ii++)
      {
         if(dependentField.registeredAsDependents[ii].id == masterField.id)
            return;
      }
   }
   dependentField.registeredAsDependents.push(masterField);
}

/*
 * registers this field as putting its mandatoryness and validation status on this label
 * 
 */
function registerFieldAsLabelDependent(label, dependentField)
{
   if (label == undefined)
      return;
   if(typeof label.dependents == 'undefined')
      label.dependents = new Array();
   label.dependents.push(dependentField);
}

function validateDateRangeAndFocus(targetDate, format, from, to)
{
   if(!validateDateRange(targetDate, format, from, to))
      setTimeout(function(){targetDate.focus();}, 10);
}

function showCalendarForIcon(dateControl, defaultDate)
{
      if (defaultDate == undefined)
      {
         defaultDate = '';
      }
      var controlId = dateControl.id;
      controlId = controlId.replace('calendar_', '');
      return showCalendar(controlId, localizedFormat, false, true, defaultDate);
}


var currentlyDisplayedHelp;

/**
 * Pops up a div to display context sensitive help.
 */
function showHelp()
{
   if(currentlyDisplayedHelp)
      removeHelp();
   var div = document.createElement("DIV");
   var style = div.style;
   style.position = 'absolute';
   style.display = 'block';
   style.xindex = 99;
   div.innerHTML = getHelpInnerHtml(this.helpText);
   var position = getAbsolutePosition(this);
   style.left = (position.x + 25) + "px";
   style.top = position.y + "px";
   document.body.appendChild(div);
   currentlyDisplayedHelp = div;
   //let the event propagate and then add an onclcik event to the whole document for removing the help
   setTimeout("addEvent(document, 'click', removeHelp);", 10);
}

function getHelpInnerHtml(message)
{
   var html = '<table cellpadding="0" cellspacing="0" class="helpTable" ' +
   'summary="layout table for displaying context sensitive help">' +
   '<tr><td class="topLeft"></td><td class="top"></td><td class="topRight"></td></tr>' +
   '<tr><td class="left"></td><td class="middle">' + message + '</td><td class="right"></td></tr>' +
   '<tr><td class="bottomLeft"></td><td class="bottom"></td><td class="bottomRight"></td></tr>' +
   '</table>';
   
   return html;
}

/**
 * Remove the context sensitive help div from the document.
 */
function removeHelp()
{
   if(currentlyDisplayedHelp)
   {
      currentlyDisplayedHelp.style.display = 'none';
      document.body.removeChild(currentlyDisplayedHelp);
      currentlyDisplayedHelp = null;
      removeEvent(document, 'click', removeHelp);
   }
}

function getAbsolutePosition(el) 
{
   var SL = 0, ST = 0;
   var is_div = /^div$/i.test(el.tagName);
   if (is_div && el.scrollLeft)
      SL = el.scrollLeft;
   if (is_div && el.scrollTop)
      ST = el.scrollTop;
   var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
   if (el.offsetParent) {
      var tmp = this.getAbsolutePosition(el.offsetParent);
      r.x += tmp.x;
      r.y += tmp.y;
   }
   return r;
}

/**
 * Check whether the field provided has context sensitive help.
 * @param {Object} fieldOrId
 */
function hasHelp(fieldOrId)
{
   var field = $(fieldOrId);
   var id = field.id;
   id = 'help_' + id;
   return $(id) != null;
}

/*
* Switches the current page to edit mode if in 
* read mode or read mode if in edit mode
*/
function switchPageMode() {
  if ($F("e") == "1") {
    if (window.location.href.indexOf("e=1") >= 0) {
      window.location.href = window.location.href.replace("e=1", "e=0");
    } else {
      if (window.location.href.indexOf("#") >= 0) {
        window.location.href = window.location.href.substring(0, window.location.href.indexOf("#"));
      } else {
        window.location.href = window.location.href + "&e=0";
      }
    }
  } else {
    if (window.location.href.indexOf("e=0") >= 0) {
      window.location.href = window.location.href.replace("e=0", "e=1");
    } else {
      if (window.location.href.indexOf("#") >= 0) {
        window.location.href = window.location.href.substring(0, window.location.href.indexOf("#"));
      } else {
        window.location.href = window.location.href + "&e=1";
      }
    }
  }
}

/**
 * Prevent memory leak in IE. See pattern 1 on:
 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp
 * <p>
 * This method is to be run on page unload, as it is responsible for undoing
 * circular references set up by registerFieldAsMandatoryDependent().
 */
function breakCircularReferences()
{
   for (var i = 0; i < LAYOUT.masterFields.length; i++)
   {
      LAYOUT.masterFields[i].dependents = null;
   }

   for (var i = 0; i < LAYOUT.dependentFields.length; i++)
   {
      LAYOUT.dependentFields[i].registeredAsDependents = null;
   }
}

