/*
 * theValidator by ChadSteele.com  copyright 2009
 *
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */


// Don't forget the following in your code...
//
// $(document).ready(function(){
//        theValidator.init();
//        theValidator.discover();
//        theValidator.submit("form");
//        });



//useful function for number formats
function addCommas(nStr)
    {
        nStr += '';
        x = nStr.split('.');
        x1 = x[0];
        x2 = x.length > 1 ? '.' + x[1] : '';
        var rgx = /(\d+)(\d{3})/;
        while (rgx.test(x1)) {
            x1 = x1.replace(rgx, '$1' + ',' + '$2');
        }
        return x1 + x2;
    }


theValidator =
			{
            init : function(){
                $(".validator")
                    .addClass('error')
                    .hide()
                    .each(function(){
                        var validator = this;
                        var tFor = $(this).attr('for');
                        if (!tFor) alert("validator missing a 'for' attribute " + this.id);
                        this.that = document.getElementById(tFor);  //todo consider using jquery selector instead
                        this.stack = []; //defaults to valid
                        //todo: the order of the stack determines priority, the stack should be sorted according to the sequence in the class attribute
                        this.addValidator = function(x) { validator.stack.push(x); }
                        
                        this.focus = function(){  //scroll the validator into view and put the focus on "that"
                            $("html,body").animate({scrollTop: $(validator).offset().top-50},500);  
                            validator.that.focus();
                            //todo $(validator.that).animate({backgroundColor: '#FF0000'},3000);
                            //see http://interface.eyecon.ro/docs/animate
                            }
                            
                        this.isHidden = function(){
                            return $(validator.that).is(":hidden") || $(validator).parents(":hidden").length > 0;
                            }
                            
                        this.isValid = function(){

                            
                            if (validator && validator.that){
                                if ($(validator).hasClass("disabled") 
                                    || $(validator.that).hasClass("disabled")
                                    || validator.isHidden() 
                                    || validator.that.disabled 
                                    || !validator.enabled)
                                    { validator.hide(); return true;      }
                                        
                                for (var i=0; i<validator.stack.length; i++)
                                    if (!validator.stack[i]()) {validator.show(); return false;    }
                                }
                                
                            validator.hide();
                            return true;
                            }
                            
                        this.refresh = function(){ validator.isValid(); return true; }  //always return true
                        
                        this.show = function(){ 
                            if (!validator.enabled) { validator.hide(); return; }
                            if($(validator).is(":visible")) return;
                            $(validator).fadeIn(); 
                            }
                                
                        this.hide = function(){  $(validator).fadeOut();  }
                            
                        this.enabled= true;
                        this.disable = function(){validator.enabled = false; validator.hide(); $(this).addClass('disabled'); }
                        this.enable = function() {validator.enabled = true; validator.isValid(); $(this).removeClass('disabled'); }
                        });
                    
                    $(".validator.required").each(function(){
                        var validator = this;
                        this.addValidator(function(){
                            var that = $(validator.that);
                            if(that.hasClass('watermarkOn')) return false;
                            if(that.is("[type='checkbox']")) return that.is(":checked");
                            if(that.is("[type='radio']")) return that.is(":checked");
                            return (that.val()); 
                            });  
                        
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        $(this.that).hover(validator.refresh);                        
                        $(this.that).click(validator.refresh);
                        });
                    
                    $(".validator.radio").each(function(){
                        var validator = this;
                        var name = $(this).attr("radio");
                        this.addValidator(function(){ return ($("input:[name='"+name+"']:checked").val());  });  
                        
                        $("input:[name='"+name+"']").click(validator.refresh);
                        $("input:[name='"+name+"']").hover(validator.refresh);
                        });
                    
                    $(".validator.alpha").addClass("filter").each(function(){
                        $(this).attr("filter","/[^a-z]/i");
                        });
                    
                    $(".validator.digit").addClass("filter").each(function(){
                        $(this).attr("filter","/\\D/");
                        });

                   $(".validator.adanbr").addClass("filter").each(function(){
                       $(this).attr("filter","/[^TtPp0-9]\\D/");
                       }); 
                        
                    $(".validator.dollar").addClass("filter").each(function(){
                        $(this).attr("filter","/[^$+-\\.0-9]/");
                        });

                    $(".validator.float").addClass("filter").each(function(){
                        $(this).attr("filter","/[^+-\\.\\,0-9]/");
                        });
                    
                    $(".validator.filter").each(function(){
                        var validator = this;
                        
                        this.addValidator(function(){
                            var txt = $(validator.that).val();
                            if (!txt || txt.length == 0)  return true; //no text is valid unless "required"
                            var regx = eval($(validator).attr("filter"));
                            var bad = txt.match(regx);
                            if (!bad)  return true;
                            while(bad){
                                txt = txt.replace(bad,"");
                                $(validator.that).val(txt);  //delete bad characters
                                bad = txt.match(regx);
                                }
                            return false;
                            });            
                        
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        });
                        
                        
                    $(".validator.toFixed").each(function(){
                        var validator = this;
                        
                        function func(){
                            var txt = $(validator.that).val();
                            if (!txt || txt.length == 0)  return true; //no text is valid unless "required"
                            var old = txt;
                            txt = txt.replace(/,/g,"");
                            var num = parseFloat(txt);
                            var f = parseInt($(validator).attr("toFixed"));
                            if(num && f)try{
                                txt = num.toFixed(f);
                                if (old.indexOf(',') > 0) txt = addCommas(txt); 
                                $(validator.that).val(txt);
                                return true;
                                }catch(e){}
                            return false;
                            };       
                        
                        $(this.that).blur(func);    
                        });                        


                    $(".validator.float").addClass("match").each(function(){
                        $(this).attr("match","/^[+\\-]?(((([1-9][\\d\\,]*\\.)|(0\\.))\\d+)|([1-9][\\d\\,]+))$/"); 
                        });
                        
                    $(".validator.dollar").addClass("match").each(function(){
                        $(this).attr("match","/^[+\\-]?\$?(((([1-9][\\d\\,]*\\.)|(0\\.))\\d{2})|([1-9][\\d\\,]+))$/"); 
                        });

                    $(".validator.email").addClass("match").each(function(){
                        $(this).attr("match","/[\\w\\+\\-\\._]+@[\\w\\-\\._]+\\.\\w{2,}/");
                        });
                        
                    $(".validator.adanbr").addClass("match").each(function(){
                      $(this).attr("match","/^[TPtp0123456789]\\d{8}/"); 
                      });

                    $(".validator.match").each(function(){  //should not change content
                        var validator = this;
                        
                        this.addValidator(function(){
                            var txt = $(validator.that).val();
                            if (!txt || txt.length == 0) return true; //no text is valid unless "required"
                            var regx = eval($(validator).attr("match"));
                            return txt.match(regx);
                            });            
                        
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        });
                        
                    $(".validator.mod").each(function(){
                        var validator = this;
                        var mod = $(this).attr('mod');

                        this.addValidator(function(){ 
                            var txt = $(validator.that).val();
                            if (!txt || txt.length == 0)  return true; //no text is valid unless "required"
                            return ($(validator.that).val() % mod == 0);  
                            });
                         
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        });                        
                    
                    $(".validator.minLength").each(function(){
                        var validator = this;
                        var min = $(this).attr('minLength');

                        this.addValidator(function(){ 
                            var txt = $(validator.that).val();
                            if (!txt || txt.length == 0)  return true; //no text is valid unless "required"
                            return ($(validator.that).val().length >= min);  
                            });
                         
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        });
                        
                    $(".validator.date").each(function(){
                        var validator = this;

                        this.addValidator(function(){ 
                            var txt = $(validator.that).val();
                            if (!txt || txt.length == 0)  return true; //no text is valid unless "required"
                            return  !/Invalid|NaN/.test(new Date(txt)); 
                            });
                         
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        });    
                        
                    $(".validator.min").each(function(){
                        var validator = this;
                        var min = $(this).attr('min');

                        this.addValidator(function(){ 
                            var txt = $(validator.that).val();
                            if (!txt || txt.length == 0)  return true; //no text is valid unless "required"
                            if (!/Invalid|NaN/.test(new Date(min))) return (new Date(txt) >= new Date(min));
                            if (!/Invalid|NaN/.test(parseFloat(min))) return (parseFloat(txt) >= parseFloat(min));
                            if (!/Invalid|NaN/.test(parseInt(min))) return (parseInt(txt) >= parseInt(min));
                            return  (txt >= min);  
                            });
                         
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        });
                        
                    $(".validator.max").each(function(){
                        var validator = this;
                        var max = $(this).attr('max');

                        this.addValidator(function(){ 
                            var txt = $(validator.that).val();
                            if (!txt || txt.length == 0)  return true; //no text is valid unless "required"
                            if (!/Invalid|NaN/.test(new Date(max))) return (new Date(txt) <= new Date(max));
                            if (!/Invalid|NaN/.test(parseFloat(max))) return (parseFloat(txt) <= parseFloat(max));
                            if (!/Invalid|NaN/.test(parseInt(max))) return (parseInt(txt) <= parseInt(max));
                            return  (txt <= max);  
                            });
                         
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        });
                        
                    $(".validator.equalTo").each(function(){
                        var validator = this;
                        var eq = $(this).attr('equalTo');

                        this.addValidator(function(){ 
                            if ($(validator.that).val().length == 0) return true;
                            if ($(validator.that).hasClass("watermarkOn")) return true;
                            return $(eq).val() == $(validator.that).val();
                            });
                         
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        $(eq).blur(validator.refresh);
                        });
                        
                        
                    $(".validator.script").each(function(){
                        var validator = this;
                        var scr = $(this).attr('script');

                        this.addValidator(function(){ 
                            eval(scr);  //script should return false to be a useful validator
                            return true;  //default
                            });
                         
                        $(this.that).keyup(validator.refresh);
                        $(this.that).blur(validator.refresh);
                        });

                                                
                },
                
            submit : function(select){
                    $(select).submit(function(){
                        var allValid = true;
                        $(".validator").each(function(){  allValid = this.isValid() && allValid;      });
                        $(".validator:visible:first").each(function(){this.focus()});
                        return allValid;  //false will interrupt submit behaviour
                        });
                    }                    
			}