/***************************************
   =Simple jQuery Validation Plugin
************************************** */

;(function($) { 

$.fn.tinyvalidate = function(options) {
  var errCount = 0, timer, currentFieldset = null; 

  var corerules = {
    required:     {
                    ruleClass: 'required',
                    rule: function(r) {
                      return (/\S+/).test(r);
                    },
                    text: '&laquo; required field has no value'
                  },
    email:        {
                    ruleClass: 'email',
                    rule: function(r) {
                      return (/^\S+[@]\w+(\.[a-zA-Z0-9]{2,4}){1,4}/).test(r) || r == '';
                    },
                    text: '&laquo; incorrect E-mail format',
                    check: 'value'
                  },
    zip:  {
                    ruleClass: 'zip',
                    rule: function(r) {
                     return (/^\d{5}(-\d{4})?$/).test(r) || r == '';
                    },
                    text: '&laquo; incorrect ZIP code',
                    check: 'value'
                  }
  };
  var rules = $.extend({},corerules, $.tinyvalidate.morerules || {});

  return this.each(function() {
    
    var errCount = 0, 
      errMsg = '',
      $form = $(this);
    
    
    var opts = $.extend({}, $.fn.tinyvalidate.defaults, options || {}, $.metadata ? $form.metadata() : $.meta ? $form.data() : {});
    
    function validate(evt) {
      errMsg = '';
      errCount = 0;
      $.each(rules, function(rulename, val) {

        $('.' + val.ruleClass, $form)[evt != 'submit' ? evt : 'each'](function() {
          var $field = $(this);
          
          var $errElement = (/(radio|checkbox)/).test(rulename) ? $field : $field.parents('div:first');
          
          // if a field is both required and validated against another rule, 
          // ...don't process other rule if empty 
          if (rulename !== 'required' && $field.hasClass('required') && $field.val() == '') {
            return;
          }
         
          $errElement.removeClass(opts.errorClass).find(opts.noticeElement + '.' + opts.noticeClass).remove();
          var arg = val.check == 'element' ? $field : $field.val();
          if (!val.rule(arg) && !$field.is(':trulyHidden')) {
            errCount++;
            var postype = opts.positionType;
            if (opts.positionElement.join().match('inline')) {

              if ( (/(input|select|textarea)/i).test(this.nodeName) ) {
                if (postype == 'append') {
                  postype = 'after';
                } else if (postype == 'prepend') {
                  postype = 'before';
                }
              } else if (this.nodeName.toLowerCase() === 'fieldset' ) {
                if (postype == 'after') {
                  postype = 'append';
                } else if (postype == 'before') {
                  postype = 'prepend';
                }                
              }
              $(this)[postype]('<' + opts.noticeElement + ' class="' + opts.noticeClass + '">' + val.text + '</' + opts.noticeElement + '>');
              $errElement.addClass(opts.errorClass);
            } 
            if (opts.submitDetails === true) {
              var detailText = $field.is('fieldset') ? $field.children(':first').text() : $field.prev().text().replace(/\*$/,'');
              errMsg += '<' + opts.noticeElement + ' class="' + opts.noticeClass + '">' + detailText + ' ' + val.text + '</' + opts.noticeElement + '>';            
            }
          }       
        });
    
      });
    }
    
    if (opts.primaryEvent == 'submit') {
      $form.bind('submit', function() {
        validate(opts.primaryEvent);
        insertMessage();
        if (errCount) {return false;}
      });      
    } else {
      validate(opts.primaryEvent);
    }
    if (opts.secondaryEvent && opts.secondaryEvent == 'submit') {
      $form.bind('submit', function() {
        validate(opts.secondaryEvent);
        insertMessage();        
        if (errCount) {return false;}
      }); 
    } else if (opts.secondaryEvent) {
      validate(opts.secondaryEvent);
    }
     
    function insertMessage() {
      if (errCount) {
        $('#submiterror').remove();
        var $errorElement = $(opts.wrapper), 
          pel = opts.positionElement;  
        if (pel[0] == 'inline') {pel = pel.slice(1).join();}
        if (pel == 'form') {pel = $form[0];}
        $errorElement.addClass(opts.errorClass).attr('id','submiterror').html(opts.preNotice + errMsg + opts.postNotice);
        $(pel)[opts.positionType]($errorElement);
      }
    }
    
  }); //end return this.each
}; // end $.fn.tinyvalidate

$.tinyvalidate = {};

// validation defaults

$.fn.tinyvalidate.defaults = {
  positionType: 'append', 
  positionElement: ['inline'],
  submitDetails: true,
  wrapper: '<div></div>',
  noticeElement: 'span',
  noticeClass: 'notice',
  preNotice: 'There was an error processing your request. Please correct the above highlighted fields and try again. Thank you.',
  postNotice: '',
  errorClass: 'error',
  primaryEvent: 'blur',
  secondaryEvent: 'submit'
};

/***************************************
   =optional rules to add to the plugin
************************************** */

$.tinyvalidate.morerules = {
    date:          {
                    ruleClass: 'date',
                    rule: function(r) {
                      // var thisYear = new Date().getFullYear();
                      /* loose: */
                      return (/(0?\d|1[0-2])[\/ -]?(0?\d|[1-2]\d|3[0-1])[\/ -]?[1-2]\d{3}/).test(r);
                      /* strict:
                      return (/(0\d|1[0-2])\/([0-2]\d|3[0-1])\/[1-2]\d{3}/).test(r);
                      */
                      // && (+r.slice(-4) < +thisYear-10);
                    },
                    text: '&laquo; incorrect date',
                    check: 'value'
                  },
    ssn:          {
                    ruleClass: 'ssn',
                    rule: function(r) {
                      var thisYear = new Date().getFullYear();
                      return (/\d{3}-\d{2}-\d{4}/).test(r);
                    },
                    text: '&laquo; incorrect ssn format (must be xxx-xx-xxxx)',
                    check: 'value'
                  },

    currency:     {
                    ruleClass: 'currency',
                    rule: function(r) {
                      var thisYear = new Date().getFullYear();
                      return (/^\d+(\.\d\d)?$/).test(r) || r == ''; // To make it required, remove --> || r == ''
                    },
                    text: '&laquo; incorrect currency format',
                    check: 'value'
                  },
  cbrequired: {
    ruleClass: 'cb-required',
    rule: function(el) {
      if (el.constructor == Object) {
        return el.is(':checked');
      }
    }, 
    text: 'this checkbox must be checked',
    check: 'element'
  },
  requiredradio:{
                  ruleClass: 'choose-one',
                  rule: function(el) {
                    if (el.constructor == Object) {
                      return el.find(':checked').length;
                    }
                  },
                  text: '&laquo; at least one option must be selected',
                  check: 'element'
                },
  maxradio:     {
                    ruleClass: 'max',
                    rule: function(el) {
                      return (el.find('input:checked').length < 3);
                    },
                    text: '&laquo; no more than 2 may be checked',
                    check: 'element'
                },
  phone:        {
                  ruleClass: 'phone',
                  rule: function(r) {
                    return (/(\(?\d{3}\)?)?[\. -]?\d{3}[\. -]?\d{4}/).test(r) || r == '';
                  },
                  text: '&laquo; phone number is incorrectly formatted ',
                  check: 'value'
                },
  salary:        {
                  ruleClass: 'salary',
                  rule: function(r) {
                    return (/^(?:\$ ?)?[1-9](?:\d|,\d{3})*(?:\.\d{2})?$/).test(r) || r == '';
                  },
                  text: '&laquo; hourly rate/salary is incorrectly formatted ',
                  check: 'value'
                },
  emailnone:    {
                  ruleClass: 'emailnone',
                  rule: function(r) {
                      return (/^\S+[@]\w+(\.[a-zA-Z0-9]{2,4}){1,4}/).test(r) || (/^none$/i).test(r);
                  },
                  text: '&laquo; incorrect E-mail format or enter \'None\' ',
                  check: 'value'
                },
  digitsonly:   {
                  ruleClass: 'digitsonly',
                  rule: function(r) {
                    return (/^\d+$/).test(r) || r == '';
                  },
                  text: '&laquo; Only digits are allowed in this field ',
                  check: 'value'
                }

};
 
 
$.extend(jQuery.expr[ ":" ], { 
  trulyHidden : function(a,i,m) {
    return (jQuery(a).is(':hidden') || jQuery(a).parents(':hidden').length);
  }
});
})(jQuery);

