/**
*	@name							Valid8
*	@descripton						An input field validation plugin for Jquery
*	@version						1.3
*	@requires						Jquery 1.3.2+
*
*	@author							Jan Jarfalk
*	@author-email					jan.jarfalk@unwrongest.com
*	@author-website					http://www.unwrongest.com
*
*	@licens							MIT License - http://www.opensource.org/licenses/mit-license.php
*/

(function ($) {
    $.fn.extend({

        valid8: function (options) {
            return this.each(function () {

                $(this).data('valid', false);
                $(this).data('isOnLoad', true);

                var defaultOptions = {
                    regularExpressions: [],
                    ajaxRequests: [],
                    jsFunctions: [],
                    validationEvents: ['keyup'],
                    validationFrequency: 550,
                    values: null,
                    defaultErrorMessage: 'Required'
                };

                if (typeof options == 'string')
                    defaultOptions.defaultErrorMessage = options;

                if (this.type == 'checkbox') {
                    defaultOptions.regularExpressions = [{ expression: /^true$/, errormessage: defaultOptions.defaultErrorMessage}];
                    defaultOptions.validationEvents = ['click'];
                } else if (this.type == 'select-one' || this.type == 'select-multiple') {
                    defaultOptions.regularExpressions = [{ expression: /^.+$/, errormessage: defaultOptions.defaultErrorMessage}];
                    defaultOptions.validationEvents = ['change'];
                }
                else
                    defaultOptions.regularExpressions = [{ expression: /^.+$/, errormessage: defaultOptions.defaultErrorMessage}];

                $(this).data('settings', $.extend(defaultOptions, options));

                initialize(this);
                setTimeout("$('#" + $(this).attr('id') + "').data('isOnLoad', false);", 500);
            });
        },

        isValid: function () {
            var valid = true;
            this.each(function (item, index) {
                validate(this);
                if ($(this).data('valid') == false)
                    valid = false;
            });
            return valid;
        }

    });

    function initializeDataObject(el) {
        $(el).data('loadings', new Array());
        $(el).data('errors', new Array());
        $(el).data('valids', new Array());
        $(el).data('keypressTimer', null);
    }

    function initialize(el) {
        initializeDataObject(el);


        if ($(el).attr('value').length > 0 && el.type != 'checkbox') {
            validate(el);
        }
        activate(el);
    };

    function activate(el) {
        var events = $(el).data('settings').validationEvents;
        if (typeof events == 'string')
            $(el)[events](function (e) { handleEvent(e, el); });
        else {
            $.each(events, function (i, event) {
                $(el)[event](function (e) { handleEvent(e, el); });
            });
        }
    };

    function validate(el) {
        // Dispose old errors and valids
        initializeDataObject(el);

        var value;

        // Handle checkbox
        if (el.type == 'checkbox') {
            value = el.checked.toString();
        }
        else {
            value = el.value;
        }

        regexpValidation(value.replace(/^[ \t]+|[ \t]+$/, ''), el);
    };

    function regexpValidation(value, el) {

        $.each($(el).data('settings').regularExpressions, function (i, validator) {
            if (!validator.expression.test(value))
                $(el).data('errors')[$(el).data('errors').length] = validator.errormessage;
            else if (validator.validmessage)
                $(el).data('valids')[$(el).data('valids').length] = validator.validmessage;
        });

        if ($(el).data('errors').length > 0)
            onEvent(el, { 'valid': false });
        else if ($(el).data('settings').jsFunctions.length > 0) {
            functionValidation(value, el);
        }
        else if ($(el).data('settings').ajaxRequests.length > 0) {
            fileValidation(value, el);
        }
        else {

            onEvent(el, { 'valid': true });
        }

    };

    function functionValidation(value, el) {

        $.each($(el).data('settings').jsFunctions, function (i, validator) {

            var v;
            if (validator.values) {
                if (typeof validator.values == 'function')
                    v = validator.values();
            }

            var values = v || value;

            handleLoading(el, validator);

            if (validator['function'](values).valid)
                $(el).data('valids')[$(el).data('valids').length] = validator['function'](values).message;
            else
                $(el).data('errors')[$(el).data('errors').length] = validator['function'](values).message;
        });

        if ($(el).data('errors').length > 0)
            onEvent(el, { 'valid': false });
        else if ($(el).data('settings').ajaxRequests.length > 0) {
            fileValidation(value, el);
        }
        else {
            onEvent(el, { 'valid': true });
        }
    };

    function fileValidation(value, el) {


        $.each($(el).data('settings').ajaxRequests, function (i, validator) {

            var v;
            if (validator.values) {
                if (typeof validator.values == 'function')
                    v = validator.values();
            }

            var values = v || { value: value };

            handleLoading(el, validator);

            $.post(validator.url, values,
			  function (data, textStatus) {
			      if (data == null)
			          return;

			      if (data.valid) {
			          $(el).data('valids')[$(el).data('valids').length] = data.message || validator.validmessage || "";
			      } else {
			          $(el).data('errors')[$(el).data('errors').length] = data.message || validator.errormessage || "";
			      }
			      if ($(el).data('errors').length > 0)
			          onEvent(el, data);
			      else {
			          onEvent(el, data);
			      }
			  }, "json");
        });

    };

    function handleEvent(e, el) {
        if (e.keyCode && $(el).attr('value').length > 0) {
            clearTimeout($(el).data('keypressTimer'));
            $(el).data('keypressTimer', setTimeout(function () {
                validate(el);
            }, $(el).data('settings').validationFrequency));
        }
        else if (e.keyCode && $(el).attr('value').length <= 0)
            return false;
        else {
            validate(el);
        }
    };

    function handleLoading(el, validator) {
        if (validator.loadingmessage) {
            $(el).data('loadings')[$(el).data('loadings').length] = validator.loadingmessage;
            onEvent(el, { 'valid': null });
        }
    };

    function onEvent(el, response) {

        if (response.valid === true) {
            messages = $(el).data('valids');
            $(el).data('valid', response.valid);
            $(el).trigger('valid', [response, el]);
        } else if (response.valid === false) {
            messages = $(el).data('errors');
            $(el).data('valid', response.valid);
            $(el).trigger('error', [response, el]);
        } else {
            messages = $(el).data('loadings');
            $(el).trigger('loading', [response, el]);
        }

        if ($(el).data('isOnLoad') == false) {
            setParentClass(el, response.valid);
            setMessage(messages, el);
        }
    }

    function setParentClass(el, valid) {
        var className = (valid) ? 'valid' : 'error';
        var parent = $(el).closest('p');
        parent[0].className = (parent[0].className.replace(/(^\s|(\s*(loading|error|valid)))/g, '') + ' ' + className).replace(/^\s/, '');
    }

    function setMessage(messages, el) {
        var parent = $(el).parent();
        var elementId = el.id + "ValidationMessage";
        var elementClass = 'validationMessage';
        if (!$('#' + elementId).length > 0) {
            parent.append('<span id="' + elementId + '" class="' + elementClass + '"></span>');
        }

        $('#' + elementId).html("");
        $('#' + elementId).text(messages[0]);
    };

})(jQuery);
