/*
	Class: FormCheckPlus
		Validation.

	Parameters:
		When you initialize the class with addEvent, you can set some options. If you want to modify regex, you must do it in a hash, like for display or alert. You can also add new regex check method by adding the regex and an alert with the same name.

		Required:

			form_id - The id of the formular. This is required.

		Optional:

			submit					- If you turn this option to false, the FormCheck will only perform a validation, without submitting the form, even on success. You can use validateSuccess event to execute some code.

			submitByAjax 			- you can set this to true if you want to submit your form with ajax. You should use provided events to handle the ajax request (see below). By default it is false.
			ajaxResponseDiv 		- id of element to inject ajax response into (can also use onAjaxSuccess). By default it is false.
			ajaxEvalScripts 		- use evalScripts in the Request response. Can be true or false, by default it is false.
			onAjaxRequest 			- Function to fire when the Request event starts.
			onAjaxSuccess 			- Function to fire when the Request receives .  Args: response [the request response] - see Mootools docs for Request.onSuccess.
			onAjaxFailure 			- Function to fire if the Request fails.

			onSubmit				- Function to fire when form is submited (so before validation)
			onValidateSuccess 		- Function to fire when validation pass (you should prevent form submission with option submit:false to use this)
			onValidateFailure		- Function to fire when validation fails

			tipsClass 				- The class to apply to tipboxes' errors. By default it is 'fc-tbx'.
			errorClass 				- The class to apply to alertbox (not tips). By default it is 'fc-error'.
			fieldErrorClass 		- The class to apply to fields with errors, except for radios. You should also turn on  options.addClassErrorToField. By default it is 'fc-field-error'

			trimValue				- If set to true, strip whitespace (or other characters) from the beginning and end of values. By default it is false.
			validateDisabled		- If set to true, disabled input will be validated too, otherwise not.

		Display:
			This is a hash of display settings. in here you can modify.

			showErrors 			- 0 : onSubmit, 1 : onSubmit & onBlur, by default it is 0.
			titlesInsteadNames		- 0 : When you do a check using differs or confirm, it takes the field name for the alert. If it's set to 1, it will use the title instead of the name.
			errorsLocation 			- 1 : tips, 2 : before, 3 : after, by default it is 1.
			indicateErrors 			- 0 : none, 1 : one by one, 2 : all, by default it is 1.
			indicateErrorsInit		- 0 : determine if the form must be checked on initialize. Could be usefull to force the user to update fields that don't validate.
			keepFocusOnError 		- 0 : normal behaviour, 1 : the current field keep the focus as it remain errors. By default it is 0.
			checkValueIfEmpty 		- 0 : When you leave a field and you have set the showErrors option to 1, the value is tested only if a value has been set. 1 : The value is tested  in any case.  By default it is 1.
			addClassErrorToField 	- 0 : no class is added to the field, 1 : the options.fieldErrorClass is added to the field with an error (except for radio). By default it is 0.
			removeClassErrorOnTipClosure - 0 : Error class is kept when the tip is closed, 1 : Error class is removed when the tip is closed

			fixPngForIe 			- 0 : do nothing, 1 : fix png alpha for IE6 in formcheck.css. By default it is 1.
			replaceTipsEffect 		- 0 : No effect on tips replace when we resize the broswer, 1: tween transition on browser resize;
			closeTipsButton 		- 0 : the close button of the tipbox is hidden, 1 : the close button of the tipbox is visible. By default it is 1.
			flashTips 				- 0 : normal behaviour, 1 : the tipbox "flash" (disappear and reappear) if errors remain when the form is submitted. By default it is 0.
			tipsPosition 			- 'right' : the tips box is placed on the right part of the field, 'left' to place it on the left part. By default it is 'right'.
			tipsOffsetX 			- Horizontal position of the tips box (margin-left), , by default it is 100 (px).
			tipsOffsetY				- Vertical position of the tips box (margin-bottom), , by default it is -10 (px).

			listErrorsAtTop 		- List all errors at the top of the form, , by default it is false.
			scrollToFirst 			- Smooth scroll the page to first error and focus on it, by default it is true.
			fadeDuration 			- Transition duration (in ms), by default it is 300.

		Alerts:

	Example:
		You can initialize a formcheck (no scroll, custom classes and alert) by adding for example this in your html head this code :

		(code)
		<script type="text/javascript">
			window.addEvent('domready', function() {
				var myCheck = new FormCheck('form_id', {
					tipsClass : 'tips_box',
					display : {
						scrollToFirst : false
					},
					alerts : {
						required : 'This field is ablolutely required! Please enter a value'
					}
				})
			});
		</script>
		(end code)

	About:
		formcheck.js v.1.5 for mootools v1.2 - 09 / 2009

		by Mootools.Floor (http://mootools.floor.ch) MIT-style license

		Created by Luca Pillonel, 
		Last modified by Luca Pillonel

	Credits:
		This class was inspired by formcheck by Luca Pillonel

		Thanks to all contributors from groups.google.com/group/moofloor (and others as well!) providing ideas, fixes and motivation!
 */

var FormCheck = new Class(
{
    Implements :
    [ Options, Events ],

    options :
    {

        tipsClass : 'fc-tbx', // tips error class
        errorClass : 'fc-error', // div error class
        fieldErrorClass : 'fc-field-error', // error class for elements

        submit : true, // false : just validate the form and do nothing
        // else. Use onValidateSuccess event to execute
        // some code

        trimValue : false, // trim (remove whitespaces before and
        // after) the value
        validateDisabled : false, // skip validation on disabled input
        // if set to false.

        submitByAjax : false, // false : standard submit way, true :
        // submit by ajax
        ajaxResponseDiv : false, // element to inject ajax response
        // into (can also use onAjaxSuccess)
        // [cronix]
        ajaxEvalScripts : false, // use evalScripts in the Request
        // response [cronix]
        onAjaxRequest : $empty, // Function to fire when the Request
        // event starts
        onAjaxSuccess : $empty, // Function to fire when the Request
        // receives . Args: response [the
        // request response] - see Mootools docs
        // for Request.onSuccess
        onAjaxFailure : $empty, // Function to fire if the Request fails

        onSubmit : $empty, // Function to fire when user submit the
        // form
        onValidateSuccess : $empty, // Function to fire when validation
        // pass
        onValidateFailure : $empty, // Function to fire when validation
        // fails

        display :
        {
            showErrors : 0,
            titlesInsteadNames : 0,
            errorsLocation : 1,
            indicateErrors : 1,
            indicateErrorsInit : 0,
            keepFocusOnError : 0,
            checkValueIfEmpty : 1,
            addClassErrorToField : 0,
            removeClassErrorOnTipClosure : 0,
            fixPngForIe : 1,
            replaceTipsEffect : 1,
            flashTips : 0,
            closeTipsButton : 1,
            tipsPosition : "right",
            tipsOffsetX : -45,
            tipsOffsetY : 0,
            listErrorsAtTop : false,
            scrollToFirst : true,
            fadeDuration : 300
        }

    },

    /*
     * Constructor: initialize Constructor
     *
     */
    initialize : function( formId, options )
    {
        if ((this.form = $(formId)) != undefined )
        {
            this.form.isValid = true;
            this.regex =
            [ 'length' ];
            this.setOptions(options);

            // internalization
            if (typeof (formcheckLanguage) != 'undefined')
            {
                this.options.alerts = $merge( this.options.alerts,
                    formcheckLanguage );
            }

            this.validations = [];
            this.alreadyIndicated = false;
            this.firstError = false;

            var regex = new Hash(this.options.regexp);
            regex.each(function(el, key)
            {
                this.regex.push(key);
            }, this);

            var formElements = this.form
            .getElements("*[class*=validate]");
            formElements.each(function(el)
            {
                if (el.get('tag') == 'select'
                    || el.get('tag') == 'input'
                    || el.get('tag') == 'textarea')
                    {
                    this.register(el);
                }
            }, this);

            this.form.addEvents(
            {
                "submit" : this.onSubmit.bind(this)
            });

            if (this.options.display.fixPngForIe)
            {
                this.fixIeStuffs();
            }
            document.addEvent('mousewheel', function()
            {
                this.isScrolling = false;
            }.bind(this));
        }
    },


    setElementRules : function(elToCheck, checks)
    {
        if(elToCheck != null)
        {
            elToCheck.checks = checks;
            elToCheck.validation =
            [];
            this.validations.push(elToCheck);
            this.addListener(elToCheck);
        }
    },
    /*
			 * Function: dispose Allows you to remove a declared field from
			 * formCheck
			 * 
			 * Example: (code) <script type="text/javascript">
			 * window.addEvent('domready', function() { formcheck = new
			 * FormCheck('form_id'); }); // ...some code...
			 * 
			 * formcheck.dispose($('obsolete-field')); </script> (end code)
			 * 
			 * See also: <FormCheck::register>
			 */
    dispose : function(element)
    {
        this.validations.erase(element);
    },

    showHostElementError : function(el, msg)
    {
        if(el.errors==undefined)
        {
            el.errors = [];
        }
        el.errors.push(msg);
        this.addError(el);
    },
    /*
			 * Function: addListener Private method
			 * 
			 * Add listener on fields
			 */
    addListener : function(el)
    {
        el.errors =
        [];

        if (this.options.display.indicateErrorsInit)
        {
            this.validations.each(function(el)
            {
                if (!this.manageError(el, 'submit'))
                    this.form.isValid = false;
            }, this);
            return true;
        }
        if( el.checks[0] != undefined )
        {
            if (el.checks[0].message == 'submit')
            {
                el.addEvent('click', function(e)
                {
                    if (this.onSubmit(e))
                    {
                            this.form.submit();
                    }
                        
                }.bind(this));
                return true;
            }

        }

        if (this.isChildType(el) == false)
            el
            .addEvent(
                'blur',
                function()
                {
                    (function()
                    {
                        if (!this.fxRunning
                            && (el.element || this.options.display.showErrors == 1)
                            && (this.options.display.checkValueIfEmpty || el.value))
                            this.manageError(el, 'blur');
                    }.bind(this)).delay(100);
                }.bind(this));
        // We manage errors on radio
        else if (this.isChildType(el) == true)
        {
            // We get all radio from the same group and add a blur
            // option
            var nlButtonGroup = this.form
            .getElements('input[name="' + el
                .getProperty("name") + '"]');
            nlButtonGroup
            .each(
                function(radio)
                {
                    radio
                    .addEvent(
                        'blur',
                        function()
                        {
                            (function()
                            {
                                if ((el.element || this.options.display.showErrors == 1)
                                    && (this.options.display.checkValueIfEmpty || el.value))
                                    this
                                    .manageError(
                                        el,
                                        'click');
                            }.bind(this))
                            .delay(100);
                        }.bind(this))
                }, this);
        }
    },

    /*
			 * Function: validate Private method
			 * 
			 * Dispatch check to other methods
			 */
    validate : function(el)
    {
        el.errors =
        [];
        el.isOk = true;

        // skip validation and trim if specified
        if (!this.options.validateDisabled && el.get('disabled'))
            return true;
        if (this.options.trimValue && el.value)
            el.value = el.value.trim();

        el.continueChecks = true;

        // use encapsulated validator classes
        // checking is a simple loop
        // check if we have validators and it is required or optional and nonempty
        if (el.checks != undefined && el.checks.length > 0  )
        {
            el.checks.each( function( validator )
            {
                if( validator != undefined )
                {
                    if( el.continueChecks && validator.proceedWithValidation( el ) )
                    {
                        if (!validator.validate(el))
                        {
                            el.isOk = false;
                            el.errors.push(validator.getMessage(el));
                        }
                    }
                    else
                    {
                        el.continueChecks = false;
                    }
                }


            });
            return el.isOk;
        }

        if (el.isOk)
            return true;
        else
            return false;
    },

    /*
			 * Function: isFormValid public method
			 * 
			 * Determine if the form is valid
			 * 
			 * Return true or false
			 */
    isFormValid : function()
    {
        this.form.isValid = true;
        this.validations.each(function(el)
        {
            var validation = this.manageError(el, 'testonly');
            if (!validation)
                this.form.isValid = false;
        }, this);
        return this.form.isValid;
    },

    /*
			 * Function: isChildType Private method
			 * 
			 * Determine if the field is a group of radio or not.
			 */
    isChildType : function(el)
    {
        return ($defined(el.type) && el.type == 'radio') ? true : false;
    },

    /*
			 * Function: validateGroup Private method
			 * 
			 * Perform radios validations
			 */
    validateGroup : function(el)
    {
        el.errors =
        [];
        var nlButtonGroup = this.form[el.getProperty("name")];
        el.group = nlButtonGroup;
        var cbCheckeds = false;

        for ( var i = 0; i < nlButtonGroup.length; i++)
        {
            if (nlButtonGroup[i].checked)
            {
                cbCheckeds = true;
            }
        }
        if (cbCheckeds == false)
        {
            el.errors.push(this.options.alerts.radios);
            return false;
        }
        else
        {
            return true;
        }
    },

    /*
			 * Function: listErrorsAtTop Private method
			 * 
			 * Display errors
			 */
    listErrorsAtTop : function(obj)
    {
        if (!this.form.element)
        {
            this.form.element = new Element('div',
            {
                'id' : 'errorlist',
                'class' : this.options.errorClass
            }).injectTop(this.form);
        }
        if ($type(obj) == 'collection')
        {
            new Element('p').set(
                'html',
                "<span>" + obj[0].name + " : </span>"
                + obj[0].errors[0]).injectInside(
                this.form.element);
        }
        else
        {
            if ((obj.validation.contains('required') && obj.errors.length > 0)
                || (obj.errors.length > 0 && obj.value && obj.validation
                    .contains('required') == false))
                    {
                obj.errors.each(function(error)
                {
                    new Element('p').set('html',
                        "<span>" + obj.name + " : </span>" + error)
                    .injectInside(this.form.element);
                }, this);
            }
        }
        window.fireEvent('resize');
    },

    /*
			 * Function: manageError Private method
			 * 
			 * Manage display of errors boxes
			 */
    manageError : function(el, method)
    {
        var isValid = this.validate(el);
        if (method == 'testonly')
            return isValid;
        if (el.checks != undefined)
        {
            //					if (((!isValid && el.checks.contains(checks.required_chk))
            //							|| (!el.checks.contains(checks.required_chk) && el.value && !isValid)))
            if( !isValid )
            {
                if (this.options.display.listErrorsAtTop == true
                    && method == 'submit')
                    {
                    this.listErrorsAtTop(el);
                }
                if (this.options.display.indicateErrors == 2
                    || this.alreadyIndicated == false
                    || el.name == this.alreadyIndicated.name)
                    {
                    if (!this.firstError)
                        this.firstError = el;

                    this.alreadyIndicated = el;

                    if (this.options.display.keepFocusOnError
                        && el.name == this.firstError.name)
                        (function()
                        {
                            el.focus()
                        }).delay(20);
                    this.addError(el);
                    return false;
                }
            }

        }
				
        if ((isValid ))
        {
            this.removeError(el);
            return true;
        }
        return true;
    },

    /*
			 * Function: addError Private method
			 * 
			 * Add error message
			 */
    addError : function(obj)
    {
        // determine position
        var coord = obj.target ? $(obj.target).getCoordinates() : obj
        .getCoordinates();

        if (!obj.element && this.options.display.indicateErrors != 0)
        {
            if (this.options.display.errorsLocation == 1)
            {
                var pos = (this.options.display.tipsPosition == 'left') ? coord.left
                : coord.right;
                var options =
                {
                    'opacity' : 0,
                    'position' : 'absolute',
                    'float' : 'left',
                    'left' : pos + this.options.display.tipsOffsetX
                }
                obj.element = new Element('div',
                {
                    'class' : this.options.tipsClass,
                    'styles' : options
                }).injectInside(document.body);
                this.addPositionEvent(obj);
            }
            else if (this.options.display.errorsLocation == 2)
            {
                obj.element = new Element('div',
                {
                    'class' : this.options.errorClass,
                    'styles' :
                    {
                        'opacity' : 0
                    }
                }).injectBefore(obj);
            }
            else if (this.options.display.errorsLocation == 3)
            {
                obj.element = new Element('div',
                {
                    'class' : this.options.errorClass,
                    'styles' :
                    {
                        'opacity' : 0
                    }
                });
                if ($type(obj.group) == 'object'
                    || $type(obj.group) == 'collection')
                    obj.element
                    .injectAfter(obj.group[obj.group.length - 1]);
                else
                    obj.element.injectAfter(obj);
            }
        }
        if (obj.element && obj.element != true)
        {
            obj.element.empty();
            if (this.options.display.errorsLocation == 1)
            {
                var errors =
                [];
                obj.errors.each(function(error)
                {
                    errors.push(new Element('p').set('html', error));
                });
                var tips = this.makeTips(errors).injectInside(
                    obj.element);
                if (this.options.display.closeTipsButton)
                {
                    tips.getElements('a.close').addEvent('mouseup',
                        function()
                        {
                            this.removeError(obj, 'tip');
                        }.bind(this));
                }
                obj.element.setStyle('top', coord.top
                    - tips.getCoordinates().height
                    + this.options.display.tipsOffsetY);
            }
            else
            {
                obj.errors.each(function(error)
                {
                    new Element('p').set('html', error).injectInside(
                        obj.element);
                });
            }

            if (!this.options.display.fadeDuration
                || Browser.Engine.trident
                && Browser.Engine.version == 5
                && this.options.display.errorsLocation < 2)
                {
                obj.element.setStyle('opacity', 1);
            }
            else
            {
                obj.fx = new Fx.Tween(obj.element,
                {
                    'duration' : this.options.display.fadeDuration,
                    'ignore' : true,
                    'onStart' : function()
                    {
                        this.fxRunning = true;
                    }.bind(this),
                    'onComplete' : function()
                    {
                        this.fxRunning = false;
                        if (obj.element
                            && obj.element.getStyle('opacity')
                            .toInt() == 0)
                            {
                            obj.element.destroy();
                            obj.element = false;
                        }
                    }.bind(this)
                })
                if (obj.element.getStyle('opacity').toInt() != 1)
                    obj.fx.start('opacity', 1);
            }
        }
        if (this.options.display.addClassErrorToField
            && this.isChildType(obj) == false)
            {
            obj.addClass(this.options.fieldErrorClass);
            obj.element = obj.element || true;
        }

    },

    /*
			 * Function: addPositionEvent
			 * 
			 * Update tips position after a browser resize
			 */
    addPositionEvent : function(obj)
    {
        if (this.options.display.replaceTipsEffect)
        {
            obj.event = function()
            {
                var coord = obj.target ? $(obj.target).getCoordinates()
                : obj.getCoordinates();
                new Fx.Morph(obj.element,
                {
                    'duration' : this.options.display.fadeDuration
                })
                .start(
                {
                    'left' :
                    [
                    obj.element.getStyle('left'),
                    coord.right
                    + this.options.display.tipsOffsetX ],
                    'top' :
                    [
                    obj.element.getStyle('top'),
                    coord.top
                    - obj.element
                    .getCoordinates().height
                    + this.options.display.tipsOffsetY ]
                });
            }.bind(this);

        }
        else
        {
            obj.event = function()
            {
                var coord = obj.target ? $(obj.target).getCoordinates()
                : obj.getCoordinates();
                obj.element.setStyles(
                {
                    'left' : coord.right
                    + this.options.display.tipsOffsetX,
                    'top' : coord.top
                    - obj.element.getCoordinates().height
                    + this.options.display.tipsOffsetY
                });
            }.bind(this)
        }
        window.addEvent('resize', obj.event);
    },

    /*
			 * Function: removeError Private method
			 * 
			 * Remove the error display
			 */
    removeError : function(obj, method)
    {
        if ((this.options.display.addClassErrorToField
            && !this.isChildType(obj) && this.options.display.removeClassErrorOnTipClosure)
        || (this.options.display.addClassErrorToField
            && !this.isChildType(obj)
            && !this.options.display.removeClassErrorOnTipClosure && method != 'tip'))
            obj.removeClass(this.options.fieldErrorClass);

        if (!obj.element)
            return;
        this.alreadyIndicated = false;
        obj.errors =
        [];
        obj.isOK = true;
        window.removeEvent('resize', obj.event);
        if (this.options.display.errorsLocation >= 2 && obj.element)
        {
            new Fx.Tween(obj.element,
            {
                'duration' : this.options.display.fadeDuration
            }).start('height', 0);
        }
        if (!this.options.display.fadeDuration
            || Browser.Engine.trident
            && Browser.Engine.version == 5
            && this.options.display.errorsLocation == 1
            && obj.element)
            {
            this.fxRunning = true;
            obj.element.destroy();
            obj.element = false;
            (function()
            {
                this.fxRunning = false
            }.bind(this)).delay(200);
        }
        else if (obj.element && obj.element != true)
        {
            obj.fx.start('opacity', 0);
        }
    },

    /*
			 * Function: focusOnError Private method
			 * 
			 * Create set the focus to the first field with an error if needed
			 */
    focusOnError : function(obj)
    {
        var dest = 0;
        if (this.options.display.scrollToFirst && !this.alreadyFocused
            && !this.isScrolling)
            {
            if (!this.options.display.indicateErrors
                || !this.options.display.errorsLocation)
                {
                dest = obj.getCoordinates().top - 30;
            }
            else if (this.alreadyIndicated.element)
            {
                switch (this.options.display.errorsLocation)
                {
                    case 1:
                        dest = obj.element.getCoordinates().top;
                        break;
                    case 2:
                        dest = obj.element.getCoordinates().top - 30;
                        break;
                    case 3:
                        dest = obj.getCoordinates().top - 30;
                        break;
                }
                this.isScrolling = true;
            }
            if (window.getScroll.y != dest)
            {
                new Fx.Scroll(window,
                {
                    onComplete : function()
                    {
                        this.isScrolling = false;
                        if (obj.getProperty('type') != 'hidden')
                            obj.focus();
                    }.bind(this)
                }).start(0, dest);
            }
            else
            {
                this.isScrolling = false;
                obj.focus();
            }
            this.alreadyFocused = true;
        }
    },

    /*
			 * Function: fixIeStuffs Private method
			 * 
			 * Fix png for IE6
			 */
    fixIeStuffs : function()
    {
        if (Browser.Engine.trident4)
        {
            // We fix png stuffs
            var rpng = new RegExp('url\\(([\.a-zA-Z0-9_/:-]+\.png)\\)');
            var search = new RegExp('(.+)formcheck\.css');
            for ( var i = 0; i < document.styleSheets.length; i++)
            {
                if (document.styleSheets[i].href
                    .match(/formcheck\.css$/))
                    {
                    var root = document.styleSheets[i].href.replace(
                        search, '$1');
                    var count = document.styleSheets[i].rules.length;
                    for ( var j = 0; j < count; j++)
                    {
                        var cssstyle = document.styleSheets[i].rules[j].style;
                        var bgimage = root
                        + cssstyle.backgroundImage.replace(
                            rpng, '$1');
                        if (bgimage && bgimage.match(/\.png/i))
                        {
                            var scale = (cssstyle.backgroundRepeat == 'no-repeat') ? 'crop'
                            : 'scale';
                            cssstyle.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, src=\''
                            + bgimage
                            + '\', sizingMethod=\''
                            + scale + '\')';
                            cssstyle.backgroundImage = "none";
                        }
                    }
                }
            }
        }
    },

    /*
			 * Function: makeTips Private method
			 * 
			 * Create tips boxes
			 */
    makeTips : function(txt)
    {
        var table = new Element('table');
        table.cellPadding = '0';
        table.cellSpacing = '0';
        table.border = '0';

        var tbody = new Element('tbody').injectInside(table);
        var tr1 = new Element('tr').injectInside(tbody);
        new Element('td',
        {
            'class' : 'tl'
        }).injectInside(tr1);
        new Element('td',
        {
            'class' : 't'
        }).injectInside(tr1);
        new Element('td',
        {
            'class' : 'tr'
        }).injectInside(tr1);
        var tr2 = new Element('tr').injectInside(tbody);
        new Element('td',
        {
            'class' : 'l'
        }).injectInside(tr2);
        var cont = new Element('td',
        {
            'class' : 'c'
        }).injectInside(tr2);
        var errors = new Element('div',
        {
            'class' : 'err'
        }).injectInside(cont);
        txt.each(function(error)
        {
            error.injectInside(errors);
        });
        if (this.options.display.closeTipsButton)
            new Element('a',
            {
                'class' : 'close'
            }).injectInside(cont);
        new Element('td',
        {
            'class' : 'r'
        }).injectInside(tr2);
        var tr3 = new Element('tr').injectInside(tbody);
        new Element('td',
        {
            'class' : 'bl'
        }).injectInside(tr3);
        new Element('td',
        {
            'class' : 'b'
        }).injectInside(tr3);
        new Element('td',
        {
            'class' : 'br'
        }).injectInside(tr3);
        return table;
    },

    /*
			 * Function: reinitialize Reinitialize form before submit check. You
			 * can use this also to remove all tips from a form, passing the
			 * argument "forced" ( formcheck.reinitialize('forced'); )
			 */
    reinitialize : function(forced)
    {
        this.validations.each(function(el)
        {
            if (el.element)
            {
                el.errors =
                [];
                el.isOK = true;
                if (this.options.display.flashTips == 1
                    || forced == 'forced')
                    {
                    el.element.destroy();
                    el.element = false;
                }
            }
        }, this);
        if (this.form.element)
            this.form.element.empty();
        this.alreadyFocused = false;
        this.firstError = false;
        this.elementToRemove = this.alreadyIndicated;
        this.alreadyIndicated = false;
        this.form.isValid = true;
    },

    /*
			 * Function: submitByAjax Private method
			 * 
			 * Send the form by ajax, and replace the form with response
			 */

    submitByAjax : function()
    {
        var url = this.form.getProperty('action');
        this.fireEvent('ajaxRequest');
        new Request(
        {
            url : url,
            method : this.form.getProperty('method'),
            data : this.form.toQueryString(),
            evalScripts : this.options.ajaxEvalScripts,
            onFailure : function(instance)
            {
                this.fireEvent('ajaxFailure', instance);
            }.bind(this),
            onSuccess : function(result)
            {
                this.fireEvent('ajaxSuccess', result);
                if (this.options.ajaxResponseDiv)
                    $(this.options.ajaxResponseDiv).set('html',
                        result);
            }.bind(this)
        }).send();
    },

    /*
			 * Function: onSubmit Private method
			 * 
			 * Perform check on submit action
			 */
    onSubmit : function(event)
    {
        this.reinitialize();
        this.fireEvent('onSubmit');

        this.validations.each(function(el)
        {
            var validation = this.manageError(el, 'submit');
            if (!validation)
                this.form.isValid = false;
        }, this);

        if (this.form.isValid)
        {
            if (this.options.submitByAjax)
            {
                new Event(event).stop();
                this.submitByAjax();
            }
            else if (!this.options.submit)
            {
                new Event(event).stop();
            }
            this.fireEvent('validateSuccess');
            return true;
        }
        else
        {
            new Event(event).stop();
            if (this.elementToRemove
                && this.elementToRemove != this.firstError
                && this.options.display.indicateErrors == 1)
                {
                this.removeError(this.elementToRemove);
            }
            this.focusOnError(this.firstError);
            this.fireEvent('validateFailure');
            return false;
        }
    }
});



