(function($) {
  // ver: 0.0.1
  $.fn.esValidate = function(settings) {
    var opts = {
      'errAfter':'after', //expects jquery selector that is sibling to current input field
      'highlight':null, //expects jquery selector that is sibling to current input field OR true and desired highlight will have class='for_inputname'
      'submit':null, //expects jquery selector within form
      'hideMessage':false,
      'callback':null,
      'onError':null
    };
    
    if (settings) opts = $.extend(opts,settings);
    
    return this.each(function() {
      var form = $(this);
      var emailReg = new RegExp(/^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$/);
      var numReg = new RegExp(/^[0-9]/);
      var cvvReg = new RegExp(/^[0-9]{3,4}$/);
      var nameReg = new RegExp(/^[\w]+[\s]+[\w]*.?[\s]*[\w]+$/);
      
      var etc = [];
      etc.clean = true;
      etc.locked = false;
      etc.errItems = [];
      formulate = function() {
        form.find('[class*=vd]').each(function() {
          var vdtypes = getTypes($(this));
          if (vdtypes) {
            len = vdtypes.length;
            for (i=0;i<len;i++) {
              var vdtype = vdtypes[i];
              $(this).change(function() { vFormat(this,vdtype); }).keyup(function(e) { getFormat(this,vdtype,e); }).addClass('x_fc');
              switch (vdtype) {
                case "ph":
                  $(this).attr('maxlength', '14');
                  break;
              }
            }
            addMsg(this);
          }
        })
        .end()
        .unbind('submit')
        .submit(function() {
          form.find('.vd_error').hide();
          form.find('.err').removeClass('err');
          form.find('.err_color').removeClass('err_color');
          
          etc.clean = true;
          etc.targ = null;
          etc.errItems = [];
          $(this).find('.x_fc').each(function() {
            var vdtypes = getTypes($(this));
            var len = vdtypes.length;
            for (i=0;i<len;i++) {
              var vdtype = vdtypes[i];
              if (this.type != 'file') this.value = this.value.trim();
              switch (vdtype) {
                case 'req':
                  switch (this.type) {
                    case 'checkbox':
                      if (!this.checked) {
                        showMsg(this);
                        i=len;
                      }
                      break;
                    default:
                      if (this.value == "") {
                        showMsg(this);
                        i=len;
                      }
                  }
                  break;
                case 'em':
                  if (!emailReg.test(this.value)) {
                    showMsg(this,' *&nbsp;invalid&nbsp;email.');
                  }
                  break;
                case 'num':
                  if (!numReg.test(this.value)) {
                    showMsg(this,' *&nbsp;invalid&nbsp;format.');
                  }
                  break;
                case 'cvv':
                  if (!cvvReg.test(this.value)) {
                    showMsg(this,' *&nbsp;invalid&nbsp;format.');
                  }
                  break;
                case 'name':
                  if (!nameReg.test(this.value)) {
                    showMsg(this,' *&nbsp;"First&nbsp;Last".');
                  }
                  break;
              }
            }
          });
          if (!etc.clean) {
            $('[name="'+etc.targ+'"]').focus().select();
            if (opts.onError) opts.onError(etc.errItems);
            return false;
          } else {
            if (opts.callback) {
              //if callback returns false cancle submission 
              if (opts.callback() === false) return false;
            }
          }
        });
        return false;
      };

      function getTypes(obj) {
        var vdtypes = null;
        var list = $(obj).attr('class').split(" ");
        var len = list.length;
        for (i=0;i<len;i++) {
          if (list[i].indexOf("vd-") >= 0) {
            cl = list[i].substring(3,list[i].length);
            vdtypes = cl.split("-");

            return vdtypes;
          }
        }
        return null;
      };

      function addMsg(obj,msg) {
        if (opts.hideMessage) return;
        if (!msg) { msg = " *&nbsp;required."; }
        var error = "<span class='vd_error' for='"+obj.name+"' id='"+obj.name+"'>"+msg+"</span>";
        if (opts.errAfter == 'after') {
          $(obj).after(error);
        } else {
          $(obj).siblings(opts.errAfter).append(error);
        }
      };

      function showMsg(id,msg) {
        var name = $(id).attr('name')
        etc.clean = false;
        if (!msg) { msg = " *&nbsp;required."; }
        if (!opts.hideMessage) $('span[id="'+name+'"]').html(msg).show().shake();
        $(id).addClass('err'); // add border to input
        
        if (opts.highlight == true) form.find('.for_'+name).addClass('err_color');
        else if (opts.highlight) $(id).parent().find(opts.highlight).addClass('err_color');
        
        etc.errItems.push(name);
        
        if (etc.targ == null) {
          etc.targ = name;
        }
      };

      function vFormat(obj,type) {
        var val;
        switch (type) {
          case "ph":
            if (obj.value!="") {
              val = obj.value.stripPunctuation();
              var a=val.substring(0,3);
              var b=val.substring(3,6);
              var c=val.substring(6,10);
              if(a.length>0) val="("+a;
              if (b!=""||a.length==3){
                val=val+") "+b;
              }
              if (c!=""||b.length==3){
                val=val+"-"+c;
              }
              obj.value = val;
            }
            break;
        }
      };

      function getFormat(obj,type,e) {
        switch (type) {
          case "ph":
            if (checkNumber(e)) {
              vFormat(obj,type);
            } else {
              obj.value = obj.value.stripLetters();
            }
        }
      };
      
      String.prototype.trim = function() {
        return this.replace(/^\s+|\s+$/g,"");
      }

      String.prototype.stripPunctuation = function() {
        return this.replace( /[~`\.,;!@#\$%\^\*&\+=<>"\/:\?'\|\(\)\[\]_\-\\\s]/g, '');
      };

      String.prototype.stripLetters = function() {
        return this.replace( /[A-Za-z]/g, '');
      };

      function checkNumber(e){
        // detect last key pressed. if not a number, then dont do anything.
        var key = e.keyCode;
        return ((key>47 && key<58)||(key>95&&key<106))
      };
      
      if (opts.submit) {
        form.find(opts.submit).click(function(e) {
          e.preventDefault();
          form.submit();
        });
      }
      
      // form.keypress(function(e) {
        // if (e.target.className.indexOf('nsoe') != -1) return;
        // code = e.keyCode ? e.keyCode : e.which;
        // if(code.toString() == 13) {
            // form.submit();
        // }
      // });
      
      formulate();
    });
  };

  $.fn.shake = function (repeat) {
    return this.each(function() {
      $(this).stop(1,1).animate( { marginLeft:"10px" }, 50 )
      .animate( { marginLeft:"0px" } , 50 )
      .animate( { marginLeft:"5px"}, 80 )
      .animate( { marginLeft:"0px" } , 120 );
    })
  };
})(jQuery);
