/* ===================================================================================================
* 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
==================================================================================================== */

/*
 * FormValidator.js
 *
 * Company: Hyfinity Ltd
 * Copyright (c) 2003
 *
 * Generic form validation class.
 * Allows the user to specify compulsory fields and other validation
 * information in a declarative manner, all form validation is then
 * taken care of automatically.
 *
 * @author <a href="rafel.bordas@hyfinity.com">Rafel Bordas</a>
 * @version 1.1
 */

hyf.validation =
{
    version: '1.1',
    desc:    'Contains all the functionality relating to validating forms and displaying any errors'
}

/**
 * Simple utility function to validate all the fields on the form
 * and display the errors in the appropriate way.
 * @return A boolean value indicating whether or not there were errors.
 */
hyf.validation.validateForm = function()
{
    //get the form validator and error display objects
    var fv = hyf.FMAction.getFormValidator();
    var ed = hyf.FMAction.getErrorDisplay();

    ed.resetDisplay();
    var errors = fv.checkForm();
    ed.addErrors(errors);
    if (ed.hasErrorsToShow())
    {
        ed.showErrors();
        return false;
    }
    else
    {
        return true;
    }
}

/**
 * Simple utility function to validate all the fields in a given container
 * and display the errors in the appropriate way.
 * @param container The HTML component (eg DIV) that contains the fields to valdiate.
 * @return A boolean value indicating whether or not there were errors.
 */
hyf.validation.validateContainer = function(container)
{
    //get the form validator and error display objects
    var fv = hyf.FMAction.getFormValidator();
    var ed = hyf.FMAction.getErrorDisplay();

    ed.resetDisplay(container);
    var errors = fv.checkContainer(container);
    ed.addErrors(errors);
    if (ed.hasErrorsToShow(container))
    {
        ed.showErrors(container);
        return false;
    }
    else
    {
        return true;
    }
}

/**
 * Simple utility function to validate the given field
 * and display any errors in the appropriate way.
 * @param field The HTML field (eg input) to validate.
 * @return A boolean value indicating whether or not there were errors.
 */
hyf.validation.validateField = function(field)
{
    //get the form validator and error display objects
    var fv = hyf.FMAction.getFormValidator();
    var ed = hyf.FMAction.getErrorDisplay();

    var errors;

    if ((typeof(field.declaredClass) != 'undefined') && (field.declaredClass.indexOf('dijit.form.') == 0))
    {
        //field is actually a dojo widget
        errors = fv.checkWidget(field);
        field = document.getElementById(field.id);
    }
    else
        errors = fv.checkField(field);

    ed.resetDisplay(field);

    if ((errors != null) && (errors.length != 0))
        ed.addErrors(errors);

    if (ed.hasErrorsToShow(field))
    {
        ed.showErrors(field, false);
        return false;
    }
    else
    {
        return true;
    }
}








 /*
  * Constructs a new form validator object.
  *
  * @param form A HTML form to validate
  */
hyf.validation.FormValidator = function(form)
{
    this._form = form;

    //set up the type validation classes
    this._numberValidator = new hyf.validation.NumberValidator();
    this._stringValidator = new hyf.validation.StringValidator();
    this._booleanValidator = new hyf.validation.BooleanValidator();
    this._dateValidator = new hyf.validation.DateValidator();
}

/*
 * Return the HTML form associated with the validator
 *
 * @return The HTML Form being validated
 */
hyf.validation.FormValidator.prototype.getForm = function()
{
    return this._form;
}



/*
 * Validates the form object associated with this FormValidator.
 *
 * @return An array of ValidationError objects indicating the validation errors.
 */
hyf.validation.FormValidator.prototype.checkForm = function()
{
    var invalidFields = new Array();
    for (var i = 0; i < this._form.elements.length; ++i)
    {
        var element = this._form.elements[i];

        var fieldErrors = this.checkField(element)
        if (fieldErrors != null)
        {
            invalidFields = invalidFields.concat(fieldErrors);
        }
    }

    //add in any dojo widget errors
    invalidFields = invalidFields.concat(this.checkWidgets(this._form));

    return invalidFields;
}

/**
 * Checks the given field to see if it is valid.
 * @param field The field on the page to validate.
 * @return One or more ValidationError objects detailing the validation problems with the given field.
 *         If multiple errors, these are contained within an array, if no errors, null is returned.
 */
hyf.validation.FormValidator.prototype.checkField = function(field, checkHidden, checkEditableTable)
{
    if ((field.getAttribute("_type") != undefined) && (field.getAttribute("_type") != null) && (field.getAttribute("_type") != ''))
    {
        //check if the element should be validated
        if (this.shouldFieldBeValidated(field, checkHidden, checkEditableTable))
        {
            switch(field.getAttribute("_type"))
            {
                case "number":
                      return this._numberValidator.check(field);
                case "string":
                      return this._stringValidator.check(field);
                case "boolean":
                      return this._booleanValidator.check(field);
                case "date":
                      return this._dateValidator.check(field);
                default:
                      return new hyf.validation.ValidationError(field, hyf.validation.ValidationError.ERROR_INVALID_TYPE);
            }
        }
    }
    return null;
}

/**
 * Checks it the given field should actually be validated.
 * this checks the actual validation control flag, as well as looking at the
 * location of the field, eg is it hidden etc.
 *
 * @param field The HTML control to check
 * @param checkHidden Optional boolean value indicating whether we should check if the field is hidden
 *                  or not to determine whether to validate.  If false (the default), then fields in a hidden
 *                  container will not be validated unless they are only hidden due to being on a tab that
 *                  is not currently selected.
 * @param checkEditableTable Optional boolean value indicating whether to check fields that are specific controls
 *                  for the editable table new row functionality.  If false (the default), then these fields will
 *                  not be validated.
 * @param isWidget Optional flag indicating whether the field param is actually a dojo widget.  Defaults to false.
 * @return A boolean value indicating whether or not the provided field should be validated.
 */
hyf.validation.FormValidator.prototype.shouldFieldBeValidated = function(field, checkHidden, checkEditableTable, isWidget)
{
    //if the field is disabled then dont validate
    if (field.disabled || field.readOnly)
        return false;

    if (isWidget)
        field = document.getElementById(field.id)

    //if the validate flag is false then dont validate
    if (field.getAttribute("_validate") == 'false')
        return false;

    //check if the field is in a hidden group
    if (typeof(checkHidden) != 'boolean')
        checkHidden = false;
    if (!checkHidden)
    {
        var hiddenParent = hyf.util.findFieldHiddenParent(field)
        if (hiddenParent != null)
        {
            //check if the field is actually only hidden due to being in a non selected tab
            var parentTab = hyf.util.findFieldTabParent(field);
            if ((parentTab == null) || (parentTab != hiddenParent))
            {   //not in tab, so dont validate.
                return false;
            }

            if (parentTab == hiddenParent)
            {
                //check that there is actually a tab button for this tab pane
                var tabFieldId = parentTab.getAttribute('_tabField');
                if (document.getElementById(tabFieldId) == null)
                    return false
            }
        }
    }

    //check for editable table controls
    if (typeof(checkEditableTable) != 'boolean')
        checkEditableTable = false;
    if (!checkEditableTable && (typeof(hyf.editabletable) != 'undefined') && hyf.editabletable.checkNewRowField(field))
        return false;

    //no reason not to validate, so return true
    return true;
}

/**
 * Validates all fields within the given HTML container.
 * @param container The HTML container (eg DIV) containing the fields to validate.
 * @return An array of ValidationError objects indicating the valdiation errors with the fields checked.
 */
hyf.validation.FormValidator.prototype.checkContainer = function(container)
{
    if (container == null || typeof(container) == 'undefined')
        return null;

    var errors = new Array();

    //check any input fields
    var inputs = container.getElementsByTagName('input');
    for (var i = 0; i < inputs.length; ++i)
    {
        var fe = this.checkField(inputs[i], null, true)
        if (fe != null)
            errors = errors.concat(fe);
    }

    //check any textareas
    inputs = container.getElementsByTagName('textarea');
    for (var i = 0; i < inputs.length; ++i)
    {
        var fe = this.checkField(inputs[i], null, true)
        if (fe != null)
            errors = errors.concat(fe);
    }

    //check any select boxes
    inputs = container.getElementsByTagName('select');
    for (var i = 0; i < inputs.length; ++i)
    {
        var fe = this.checkField(inputs[i], null, true)
        if (fe != null)
            errors = errors.concat(fe);
    }

    //add in any dojo widget errors
    errors = errors.concat(this.checkWidgets(container, null, true));

    return errors;
}

/*
 * Looks for any dojo widgets in the provided container, and checks if they are valid
 * If not, then an ValidationError object is created for the error.
 * @param container The DOM Node to check in
 * @return The array of ValdiationError objects found.
 */
hyf.validation.FormValidator.prototype.checkWidgets = function(container, checkHidden, checkEditableTable)
{
    var errors = new Array();

    //check dijit available
    if ((typeof(dijit) != 'undefined') && (typeof(dijit.findWidgets) == 'function'))
    {
        var widgets = dijit.findWidgets(container);
        for (var i = 0; i < widgets.length; ++i)
        {
            var widget = widgets[i];

            errors = errors.concat(this.checkWidget(widget, checkHidden, checkEditableTable));

            //check if this dojo container widget contains other widgets that we need to check
            if (typeof(widget.getChildren) == 'function')
            {
                widgets = widgets.concat(widget.getChildren());
            }
        }
    }

    return errors;
}


/*
 * Attempts to validate the provided dojo widget, and returns an array of
 * ValidationError objects for any errors found.
 * @param widget The dojo widget to validate
 * @return The array of ValdiationError objects found.
 */
hyf.validation.FormValidator.prototype.checkWidget = function(widget, checkHidden, checkEditableTable)
{
    var errors = new Array();

    if (this.shouldFieldBeValidated(widget, checkHidden, checkEditableTable, true))
    {
        var widgetField = document.getElementById(widget.id);

        var widgetValue = widget.attr('value');
        var widgetDisplayedValue = widget.attr('displayedValue');
        var emptyValue = false;
        //if the widget has a displayed value, then use this for checking, otherwise look at the value
        if ((typeof(widgetDisplayedValue) != 'undefined') && (widgetDisplayedValue != null))
        {
            if (widgetDisplayedValue == '')
                emptyValue = true
        }
        else if (widgetValue == '')
            emptyValue = true;

        if (emptyValue)
        {
            if ((typeof(widget.required) != 'undefined') && (widget.required))
            {
                errors = errors.concat(
                    new hyf.validation.ValidationError(widgetField, hyf.validation.ValidationError.ERROR_REQUIRED));
            }
        }

        if (typeof(widget.isValid) == 'function')
        {
            if (!widget.isValid())
            {
                errors = errors.concat(
                    new hyf.validation.ValidationError(widgetField, hyf.validation.ValidationError.ERROR_INVALID));
            }
        }
    }

    return errors;
}

/*
* Checks each form element in the form associated with this formValidator
* to see if its value needs to be converted.
* If so this method actually changes the values of the fields on the form
*/
hyf.validation.FormValidator.prototype.convertFormValues = function()
{
    for (var i = 0; i < this._form.elements.length; ++i)
    {
        var element = this._form.elements[i];

        if ((element.getAttribute("_type") != undefined) && (element.getAttribute("_type") != null) && (element.getAttribute("_type") != ''))
        {
            //check if the element should be validated
            if (element.getAttribute("_validate") != 'false')
            {
                hyf.validation.ValueConverter.convertField(element)
            }
        }
    }
}


/**
 * Checks through the given container for any dojo widgets
 * and performs any initialisation steps needed to make them better fit
 * with our styling and validation approach.
 * This currently only deals with FilteringSelect and ComboBox widgets
 * @param container The container to check in for dojo widgets.  If this is not provided
 *              then the document will be used.
 */
hyf.validation.initiateWidgets = function(container)
{
    if (typeof(container) == 'undefined')
        container = document.body;

    if ((typeof(dijit) != 'undefined') && (typeof(dijit.findWidgets) == 'function'))
    {
        var widgets = dijit.findWidgets(container);

        for (var i = 0; i < widgets.length; ++i)
        {
            var widget = widgets[i];

            if (widget.declaredClass.indexOf('dijit.form.') == 0)
            {
                widget.displayMessage = function(message) {};
                dojo.removeClass(widget.textbox, 'dijitReset');
            }
            else if (typeof(widget.getChildren) == 'function')
            {
                //check if this dojo container widget contains other widgets that we need to check
                widgets = widgets.concat(widget.getChildren());
            }
        }
    }
}

hyf.validation.initialWidgetInitHandle = dojo.connect(dojo.parser, 'parse', function() {
    hyf.validation.initiateWidgets();
    dojo.disconnect(hyf.validation.initialWidgetInitHandle);
    hyf.validation.initialWidgetInitHandle = null;
});