/**
 * Class for dinamic form validate
 *
 * @author 	Preceptor educação a distância <contato@preceptoread.com.br>
 * @version 2.0
 * @license	free for all
 */

/**
 * @constructor
 */
Validator = function( form ){
	
	this.validates 	   = [];
    this.errorMessages = [];
	this.form 		   = document.getElementById( form ) || document.forms[0];

	Validator.Event.on( this.form , "submit" , this.verify , this );
}

Validator.prototype = {
	
	/**
	 * Add validate to form
	 * 
	 * @param string 	id
	 * @param function 	fn  
	 * @param array 	data
	 * @param mixed		param
	 */
	add: function( id , fn , message , param )
	{
		if( !( id && fn ) ){
			alert('Wrong object arguments. Missing: id '+ id +'or func'+ fn +'\n\n');
			return false;
		}
		
		if( typeof param != 'object' && typeof param != 'undefined' ){
			param 	  = Array.prototype.slice.call(arguments, 3);
		}
		
		var values = {};
		values.id = id;
		values.fn = fn;
        values.message = message;
        values.param = param;

		if( !values.param ){
			values.param = null;
		}
			
        if( fn.mask ){
            fn.mask( id );
        }
		
        if( fn == Validate.notEmpty ){
        	this.markupNotEmpty(id);
        }
        
        if( fn == Validate.stringLength ){
        	document.getElementById( id ).maxLength = param[param.length-1];
        }
        
		this.validates.push( values );
	},
	
    markupNotEmpty: function( value )
    {
        var labels = this.form.getElementsByTagName("label"),label;
         
        for ( k = 0; k < labels.length; k++ ){
            label = labels[k];
            if ( label.getAttribute('for') == value || label.getAttribute('htmlFor') == value ){
                label.innerHTML = "<span class='notEmpty'>*</span> " + label.innerHTML;
            }
        }
    },
    
	/**
	 * Remove validate to form
	 * 
	 * @param string 	field
	 * @param function 	fn
	 */
	remove: function( id , fn )
	{
		if( this.validates.length ){
			for(var i = this.validates.length-1; i > -1; i--){
				if(this.validates[i].id == id && this.validates[i].fn == fn){
					this.validates.splice( i , 1 );
				}
			}
		}
	},
	
	/**
	 * Verify all validates
	 */
	verify: function( ev )
	{
		Validator.Event.stopEvent( ev );
		
        this.preVerify();
        this.clearMessages();
        
        var i = 0,
            valid = true;
        
        for( i = 0; i < this.validates.length; i++ ){
            
        	if( this.inForm( this.validates[i].id ) ){
                var args = [],
                    el   = document.getElementById( this.validates[i].id );
                
                args[0] = el.value;
                args 	= args.concat( this.validates[i].param );
                args	= this._valueByIdOrName( args );
                
                if( !this.validates[i].fn.apply( { element: el , validator: this }, args ) ){
                	valid = false;
                	this.addError( i );
                }
            }
		}
        
        if( valid ){	
        	this.success();
        }
    },

    inForm: function( id )
  	{
	  	var n = this.form.elements.length;
	  	
	  	for ( var i = 0 ; i < n ; i++ ){
			if( this.form.elements[i].id == id ){
				return true;
			}
		}
		return false;
  	},

  	_valueByIdOrName: function( param )
  	{
  		for( var i = 1; i < param.length; i++ ){
  			
	  		var el = document.getElementById( param[i] );
	
	  		if( el ){
	  			param[i] = el.value;
	  		}else{
	  			
	  			var els = document.getElementsByName( param[i] );
	
	  			if( els.length ){
	  				param[i] = els[0].value;
	  			}
	  		}
  		}

  		return param;
  	},
  	
    addError: function( index )
    {
  		var span 	   = document.createElement( 'SPAN' );
  		span.className = 'validate-error';
  		span.innerHTML = this.validates[index].message;
  		
  		var el 	= document.getElementById( this.validates[index].id );
  		
  		el.parentNode.insertBefore( span , el.nextSibling );
    },
	
    clearMessages: function( childs )
    {
    	childs = childs || this.form.childNodes;
  		
  		for( var i = 0; i < childs.length; i++ ){
  			
  			var childsChilds = childs[i].childNodes;
  			
  			if( childsChilds.length ){
  				this.clearMessages( childsChilds );
  			}
  			
  			if( childs[i].className == 'validate-error' ){
  				try{
  					childs[i].parentNode.removeChild( childs[i] );
  				}catch( e ){}
  			}
  		}
    },
	/**
	 * Clear all validates
	 */
	clear: function()
	{
		this.validates = [];
        this.errorMessages = [];
	},
	
	/**
	 * overwrite
	 */
	success: function()
	{
		this.form.submit();
	},

    preVerify: function()
    {
		//overwrite
	}
}

Validate = {};

Validate.notEmpty = function( value, element )
{
  	if( !value.replace( /^\s*|\s*$/g , "" ) ){
		return false;
	}
	
	return true;
}

Validate.ckeckbox = function( value, name, limit )
{
	var els   = document.getElementsByName( name );
	var count = 0;
	limit     = limit || 1;
	
	for( var i = 0; i < els.length; i++ ){
		
		if( els[i].checked ){
			count++;
		}
		
		if( count == limit ){
			return true;
		}
	}
	
	return false;
}

Validate.radio = function( value, name )
{
	var els = document.getElementsByName( name );
	
	for( var i = 0; i < els.length; i++ ){
		
		if( els[i].checked ){
			return true;
		}
	}
	
	return false;
}


Validator.Event = {};
Validator.Event.listener = {};

Validator.Event.on = function( element , name , fn , subcribe )
{

    if( subcribe ){
        Validator.Event.listener[element.id] = fn;
        fn = function(e){
            return Validator.Event.listener[element.id].call( subcribe ,  e || window.event );
        }
    }

    if (element.addEventListener) {
        element.addEventListener( name, fn, false );
    } else if (element.attachEvent) {
        element.attachEvent( 'on' + name , fn );
    }
}

Validator.Event.stopEvent = function( event )
{
    if (event.preventDefault) {
        event.preventDefault();
        event.stopPropagation();
    } else {
        event.returnValue = false;
        event.cancelBubble = true;
    }
}

Validator.Event.key = function( ev )
{
    return ev.which || ev.keyCode;
}

