(function(jQuery) {

   var VALIDATORS = {
      "required": function validateRequired(value) {
         return !value ? "This field is required" : null;
      },
      "nohtml" : function validateNoHTML(value) {
         return value.indexOf("<") == -1 ? null : "HTML is not allowed";
      },
      "date" : function validateDate(value) {
         return isNaN(Date.parse(value)) ? "This is not a valid date" : null;
      },
      "email" : function validateEmail(value) {
         return /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/.test(value.toUpperCase()) ? null : "This is not a valid email address";
      },
      "integer" : function validateInteger(value) {
         return isNaN(+value) ? "This is not a number" : null;
      }
   };

   function init() {
      jQuery("form.validated").submit(handleFormSubmit);

      if (jQuery.fn.datepicker) {
         jQuery("input:not(.date),textarea").blur(handleInputChanged);
         jQuery("input.date").datepicker({
            onSelect: handleDateUpdated
         });
      } else {
         jQuery("input,textarea").blur(handleInputChanged);
      }

      if (jQuery.fn.manifest) {
         jQuery(".listBox").manifest();
      }

   }

   function handleDateUpdated() {
      validateItem(jQuery(this));
   }

   function handleInputChanged() {
      validateItem(jQuery(this));
   }

   function validateItem(jItem) {

      var
         name = jItem.attr("name"),
         value = jItem.val(),
         validatorList = jItem.data("validators") || "",
         validators = validatorList.split(","),
         errorCount = 0;

      for (var i = 0, l = validators.length; i < l; i++) {

         var validatorId = validators[i],
            validateFn = VALIDATORS[validatorId];

         if (validateFn) {

            var error = validateFn(value);

            if (error) {
               jItem.showError(error);
               errorCount++;
               break;
            }

         }

      }

      if (!errorCount) {
         jItem.hideError();
      }

      return {
         errorCount: errorCount,
         name: name,
         value: value
      }

   }

   function validate(jForm) {

      var data = {};
      var errorCount = 0;

      jForm.find("input,textarea").each(function(index, element) {

         var validationResult = validateItem(jQuery(element));

         if (validationResult.errorCount) {

            errorCount++;

         } else {

            data[validationResult.name] = validationResult.value;
         }


      });


      return {
         data: data,
         errorCount: errorCount
      };

   }

   /**
    * Displays a predefined set of errors on a particular form
    * these errors will usually have come from the server
    * @param jForm  The form on whose items the errors should be applied
    * @param errors The error JSON ( a map of item to errors)
    */
   function displayErrors(jForm, errors) {

      jForm.find("input,textarea").hideError();

      for (var key in errors) {
         jQuery("#" + key).showError(errors[key]);
      }

   }

   function handleFormSubmit(event) {

      console.log("Handling form submit");

      var
         jForm = jQuery(event.currentTarget),
         jButton = jForm.find("button"),
         url = jForm.attr("action"),
         values = validate(jForm),
         successMessage = jForm.data('success') || 'Form posted successfully',
         failureMessage = jForm.data('failure') || 'Sorry, could not submit the form. Please try again later.',
         submittingMessage = jButton.data("posting") || "Submitting...",
         buttonText = jButton.val() || jButton.text(),
         redirect = jForm.data('redirect'),
         recaptcha = jQuery("#recaptcha_widget_div");

      if (!values.errorCount) {

         if (!!recaptcha.length && !recaptcha.hasClass("visible")) {

            recaptcha.addClass("visible");

         } else {

            jButton
               .text(submittingMessage)
               .addClass("submitting");

            jQuery.ajax({
               url: url,
               data: values.data,
               success: function onPostSuccess() {

                  var redirect = jForm.data("redirect");

                  if (redirect) {
                     self.location.href = redirect;
                  } else {

                     new Dialog(successMessage, 'Message', redirect);
                     jForm.find("input,textarea").val("");
                     recaptcha.removeClass("visible");
                     jButton
                        .text(buttonText)
                        .removeClass("submitting");

                  }

               },
               error:  jQuery.proxy(function onPostError(response) {

                  if (response.status == 400) {
                     failureMessage = "Form is not valid. Please check the marked items then try again.";
                     displayErrors(jForm, jQuery.parseJSON(response.responseText));
                  } else {
                     if (response.status == 403) {
                        failureMessage = "Sorry, CAPTCHA test failed. Please try to enter the words again.";
                     }
                     new Dialog(failureMessage, 'Message');
                  }

                  jButton
                     .text(buttonText)
                     .removeClass("submitting");

               }, this)
            });

         }

      }

      return false;
   }

   jQuery(document).ready(init);

})(jQuery);


