/* ===================================================================================================
* WARNING – This file is part of the base implementation for WebMaker, so it should not be edited or changed for any project.
* These files are replaced if a project is re-imported to the WebMaker Studio or migrated to a new version of the product.
* For guidance on ‘How do I override or clone Hyfinity webapp files such as CSS & javascript?’, please read the following relevant FAQ entry:
* http://www.hyfinity.net/faq/index.php?solution_id=1113
==================================================================================================== */

/**
 * ErrorDisplay.js
 *
 * Company: Hyfinity Ltd
 * Copyright (c) 2003
 *
 * Generic javscript object for highlighting validation errors in a form
 *
 * @author Gerard Smyth
 * @version 1.1
 *
 */


hyf.validation.ErrorDisplay = function(displayMethod)
{
    this._displayMethod = displayMethod;
    this._showMessage = true;
    this._fieldStyle = "";
    this._messageStyle = "";
    this._fieldClass = "";
    this._messageClass = "";
    this._mainMessageLocation = "";
    this._mainMessageString = "";
    /** Stores whether popup alerts should be used. */
    this._showAlerts = false;
    /** Stores the message string that will be shown in the alert window.*/
    this._alertMessage = '';
    /** Indicates whether all errors should be highlighted ('all'), or just the first ('one').
     * This currently only applies to the alert messages. */
    this._validationMode = 'one';

    /** This stores all the new errors that have not yet been shown in the screen. */
    this._newErrors = new Array();
    /** This stores all the errors that are currently visible on the screen. */
    this._shownErrors = new Array();


    // provide backward compatability by handling the old display method of alert.
    if (displayMethod == 'alert')
    {
        this._displayMethod = 'none';
        this._showAlerts = true;
    }

}

/** sets the css style to apply to a field container if it has an error*/
hyf.validation.ErrorDisplay.prototype.setFieldStyle = function(style)
{
    this._fieldStyle = style;
}
/** sets the css class to apply to a field container if it has an error*/
hyf.validation.ErrorDisplay.prototype.setFieldClass = function(newClass)
{
    this._fieldClass = newClass;
}
/** sets the css style to apply to a error message container if the associated field has an error*/
hyf.validation.ErrorDisplay.prototype.setMessageStyle = function(style)
{
    this._messageStyle = style;
}
/** sets the css class to apply to a error message container if the associated field has an error*/
hyf.validation.ErrorDisplay.prototype.setMessageClass = function(newClass)
{
    this._messageClass = newClass;
}

/** sets whether or not error messages should be shown with the highlighting*/
hyf.validation.ErrorDisplay.prototype.setShowMessage = function(showMessage)
{
    this._showMessage = showMessage;
}

/** sets whether the error messages should be shown together in a top level DIV
 * @param messageLocation the name of the DIV to use to show the error messages, or null to stop this display*/
hyf.validation.ErrorDisplay.prototype.setMessageLocation = function(messageLocation)
{
    this._mainMessageLocation = messageLocation;
}

/** sets a specific string that should be used in the top level DIV instead of the specific error messages*/
hyf.validation.ErrorDisplay.prototype.setMessageString = function(messageString)
{
    this._mainMessageString = messageString;
}

/** sets whether alert messages shoulf be shown along with the visual highlighting.
 * Popup alert messages should be used for speech browsers. */
hyf.validation.ErrorDisplay.prototype.setShowAlerts = function(showAlerts)
{
    this._showAlerts = showAlerts;
}
/** sets the validationMode. Either 'all' or 'one'.
 * This value is curretnly only used for the alert popup to decide whether to include all errors or just one.
 */
hyf.validation.ErrorDisplay.prototype.setValidationMode = function(validationMode)
{
    this._validationMode = validationMode;
}

/**
 * Adds the provided ValdiationError object to the list to be displayed
 * at some point in the future.
 * @param error The ValdiationError object defining the error.
 */
hyf.validation.ErrorDisplay.prototype.addError = function(error)
{
    this.addErrors([error]);
}

/**
 * Adds all of the provided ValdiationError objects to the list of errors
 * to be displayed at some point in the future.
 * @param errors An array of ValdiationError objects defining the errors.
 */
hyf.validation.ErrorDisplay.prototype.addErrors = function(errors)
{
    this._newErrors = this._newErrors.concat(errors);
}

/**
 * Checks whether there are any errors to be displayed for the specified component.
 * This will only return true if a call to showErrors with the same component
 * will display some errors.
 * @param component (optional) The HTML component to check if there are any errors for
 * @return boolean indicating whether there are any errors to show.
 */
hyf.validation.ErrorDisplay.prototype.hasErrorsToShow = function(component)
{
    for (var i=0; i< this._newErrors.length; ++i)
    {
        //check if this error applies to the given component
        if ((component == null) || (typeof(component) == 'undefined') ||
            (hyf.util.isParent(this._newErrors[i].getField(), component)))
        {
            return true;
        }
    }
    return false;
}

/**
 * Main function that displays validation errors.
 * This will display any errors that have been added by the add methods above since the last time this
 * function was called (for the same component)
 *
 * @param component (optional) The HTML component to show errors for.  This can be an individual field,
 *          or a container element (eg DIV) holding a number of fields. If not provided, then all
 *          the new errors will be displayed.
 * @param changeFocus (optional) A boolean value indicating whether the focus should be changed
 *          to the first field in error.  If not provided then the focus will be changed.
 */
hyf.validation.ErrorDisplay.prototype.showErrors = function(component, changeFocus)
{
    var currentField = "";
    for (var i=0; i< this._newErrors.length; ++i)
    {
        var fieldName = hyf.validation.ErrorDisplay.getFieldName(this._newErrors[i].getField());

        //check if this error applies to the given component
        if ((component == null) || (typeof(component) == 'undefined') ||
            (hyf.util.isParent(this._newErrors[i].getField(), component)))
        {
            //stop showing a second error for the same field
            if (fieldName != currentField)
            {
                currentField = fieldName;
                this.updateDisplay(this._newErrors[i]);
            }

            //move the error into the showErrors array
            this._shownErrors.push(this._newErrors[i]);
            this._newErrors.splice(i, 1);
            --i; //reduce the pointer as we have reduced the length of the array

        }
    }

    if (currentField != '')
    {
        //put the focus on the first field in error
        if ((typeof(changeFocus) == 'undefined') || (changeFocus))
            this.focusErrorField();

        if (this._showAlerts)
        {
            alert(this._alertMessage);
            this._alertMessage = "";
        }
    }
}

/**
 * Tries to put the focus into the first field in error.
 */
hyf.validation.ErrorDisplay.prototype.focusErrorField = function()
{
    for (var i = 0; i < this._shownErrors.length; ++i)
    {
        var ve = this._shownErrors[i];
        var errorField = ve.getField();

        try
        {
            //check if the field is hidden
            var hiddenParent = hyf.util.findFieldHiddenParent(errorField)
            if (hiddenParent != null)
            {
                //check if the field is actually only hidden due to being in a non selected tab
                var parentTab = hyf.util.findFieldTabParent(errorField);
                if ((parentTab != null) && (parentTab == hiddenParent))
                {
                    //hidden due to tab, so try and select this tab
                    var tabFieldId = parentTab.getAttribute('_tabField');
                    if (tabFieldId != null)
                    {
                        var tabBtn = document.getElementById(tabFieldId);
                        //click the tab button to make sure the correct tab is visible.
                        if (tabBtn != null)
                        {
                            tabBtn.onclick();
                            errorField.focus();
                            //if focus is successful we just return
                            return;
                        }
                    }
                }
            }
            else
            {
                errorField.focus();
                //if focus is successful we just return
                return;
            }
        }
        catch (e)
        {
            //an error occurred trying to focus the field for some reason,
            //so we just move on to try and focus the next field in error
        }
    }
}


/**
 * Function that takes a ValidationError object and displays it based on
 * this ErrorDisplay object's settings
 * @param error ValdiationError object to display
 */
hyf.validation.ErrorDisplay.prototype.updateDisplay = function(error)
{
    if (this._displayMethod == 'text') //update the styling and contents of relevant containers to show error
    {
        this.showErrorText(error);
    }
    else if (this._displayMethod == 'tooltip') //update the styling of relevant containers and create tooltip to show error
    {
        this.showErrorTooltip(error);
    }
    else if (this._displayMethod == 'none')
    {
        //do nothing
    }
    else
    {
        alert('Unknown display method!!!');
    }

    //check if the errors should be shown in combined DIV
    if ((this._mainMessageLocation != undefined) && (this._mainMessageLocation != null) && (this._mainMessageLocation != ''))
    {
        this._mainMessageLocation.style.display = "block";
        if ((this._mainMessageString != undefined) && (this._mainMessageString != null) && (this._mainMessageString != ''))
            this._mainMessageLocation.innerHTML = this._mainMessageString;
        else
            this._mainMessageLocation.innerHTML = this._mainMessageLocation.innerHTML + '<div id="' +
                            error.getField().id + '_topLevelMsg"><span>' +
                            hyf.validation.ErrorDisplay.getFieldDisplayName(error.getField()) + '</span>: ' +
                            hyf.validation.DisplayMessages.getMessage(error.getField(), error.getErrorCode()) + '</div>';
    }

    if (this._showAlerts == true) //show alert messages for errors
    {
        this.buildAlertMessage(error);
    }
}

/** Build the message to show in a popup alert.
 * If the validationMode is set to 'one' then only the first error will be alerted,
 * otherwise the alert message will detail all errors.
 */
hyf.validation.ErrorDisplay.prototype.buildAlertMessage = function(error)
{
    if ((this._validationMode == 'one') && (this._alertMessage == ''))
    {
       this._alertMessage = "Validation Error on " + hyf.validation.ErrorDisplay.getFieldDisplayName(error.getField()) +
                    "\n\n" + hyf.validation.DisplayMessages.getMessage(error.getField(), error.getErrorCode());
    }

    if (this._validationMode == 'all')
    {
        if (this._alertMessage == '')
        {
            this._alertMessage = 'Please correct the following errors:\n\n';
        }

        this._alertMessage += hyf.validation.ErrorDisplay.getFieldDisplayName(error.getField()) + "\t:\t" + hyf.validation.DisplayMessages.getMessage(error.getField(), error.getErrorCode()) + "\n";
    }
}

/** Shows the given ValidationError object using the 'text' style display
 *  ie. changes styles of the field and places the error message within the message container*/
hyf.validation.ErrorDisplay.prototype.showErrorText = function(error)
{
    var fieldName = hyf.validation.ErrorDisplay.getFieldName(error.getField());

    var fieldContainer = document.getElementById(fieldName+"_container");
    var messageContainer = document.getElementById(fieldName+"_message_container");
    if (fieldContainer != undefined)
    {
        //Store the current class and style settings for the field container
        if ((fieldContainer.className != undefined) && (fieldContainer.className != ""))
            fieldContainer.setAttribute("oldClass", fieldContainer.className);
        else
            fieldContainer.setAttribute("oldClass", "");
        fieldContainer.setAttribute("oldStyle", fieldContainer.style.cssText);

        //set the error styles for the field container
        if (this._fieldStyle != '')
        {
            if (dojo.isIE)
            {
                fieldContainer.style.cssText = this._fieldStyle;
            }
            else
            {
                fieldContainer.setAttribute("style", this._fieldStyle);
            }
        }
        if (this._fieldClass != '')
            fieldContainer.className = this._fieldClass;
    }

    if (messageContainer != undefined)
    {
        //set the error styles for the message container
        if (this._messageStyle != '')
        {
            if (dojo.isIE)
            {
                messageContainer.style.cssText = this._messageStyle;
            }
            else
            {
                messageContainer.setAttribute("style", this._messageStyle);
            }
        }
        if (this._messageClass != '')
            messageContainer.className = this._messageClass;
        messageContainer.innerHTML="&nbsp;";
    }

    if ((this._showMessage) && (messageContainer != undefined))
    {
        // alert("show hint: "+messageContainer.getAttribute("_hintMessageShow"));
        if ((messageContainer.getAttribute("_hintMessageShow") != null) && (messageContainer.getAttribute("_hintMessageShow") == 'true'))
        {
            messageContainer.innerHTML = messageContainer.getAttribute("_hintMessage");
        }
        else
        {
            messageContainer.innerHTML = hyf.validation.DisplayMessages.getMessage(error.getField(), error.getErrorCode());
        }
    }
}

/** Shows the given ValidationError object using the 'tooltip' style display
 *  ie. changes styles of the field and places the error message within an onhover tooltip*/
hyf.validation.ErrorDisplay.prototype.showErrorTooltip = function(error)
{
    var fieldName = hyf.validation.ErrorDisplay.getFieldName(error.getField());

    var fieldContainer = document.getElementById(fieldName+"_container");
    var messageContainer = document.getElementById(fieldName+"_message_container");
    if (typeof(fieldContainer) != 'undefined')
    {
        // alert("about to update field container styling");
        //Store the current class and style settings for the field container
        if ((fieldContainer.className != undefined) && (fieldContainer.className != ""))
            fieldContainer.setAttribute("oldClass", fieldContainer.className);
        else
            fieldContainer.setAttribute("oldClass", "");

        fieldContainer.setAttribute("oldStyle", fieldContainer.style.cssText);

        //set the error styles for the field container
        if (this._fieldStyle != '')
        {
            if (dojo.isIE) //use the cssText property to set the css string
            {
                fieldContainer.style.cssText = this._fieldStyle;
            }
            else //try and use the setAttribute method to set the css string
            {
                fieldContainer.setAttribute("style", this._fieldStyle);
            }
        }
        if (this._fieldClass != '')
            fieldContainer.className = this._fieldClass;
    }

    if (typeof(messageContainer) != 'undefined')
    {
        //set the error styles for the message container
        if (this._messageStyle != '')
        {
            if (dojo.isIE) //use the cssText property to set the css string
            {
                messageContainer.style.cssText = this._messageStyle;
            }
            else //try and use the setAttribute method to set the css string
            {
                messageContainer.setAttribute("style", this._messageStyle);
            }
        }
        if (this._messageClass != '')
            messageContainer.className = this._messageClass;

        /**@todo need an alternative for this hack to ensure the pictures set using css background are shown in netscape*/
        messageContainer.innerHTML="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
    }

    if (this._showMessage && (typeof(messageContainer) != 'undefined'))
    {
        // alert("show hint: "+messageContainer.getAttribute("_hintMessageShow"));
        if ((messageContainer.getAttribute("_hintMessageShow") != null) && (messageContainer.getAttribute("_hintMessageShow") == 'true'))
        {
            messageContainer.setAttribute("_tipMessage", messageContainer.getAttribute("_hintMessage"));
        }
        else
        {
            messageContainer.setAttribute("_tipMessage", hyf.validation.DisplayMessages.getMessage(error.getField(), error.getErrorCode()));
        }
        messageContainer.onmousemove = hyf.util.showTipMessage;
        messageContainer.onmouseout = hyf.util.hideTipMessage;
    }

}


/**
 * Resets the display by undoing any changes made to show any errors within the specified component
 * @param component (optional) The HTML component to remove the errors for.  This can be a single field,
 *              or a container element (such as a DIV) that contains multiple fields with potential
 *              errors displayed.  If not provided, then all displayed errors will be removed.
 */
hyf.validation.ErrorDisplay.prototype.resetDisplay = function(component)
{
    for (var i=0; i< this._shownErrors.length; ++i)
    {
        //check if this error applies to the given component
        if ((component == null) || (typeof(component) == 'undefined') ||
            (hyf.util.isParent(this._shownErrors[i].getField(), component)))
        {
            this.resetDisplayForError(this._shownErrors[i]);
            this._shownErrors.splice(i, 1);
            --i; //reduce the pointer as we have reduced the length of the array
        }
    }

    //if there are now no errors being displayed, hide the top level message if there is one.
    if (this._shownErrors.length == 0)
    {
        if ((this._mainMessageLocation != undefined) && (this._mainMessageLocation != null) && (this._mainMessageLocation != ''))
        {
            this._mainMessageLocation.style.display = "none";
            this._mainMessageLocation.innerHTML = "";
        }
    }
}

/**
 * Removes any display changes put in place to highlight the provided error
 * @param error The ValidationError object to remove the display for
 * @private Use resetDisplay instead
 */
hyf.validation.ErrorDisplay.prototype.resetDisplayForError = function(error)
{
    if ((this._displayMethod == 'text') || (this._displayMethod == 'tooltip'))
    {
        var fieldName = hyf.validation.ErrorDisplay.getFieldName(error.getField());

        var fieldContainer = document.getElementById(fieldName+"_container");
        var messageContainer = document.getElementById(fieldName+"_message_container")


        if (fieldContainer != undefined)
        {
            if (fieldContainer.getAttribute("oldClass") != null)
                fieldContainer.className = fieldContainer.getAttribute("oldClass");

            if (fieldContainer.getAttribute("oldStyle") != null)
            {
                if (dojo.isIE)
                {
                    fieldContainer.style.cssText = fieldContainer.getAttribute("oldStyle");
                }
                else
                {
                    fieldContainer.setAttribute("style", fieldContainer.getAttribute("oldStyle"));
                }
            }
        }
        if (messageContainer != undefined)
        {
            //check if the hint or server message should be reshown
            var hintMessageShow = messageContainer.getAttribute("_hintMessageShow");
            var serverMessageShow = messageContainer.getAttribute("_serverMessageShow");
            var serverMessageRetain = messageContainer.getAttribute("_serverMessageRetain");
            if ((serverMessageShow == 'true') && (serverMessageRetain == 'true'))
            {
                //reshow server message
                if (messageContainer.getAttribute("_serverClass") != null)
                    messageContainer.className = messageContainer.getAttribute("_serverClass");

                if (messageContainer.getAttribute("_serverStyle") != null)
                {
                    if (dojo.isIE)
                    {
                        messageContainer.style.cssText = messageContainer.getAttribute("_serverStyle");
                    }
                    else
                    {
                        messageContainer.setAttribute("style", messageContainer.getAttribute("_serverStyle"));
                    }
                }
                if (this._displayMethod == 'tooltip')
                {
                    messageContainer.setAttribute("_tipMessage", messageContainer.getAttribute("_serverMessage"));
                    messageContainer.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
                    messageContainer.onmousemove = hyf.util.showTipMessage;
                    messageContainer.onmouseout = hyf.util.hideTipMessage;
                }
                else if (this._displayMethod == 'text')
                {
                    messageContainer.innerHTML = messageContainer.getAttribute("_serverMessage");
                    messageContainer.setAttribute("_tipMessage", "");
                    messageContainer.onmousemove = null;
                    messageContainer.onmouseout = null;
                }
                else
                {
                    messageContainer.innerHTML = "&nbsp;"
                    messageContainer.setAttribute("_tipMessage", "");
                    messageContainer.onmousemove = null;
                    messageContainer.onmouseout = null;
                }
            }
            else if (hintMessageShow == 'true')
            {
                //reshow hint message
                if (messageContainer.getAttribute("_hintClass") != null)
                    messageContainer.className = messageContainer.getAttribute("_hintClass");

                if (messageContainer.getAttribute("_hintStyle") != null)
                {
                    if (dojo.isIE)
                    {
                        messageContainer.style.cssText = messageContainer.getAttribute("_hintStyle");
                    }
                    else
                    {
                        messageContainer.setAttribute("style", messageContainer.getAttribute("_hintStyle"));
                    }
                }
                if (this._displayMethod == 'tooltip')
                {
                    messageContainer.setAttribute("_tipMessage", messageContainer.getAttribute("_hintMessage"));
                    messageContainer.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
                    messageContainer.onmousemove = hyf.util.showTipMessage;
                    messageContainer.onmouseout = hyf.util.hideTipMessage;
                }
                else if (this._displayMethod == 'text')
                {
                    messageContainer.innerHTML = messageContainer.getAttribute("_hintMessage");
                    messageContainer.setAttribute("_tipMessage", "");
                    messageContainer.onmousemove = null;
                    messageContainer.onmouseout = null;
                }
                else
                {
                    messageContainer.innerHTML = "&nbsp;"
                    messageContainer.setAttribute("_tipMessage", "");
                    messageContainer.onmousemove = null;
                    messageContainer.onmouseout = null;
                }
            }
            else
            {
                //clear all styling
                messageContainer.className = "";
                if (dojo.isIE)
                    messageContainer.style.cssText = "";
                else
                    messageContainer.setAttribute("style", "");

                messageContainer.innerHTML = "&nbsp;"
                messageContainer.setAttribute("_tipMessage", "");
                messageContainer.onmousemove = null;
                messageContainer.onmouseout = null;
            }
        }
    }

    //remove details from the main message location if present, and not overridden
    if ((this._mainMessageLocation != undefined) && (this._mainMessageLocation != null) && (this._mainMessageLocation != ''))
    {
        if ((typeof(this._mainMessageString) == 'undefined') || (this._mainMessageString == null) || (this._mainMessageString == ''))
        {
            var topLevelError = document.getElementById(error.getField().id + '_topLevelMsg');
            if (topLevelError != null)
            {
                topLevelError.parentNode.removeChild(topLevelError);
            }
        }
    }
}

/**
 * Returns the name of the FormMaker element represented by the specified field
 *
 */
hyf.validation.ErrorDisplay.getFieldName = function(field)
{
    var name;
    if (field.getAttribute("_element") != null)
        name = field.getAttribute("_element");
    else if (field.getAttribute("_originalFieldName") != null)
        name = field.getAttribute("_originalFieldName");
    else if ((typeof(field.name) != 'undefined') && (field.name != ''))
        name = field.name;
    else
        name = field.id;

    //check if the field is only used for display, and if so remove the '_display' suffix
    if (field.getAttribute("_display_only") == 'true')
    {
        name = name.substring(0, fieldName.length - 8);
    }

    return name;
}


/** Tries to find the display name to use for the given field.
 * This is done by trying to find a label that is associated with this field,
 * and if present returning its content.
 * If this cant be found, the name of the field is simply returned.
 *
 * @param field The form control object to find the name for
 * @return the display name to use for the given field.
 */
hyf.validation.ErrorDisplay.getFieldDisplayName = function(field)
{
    var id = field.getAttribute("id");

    if (field.type == 'radio')
        id = field.name + "1";

    if ((field.type == 'checkbox') && (field.getAttribute("_use") == 'selectMany'))
        id = field.getAttribute("_element") + "1";

    if (field.getAttribute("_originalFieldName") != null)
        id = field.getAttribute("_originalFieldName");

    var usefieldset = false;
    var fieldset = null;
    //Handle the case where the radio buttons / checkboxes are contained in a fieldset,
    //but without a specific label.  In this case, we should use the fieldset legend.
    if ((field.type == 'radio') || ((field.type == 'checkbox') && (field.getAttribute("_use") == 'selectMany')))
    {
        fieldset = hyf.validation.ErrorDisplay.findFieldsetParent(field);
        if (fieldset != null)
        {
            usefieldset = true;
            inputs = fieldset.getElementsByTagName("input");
            selects = fieldset.getElementsByTagName("select");
            textareas = fieldset.getElementsByTagName("textarea");
            for (var i = 0; i < inputs.length; ++i)
            {
                inputField = inputs.item(i);

                if (inputField.type == 'radio')
                {
                    if (inputField.name != field.name)
                        usefieldset = false;
                }
                else if (inputField.type == 'checkbox')
                {
                    if (inputField.getAttribute("_element") != field.getAttribute("_element"))
                        usefieldset = false;
                }
                else
                    usefieldset = false;
            }
            if ((selects.length > 0) || (textareas.length > 0))
            {
                usefieldset = false;
            }
        }
    }

    if (usefieldset)
    {
        if (fieldset != null)
        {
            return fieldset.getElementsByTagName("legend").item(0).innerHTML;
        }
        else
            return field.name;
    }
    else
    {
        if (id != null)
        {
            var labels = document.getElementsByTagName("label");
            for (var i = 0; i < labels.length; ++i)
            {
                var forAtt = labels.item(i).getAttribute('htmlFor');
                if (forAtt == null)
                    forAtt = labels.item(i).getAttribute('for');
                if (forAtt == id)
                {
                    var labelHTML = labels.item(i).innerHTML;
                    var startSpan = labelHTML.indexOf('<SPAN');
                    if (startSpan == -1)
                        startSpan = labelHTML.indexOf('<span');
                    if (startSpan != -1)
                    {
                        if (startSpan == 0)
                        {
                            var endSpan = labelHTML.indexOf('</SPAN>');
                            if (endSpan == -1)
                                endSpan = labelHTML.indexOf('</span>');
                            return labelHTML.substr(endSpan + 7);
                        }
                        else
                        {
                            return labelHTML.substring(0, startSpan);
                        }
                    }
                    else
                        return labelHTML;
                }
            }
        }
    }
    return field.name;
}

/**
 * checks to see if the given node has a fieldset as an ancestor, and
 * if so returns it.
 * Otherwise returns null
 */
hyf.validation.ErrorDisplay.findFieldsetParent = function(node)
{
    if ((node.parentNode == null) || (node.parentNode.nodeType == 9))
    {
        return null;
    }
    else
    {
        if (node.parentNode.tagName.toUpperCase() == 'FIELDSET')
        {
            return node.parentNode;
        }
        else
        {
            return hyf.validation.ErrorDisplay.findFieldsetParent(node.parentNode);
        }
    }
}





hyf.util.showTipMessage = function(e)
{
    var tipDiv = document.getElementById('tipDiv');
    var messageDiv = document.getElementById("messageDiv");
    if ((tipDiv != null) && (messageDiv != null))
    {
        var evt;
        var target;
        if (!e)
        {
            evt = window.event;
            target = evt.srcElement;
        }
        else //netscape
        {
            evt = e;
            target = evt.currentTarget;
        }

        var pos = hyf.util.getMouseCoords(evt);
        var viewport = hyf.util.getViewportSize();

        if ((target != null) && (typeof(target) != 'undefined'))
        {

            if ((target.getAttribute("_tipMessage") != null) && (target.getAttribute("_tipMessage") != ''))
            {
                messageDiv.innerHTML = target.getAttribute("_tipMessage");

                if (dojo.isIE < 9) //IE
                {
                    tipDiv.style.visibility = 'visible';
                    tipDiv.style.display = "block";
                    messageDiv.style.visibility = "visible";
                    messageDiv.style.display = "block";

                    tipDiv.style.top = pos.y + Number(10);
                    var leftPos = Number(pos.x) - Number(tipDiv.style.pixelWidth);
                    if (leftPos < 5)
                        tipDiv.style.left = 5;
                    else
                        tipDiv.style.left = leftPos;

                    //var messageHeight = messageDiv.clientHeight  + Number(4);
                    var messageHeight = hyf.util.getComputedHeight(messageDiv)  + Number(4);
                    tipDiv.style.pixelHeight = messageHeight;
                    document.all.tipFrame.style.pixelHeight = messageHeight;

                    //check if it has gone off the bottom of the page
                    var tipBottom = pos.y + Number(10) + messageHeight;
                    if (tipBottom > viewport.height)
                    {
                        tipDiv.style.top = pos.y - Number(10) - messageHeight;
                    }
                }
                else //netscape
                {
                    tipDiv.style.visibility = "hidden";
                    messageDiv.style.visibility = "hidden";

                    //Gecko browsers work best if all positions/sizes etc are specified as a string with
                    //the units suffix (ie 'px' in this case)

                    tipDiv.style.top = (pos.y + Number(10)) + "px";
                    var leftPos = Number(pos.x) - tipDiv.style.width.substr(0, tipDiv.style.width.length-2);
                    if (leftPos < 5)
                        tipDiv.style.left = "5px";
                    else
                        tipDiv.style.left = leftPos + "px";

                    messageDiv.style.position = "fixed";

                    messageDiv.style.top = (pos.y + Number(10) - window.pageYOffset) + "px";;

                    leftPos = (pos.x - window.pageXOffset) - tipDiv.style.width.substr(0, tipDiv.style.width.length-2);
                    if (leftPos < 5)
                        messageDiv.style.left = "5px";
                    else
                        messageDiv.style.left = leftPos + "px";

                    messageDiv.style.width = tipDiv.style.width;

                    var messageHeight = parseInt(document.defaultView.getComputedStyle(messageDiv, '').getPropertyValue("height"));
                    tipDiv.style.height = messageHeight + "px";

                    document.getElementById("tipFrame").style.height = (messageHeight - Number(4)) + "px";

                    //check if it has gone off the bottom of the page
                    var tipBottom = pos.y + Number(10) + messageHeight;
                    if (tipBottom > viewport.height)
                    {
                        tipDiv.style.top = (pos.y - Number(10) - messageHeight) + 'px';
                        messageDiv.style.top = (pos.y - Number(10) - window.pageYOffset - messageHeight) + "px";;
                    }

                    tipDiv.style.visibility = 'visible';
                    tipDiv.style.display = "block";
                    messageDiv.style.visibility = "visible";
                    messageDiv.style.display = "block";
                }
                //QUESTION: What about other browsers, eg Opera


                return;
            }
        }
        tipDiv.style.visibility = "hidden";
        tipDiv.style.display = "none";
        messageDiv.style.visibility = "hidden";
        messageDiv.style.display = "none";
    }
}

hyf.util.hideTipMessage = function(e)
{
    var tipDiv = document.getElementById('tipDiv');
    var messageDiv = document.getElementById("messageDiv")
    if (tipDiv != undefined)
    {
        tipDiv.style.visibility = "hidden";
        tipDiv.style.display = "none";
    }
    if (messageDiv != undefined)
    {
        messageDiv.style.visibility = "hidden";
        messageDiv.style.display = "none";
    }
}