// LiveValidation 1.2 (standalone version)
// Copyright (c) 2007 Alec Hill (www.livevalidation.com)
// LiveValidation is licensed under the terms of the MIT License

//config

var dataCorrect = 'Data Correcta';
var dataRequired= 'Data Requerida';
var dataNoMatch = 'Passwords no son iguales';
var dataEmailInvalid='No es  un Email valido';



var LiveValidation = function(element, optionsObj){
  	this.initialize(element, 'message', optionsObj);
}
/** element types constants ****/
LiveValidation.TEXTAREA 		= 1;
LiveValidation.TEXT 		    = 2;
LiveValidation.PASSWORD 		= 3;
LiveValidation.CHECKBOX 		= 4;
LiveValidation.SELECT			= 5;
/****** Static methods *******/
LiveValidation.massValidate = function(validations){
  var returnValue = true;
	for(var i = 0, len = validations.length; i < len; ++i ){
		var valid = validations[i].validate();
		if(returnValue) returnValue = valid;
	}

	return returnValue;
}
/****** prototype ******/
LiveValidation.prototype = {
    validClass: 'LV_valid',
    invalidClass: 'LV_invalid',
    messageClass: 'LV_validation_message',
    validFieldClass: 'LV_valid_field',
    invalidFieldClass: 'LV_invalid_field',
	focusFieldClass: 'LV_focus_field', // add by JIM

    initialize: function(element, target, optionsObj){
      var self = this;
      if(!element) throw new Error("LiveValidation::initialize - No element reference or element id has been provided!");
    	this.element = element.nodeName ? element : document.getElementById(element);
		this.target = target.nodeName ? target : document.getElementById(target);
    	if(!this.element) throw new Error("LiveValidation::initialize - No element with reference or id of '" + element + "' exists!");
    	this.validations = [];

		this.elementType = this.getElementType();
		this.form = this.element.form;

    	var options = optionsObj || {};
    	this.validMessage = options.validMessage || dataCorrect;
    	this.insertAfterWhatNode = options.insertAfterWhatNode || this.target;

		this.onValid = options.onValid || function(){ 
			//this.insertMessage(this.createMessageSpan());
			this.insertMessage();
			this.addFieldClass(); 
		};
		this.onInvalid = options.onInvalid || function(){ 
			//this.insertMessage(this.createMessageSpan());
			this.insertMessage();
			this.addFieldClass(); 
		};
    	this.onlyOnBlur =  options.onlyOnBlur || false;
    	this.wait = options.wait || 0;
      	this.onlyOnSubmit = options.onlyOnSubmit || false;
	  
      if(this.form){
        this.formObj = LiveValidationForm.getInstance(this.form);
        this.formObj.addField(this);
	  }

      this.element.onfocus = function(e){ self.doOnFocus(); }
      
	  if(!this.onlyOnSubmit){
        switch(this.elementType){
          case LiveValidation.CHECKBOX:
            this.element.onclick = function(e){ self.validate(); }
			// let it run into the next to add a change event too
          case LiveValidation.SELECT:
            this.element.onchange = function(e){ self.validate(); }
            break;
          default:
            if(!this.onlyOnBlur) this.element.onkeyup = function(e){ self.deferValidation(); }
      	    this.element.onblur = function(e){ 
				self.doOnBlur();
			}
        }
      }
	  
    },
    
    add: function(validationFunction, validationParamsObj){
      this.validations.push( {type: validationFunction, params: validationParamsObj || {} } );
      return this;
    },
    
    deferValidation: function(e){
      if(this.wait >= 300) this.removeMessageAndFieldClass();
    	var self = this;
      if(this.timeout) clearTimeout(self.timeout);
      this.timeout = setTimeout( function(){ self.validate() }, self.wait); 
    },
        
    doOnBlur: function(e){
      this.focused = false;
      this.validate(e);
    },
        
    doOnFocus: function(e){
      this.focused = true;
      this.removeMessageAndFieldClass();
   	  if (this.element.className.indexOf(this.focusFieldClass) == -1) this.element.className += ' ' + this.focusFieldClass; // add by JIM
    },
    
    getElementType: function(){
      switch(true){
        case (this.element.nodeName == 'TEXTAREA'):
          return LiveValidation.TEXTAREA;
        case (this.element.nodeName == 'INPUT' && this.element.type == 'text'):
        	return LiveValidation.TEXT;
        case (this.element.nodeName == 'INPUT' && this.element.type == 'password'):
        	return LiveValidation.PASSWORD;
        case (this.element.nodeName == 'INPUT' && this.element.type == 'checkbox'):
        	return LiveValidation.CHECKBOX;
        case (this.element.nodeName == 'SELECT'):
          return LiveValidation.SELECT;
        case (this.element.nodeName == 'INPUT'):
        	throw new Error('LiveValidation::getElementType - Cannot use LiveValidation on an ' + this.element.type + ' input!');
        default:
        	throw new Error('LiveValidation::getElementType - Element must be an input, select, or textarea!');
      }
    },
    
    doValidations: function(){
      	this.validationFailed = false;
      	for(var i = 0, len = this.validations.length; i < len; ++i){
    	 	var validation = this.validations[i];
    		switch(validation.type){
    		   	case Validate.Presence:
                case Validate.Confirmation:
                case Validate.Acceptance:
    		   		this.displayMessageWhenEmpty = true;
    		   		this.validationFailed = !this.validateElement(validation.type, validation.params); 
    				break;
    		   	default:
    		   		this.validationFailed = !this.validateElement(validation.type, validation.params);
    		   		break;
    		}
    		if(this.validationFailed) return false;	
    	}
    	this.message = this.validMessage;
    	return true;
    },
    
    validateElement: function(validationFunction, validationParamsObj){
      	var value = (this.elementType == LiveValidation.SELECT) ? this.element.options[this.element.selectedIndex].value : this.element.value;     
        if(validationFunction == Validate.Acceptance){
    	    if(this.elementType != LiveValidation.CHECKBOX) throw new Error('LiveValidation::validateElement - Element to validate acceptance must be a checkbox!');
    		value = this.element.checked;
    	}
        var isValid = true;
      	try{    
    		validationFunction(value, validationParamsObj);
    	} catch(error) {
    	  	if(error instanceof Validate.Error){
    			if( value !== '' || (value === '' && this.displayMessageWhenEmpty) ){
    				this.validationFailed = true;
    				this.message = error.message;
    				isValid = false;
    			}
    		}else{
    		  	throw error;
    		}
    	}finally{
    	    return isValid;
        }
    },
    
    validate: function(){
      var isValid = this.doValidations();
    	if(isValid){
    		this.onValid();
    		return true;
    	}else{
    	  	this.onInvalid();
    	  	return false;
    	}
    },
    
    createMessageSpan: function(){
        var span = document.createElement('span');
    	var textNode = document.createTextNode(this.message);
      	span.appendChild(textNode);
        return span;
    },
/*
    insertMessage: function(elementToInsert){
      	this.removeMessage();
      	if( (this.displayMessageWhenEmpty && (this.elementType == LiveValidation.CHECKBOX || this.element.value == ''))
    	  || this.element.value != '' ){
            var className = this.validationFailed ? this.invalidClass : this.validClass;
    	  	elementToInsert.className += ' ' + this.messageClass + ' ' + className;
	        if(this.insertAfterWhatNode.nextSibling){
    		  		this.insertAfterWhatNode.parentNode.insertBefore(elementToInsert, this.insertAfterWhatNode.nextSibling);
    		}else{
    			    this.insertAfterWhatNode.parentNode.appendChild(elementToInsert);
    	    }
    	}
    },
*/
    insertMessage: function(){
      	//this.removeMessage();
		/*
      	if( (this.displayMessageWhenEmpty && (this.elementType == LiveValidation.CHECKBOX || this.element.value == ''))
    	  || this.element.value != '' ){
		*/
            //var className = this.validationFailed ? this.invalidClass : this.validClass;
    	  	//elementToInsert.className += ' ' + this.messageClass + ' ' + className;
			//getToggleIsOpen();
			//$("LV_MSG").set("html", this.message);
			//getToggleMessageOpen();
/*
            if(this.insertAfterWhatNode.nextSibling){
    		  		this.insertAfterWhatNode.parentNode.insertBefore(elementToInsert, this.insertAfterWhatNode.nextSibling);
    		}else{
    			    this.insertAfterWhatNode.parentNode.appendChild(elementToInsert);
    	    }
*/
    	//}
    },
     
    addFieldClass: function(){
        this.removeFieldClass();
        if(!this.validationFailed){
            if(this.displayMessageWhenEmpty || this.element.value != ''){
				if(this.focused) { // add by JIM
	                if(this.element.className.indexOf(this.validFieldClass) == -1) this.element.className += ' ' + this.validFieldClass;
				} // add by JIM
            }
        }else{
            if(this.element.className.indexOf(this.invalidFieldClass) == -1) this.element.className += ' ' + this.invalidFieldClass;
        }
    },
    
    removeMessage: function(){
		/*
    	var nextEl;
    	var el = this.insertAfterWhatNode;
    	while(el.nextSibling){
    	    if(el.nextSibling.nodeType === 1){
    		  	nextEl = el.nextSibling;
    		  	break;
    		}
    		el = el.nextSibling;
    	}
      	if(nextEl && nextEl.className.indexOf(this.messageClass) != -1) this.insertAfterWhatNode.parentNode.removeChild(nextEl);
		*/
    },
    
    removeFieldClass: function(){
      if(this.element.className.indexOf(this.invalidFieldClass) != -1) this.element.className = this.element.className.split(this.invalidFieldClass).join('');
      if(this.element.className.indexOf(this.validFieldClass) != -1) this.element.className = this.element.className.split(this.validFieldClass).join(' ');
	  if(this.element.className.indexOf(this.focusFieldClass) != -1) this.element.className = this.element.className.split(this.focusFieldClass).join(''); // add by JIM
    },
        
    removeMessageAndFieldClass: function(){
      this.removeMessage();
      this.removeFieldClass();
    }

}



/*************************************** LiveValidationForm class ****************************************/
var LiveValidationForm = function(element){
  this.initialize(element);
}

LiveValidationForm.getInstance = function(element){
  if(!element.id) element.id = 'formId_' + new Date().valueOf();
  if(!window['LiveValidationForm_' + element.id]) window['LiveValidationForm_' + element.id] = new LiveValidationForm(element);
  return window['LiveValidationForm_' + element.id];
}

LiveValidationForm.prototype = {
  initialize: function(element){
    this.element = element;
    this.fields = [];
    var self = this;
    this.element.onsubmit = function(){
      return LiveValidation.massValidate(self.fields);
    }
  },
  
  addField: function(newField){
    this.fields.push(newField);
  }
   
}

var Validate = {
    Presence: function(value, paramsObj){
      	var paramsObj = paramsObj || {};
    	var message = paramsObj.failureMessage || dataRequired;
    	if(value === '' || value === null || value === undefined){ 
    	  	Validate.fail(message);
    	}
    	return true;
    },
    
    Numericality: function(value, paramsObj){
        var suppliedValue = value;
        var value = Number(value);
    	var paramsObj = paramsObj || {};
        var minimum = ((paramsObj.minimum) || (paramsObj.minimum == 0)) ? paramsObj.minimum : null;;
        var maximum = ((paramsObj.maximum) || (paramsObj.maximum == 0)) ? paramsObj.maximum : null;
    	var is = ((paramsObj.is) || (paramsObj.is == 0)) ? paramsObj.is : null;
        var notANumberMessage = paramsObj.notANumberMessage || "Debe ser un n&uacute;mero!";
        var notAnIntegerMessage = paramsObj.notAnIntegerMessage || "Debe ser un entero!";
    	var wrongNumberMessage = paramsObj.wrongNumberMessage || "Deb ser " + is + "!";
    	var tooLowMessage = paramsObj.tooLowMessage || "No puede ser menor a " + minimum + "!";
    	var tooHighMessage = paramsObj.tooHighMessage || "No puede ser mayor a " + maximum + "!";
        if (!isFinite(value)) Validate.fail(notANumberMessage);
        if (paramsObj.onlyInteger && (/\.0+$|\.$/.test(String(suppliedValue))  || value != parseInt(value)) ) Validate.fail(notAnIntegerMessage);
    	switch(true){
    	  	case (is !== null):
    	  		if( value != Number(is) ) Validate.fail(wrongNumberMessage);
    			break;
    	  	case (minimum !== null && maximum !== null):
    	  		Validate.Numericality(value, {tooLowMessage: tooLowMessage, minimum: minimum});
    	  		Validate.Numericality(value, {tooHighMessage: tooHighMessage, maximum: maximum});
    	  		break;
    	  	case (minimum !== null):
    	  		if( value < Number(minimum) ) Validate.fail(tooLowMessage);
    			break;
    	  	case (maximum !== null):
    	  		if( value > Number(maximum) ) Validate.fail(tooHighMessage);
    			break;
    	}
    	return true;
    },
    
    Format: function(value, paramsObj){
      	var value = String(value);
    	var paramsObj = paramsObj || {};
    	var message = paramsObj.failureMessage || "Invalido!";
      	var pattern = paramsObj.pattern || /./;
    	if(!pattern.test(value) /* && value != ''*/ ){ 
    	  	Validate.fail(message);
    	}
    	return true;
    },
    
    Email: function(value, paramsObj){
    	var paramsObj = paramsObj || {};
    	var message = paramsObj.failureMessage || dataEmailInvalid;
    	Validate.Format(value, { failureMessage: message, pattern: /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i } );
    	return true;
    },
    
    Length: function(value, paramsObj){
    	var value = String(value);
    	var paramsObj = paramsObj || {};
        var minimum = ((paramsObj.minimum) || (paramsObj.minimum == 0)) ? paramsObj.minimum : null;
    	var maximum = ((paramsObj.maximum) || (paramsObj.maximum == 0)) ? paramsObj.maximum : null;
    	var is = ((paramsObj.is) || (paramsObj.is == 0)) ? paramsObj.is : null;
        var wrongLengthMessage = paramsObj.wrongLengthMessage || "Debe tener " + is + " caracteres de longitud!";
    	var tooShortMessage = paramsObj.tooShortMessage || "No debe tener menos de " + minimum + " caracteres!";
    	var tooLongMessage = paramsObj.tooLongMessage || "No debe tener mas de " + maximum + " caracteres!";
    	switch(true){
    	  	case (is !== null):
    	  		if( value.length != Number(is) ) Validate.fail(wrongLengthMessage);
    			break;
    	  	case (minimum !== null && maximum !== null):
    	  		Validate.Length(value, {tooShortMessage: tooShortMessage, minimum: minimum});
    	  		Validate.Length(value, {tooLongMessage: tooLongMessage, maximum: maximum});
    	  		break;
    	  	case (minimum !== null):
    	  		if( value.length < Number(minimum) ) Validate.fail(tooShortMessage);
    			break;
    	  	case (maximum !== null):
    	  		if( value.length > Number(maximum) ) Validate.fail(tooLongMessage);
    			break;
    		default:
    			throw new Error("Validate::Length - Length(s) to validate against must be provided!");
    	}
    	return true;
    },
    
    Inclusion: function(value, paramsObj){
    	var paramsObj = paramsObj || {};
    	var message = paramsObj.failureMessage || "Debe estar incluido en la lista!";
    	if(paramsObj.allowNull && value == null) return true;
        if(!paramsObj.allowNull && value == null) Validate.fail(message)
    	var list = paramsObj.within || [];
    	var found = false;
    	for(var i = 0, length = list.length; i < length; ++i){
    	  	if(list[i] == value) found = true;
            if(paramsObj.partialMatch){ 
                if(value.indexOf(list[i]) != -1) found = true;
            }
    	}
    	if( (!paramsObj.exclusion && !found) || (paramsObj.exclusion && found) ) Validate.fail(message);
    	return true;
    },
    
    Exclusion: function(value, paramsObj){
        var paramsObj = paramsObj || {};
    	paramsObj.failureMessage = paramsObj.failureMessage || "No debe estar incluido en la lista!";
        paramsObj.exclusion = true;
    	Validate.Inclusion(value, paramsObj);
        return true;
    },
    
    Confirmation: function(value, paramsObj){
      	if(!paramsObj.match) throw new Error("Validate::Confirmation - Error validating confirmation: Id of element to match must be provided!");
    	var paramsObj = paramsObj || {};
    	var message = paramsObj.failureMessage || dataNoMatch;
    	var match = paramsObj.match.nodeName ? paramsObj.match : document.getElementById(paramsObj.match);
    	if(!match) throw new Error("Validate::Confirmation - There is no reference with name of, or element with id of '" + paramsObj.match + "'!");
    	if(value != match.value){ 
    	  	Validate.fail(message);
    	}
    	return true;
    },
    
    Acceptance: function(value, paramsObj){
      	var paramsObj = paramsObj || {};
    	var message = paramsObj.failureMessage || "Must be accepted!";
    	if(!value){ 
    	  	Validate.fail(message);
    	}
    	return true;
    },
    
    now: function(validationFunction, value, validationParamsObj){
      	if(!validationFunction) throw new Error("Validate::now - Validation function must be provided!");
    	var isValid = true;
        try{    
    		validationFunction(value, validationParamsObj || {});
    	} catch(error) {
    		if(error instanceof Validate.Error){
    			isValid =  false;
    		}else{
    		 	throw error;
    		}
    	}finally{ 
            return isValid 
        }
    },
    
    fail: function(errorMessage){
            throw new Validate.Error(errorMessage);
    },
    
    Error: function(errorMessage){
    	this.message = errorMessage;
    	this.name = 'ValidationError';
		//alert ( errorMessage );
    }

}
