if(null==document.getElementsByClass) {
	document.getElementsByClass = function(searchClass,node,tag) {
	       var classElements = new Array();
	       if ( node == null )
	               node = document;
	       if ( tag == null )
	               tag = '*';
	       var els = node.getElementsByTagName(tag);
	       var elsLen = els.length;
	       var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
	       for (i = 0, j = 0; i < elsLen; i++) {
	               if ( pattern.test(els[i].className) ) {
	                       classElements[j] = els[i];
	                       j++;
	               }
	       }
	       return classElements;
	  }
}

/**
 * Manejador de formularios y validaci?n.
 * @class FormManager
 */
var FormManager = Class.create({
  
  /* Propiedades **************************************************************/
  
  /**
   * Identificador del elemento DOM de formulario.
   * @var string id
   */
  id: null,
  
  /**
   * Elemento DOM de formulario.
   * @var Element formElement
   */
  formElement: null,
  
  /**
   * Elementos del formulario que manejar? FormManager.
   * @var array elements
   */
  elements: null,

  /**
   * Valores por defecto en el formulario.
   * @var array defaults
   */
  defaults: {},
  
  /* Ejecutiva ****************************************************************/
  
  /**
   * Inicializa el formulario cuyo identificador se enterga.
   * @param string elementId - Identificador de formulario.
   * @return void
   */
  initialize: function(elementId) {
   
    // Inicialización.
    this.id = elementId;
    this.formElement = $(elementId);
    this.elements = document.getElementsByClassName('regexp', this.formElement);
    if(this.formElement.className && this.formElement.className.indexOf('appendable') >= 0)
      this.defaults = this.getDefaults();

    // Actualiza los elementos del formulario.
    for(var i = 0; i < this.elements.length; i++) {
      var element = this.elements[i];
      
      try {
        var attribute  = element.getAttribute('constraint');
        var constraint = attribute.replace('?',  '');
        var optional   = attribute.indexOf('?') > -1;
        // Recupera la constraint.
        for(var j = 0; j < FormManager.regidz.length; j++) {
          if(constraint == FormManager.regidz[j]) {
            element._regfn  = FormManager.regfn[j];
            element._regexp = '^' + (optional? '(' : '') 
              + FormManager.regexp[j]
              + (optional? ')?' : '')  + '$';
            element._regerr = j;
            element._optional = optional;
            break;
          }
        }
      } catch(e) {
      }
    }

    // Actualiza el formulario.
    this.formElement._manager = this;
    this.formElement.onsubmit = function() {
      return this._manager.validate();
    };
  },
  
  stripHTML: function(oldString) {
    var newString = "";
    var inTag = false;
    for(var i = 0; i < oldString.length; i++) {
      if(oldString.charAt(i) == '<') inTag = true;
      if(oldString.charAt(i) == '>') {
        if(oldString.charAt(i+1)=="<") {
          //dont do anything
        } else {
          inTag = false;
          i++;
        }
      }
      if(!inTag) newString += oldString.charAt(i);
    }
   
   return newString;
  },
  
  /**
   * Valida el contenido del formulario.
   * @return boolean - Verdadero si el formulario valid? correctamente, falso
   *   en caso contrario.
   */
  validate: function() {
    this.clearErrors();
    var isValid = true;
    for(var i = 0; i < this.elements.length; i++) {
      var val = null, elem = this.elements[i];
      if(elem.nodeName == 'TEXTAREA') {
        if(elem.className.indexOf('mce-editor') == -1) {
          val = this.stripHTML(elem.innerHTML);
        } else {
          var ifr = document.getElementById(elem.name + '_ifr');            
          val = this.stripHTML(ifr.contentWindow.document.body.innerHTML).replace(/\n/g,'');

          if(val === '&nbsp;'){
          	val = '';
          }          
        }
      } else { 
        val = elem.value;
      }
      var thisIsValid = true;
      if(!elem._optional || (elem._optional && val)) {
        if(elem._regexp) thisIsValid &= (val.match(elem._regexp) !== null);
        if(elem._regfn ) thisIsValid &= elem._regfn(val);
      }
     if(!thisIsValid) this.renderError(elem);
      isValid &= thisIsValid;
        
    }
    return isValid? true : false;    
  },
  
  /**
   * Elimina todos los mensajes de error en el formulario.
   * @return void
   */
  clearErrors: function() {
    var elements = document.getElementsByClass('error', this.formElement );
    //alert(elements.length);
    for(var i = 0; i < elements.length; i++) {
      elements[i].parentNode.removeChild(elements[i]);
      //Miramos si existe otros elementos con una clase error
      var restelem = document.getElementsByClass('error', this.formElement );
      //alert('rest' + restElem.length);
      if(restelem.length>0){
        this.clearErrors();
      }                 
    }
  },
  
  /**
   * Dibuja el mensaje de error adecuado para el elemento dado.
   * @param Element element - Elemento DOM cuyo error se mostrar?.
   * @return void
   */
  renderError: function(element) {
    var error = document.createElement('div');
    error.className = 'error';
    error.innerHTML = FormManager.regerr[element._regerr];
    if(element.nodeName == 'TEXTAREA'){
     	var span = document.getElementById(element.name + '_container'); 
      element.parentNode.insertBefore(error, span.nextSibling);      	
    } else {
      element.parentNode.insertBefore(error, element.nextSibling);      	
    }

     
  },
  
  getDefaults: function() {
    var ez = this.formElement.elements;
    var defaults = {};
    for(var i = 0; i < ez.length; i++) {
      var element = ez[i], value = null;
      if(!element.className || element.className.indexOf('keep-value') < 0) {
        if(element.nodeName == 'INPUT') {
          if(element.type) {
            if(element.type == 'checkbox') value = element.checked;
              else value = element.value;
          }
        } else if(element.nodeName == 'TEXTAREA') value = element.innerHTML;
        defaults[element.name] = value;
      }
    }
    alert(value);
    return defaults;
  },

  append: function() {
    var ez = document.getElementsByClass('appendable', this.formElement, 'DIV');
    if(ez.length) {
      element = ez[0];
      if(element.style.display) this.reset();
      element.style.display = 'block';
    } else this.reset();
    var ez = document.getElementsByClass('append', this.formElement, 'BUTTON'), element = null;
    if(ez.length) {
      element = ez[0];
      element.innerHTML = element.innerHTML.replace('Crear', 'Limpiar');
      element.childNodes[0].src = '/img/clear.gif';
    }
  },
  
  reset: function() {
    var ez = his.formElement.elements;
    for(var i = 0; i < ez.length; i++) {
      var element = ez[i];
      try {
        if(element.nodeName == 'INPUT') {
          if(element.type == 'checkbox') element.checked = this.defaults[element.name];
            else element.value = this.defaults[element.name];
        } else if(element.nodeName == 'TEXTAREA') element.innerHTML = this.defaults[element.name];
      } catch(e) { alert(e); }
    }
  }
});

/**
 * Lista de expresiones regulares para el validador.
 * @var array FormManager.regexp
 */
FormManager.regexp = [
  '\\d\\d\\-\\d\\d\\-\\d\\d\\d\\d',
  '.+',
  '\\w',
  '[0-9]+',
  '[+-]?[0-9]+',
  '[0-9]+((\\.)?[0-9]+)?',
  '\\d+((\\,\\.)?\\d+)?\\d+)?',
  '[+-]?\\d+([,.]\\d+)?',
  '[+-]?[1]?[0-9]{1,2}(\\.[0-9]+)?',
  '.+',
  '.+',
  '.+',
  '.+',
  '.+',
  '(ftp|http|https):\\/\\/(\\w+:{0,1}\\w*@)?(\\S+)(:[0-9]+)?(\\/|\\/([\\w#!:.?+=&%@!\\-\\/]))?',
  '[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}',
  '[a-zA-Z0-9_.-]{6,12}'
];

FormManager.regfn  = [
  null, // date
  null, // text
  null, // char
  null, // absint
  null, // int
  null, // absfloat
  null, // float
  null, // abspercent
  null, // percent
  null, // path
  null, // filename
  function valid(val) { /* credential */
    if(val) val = val.toString().toUpperCase();
    if(new RegExp(/^[0-9]{8}$/).exec(val)) { // DNI
      return true;
    } else if(new RegExp(/^[0-9]{8}[A-Z]$/i).exec(val)) { // NIF
      var nl = 'TRWAGMYFPDXBNJZSQVHLCKE';
      var id = parseInt(val.substring(0, 8)) % 23;
      return nl.substring(id, id + 1) == val.substring(8, 9);
    } else if(new RegExp(/^[ABCDEFGHKLMNPQS]\d\d\d\d\d\d\d[0-9,A-J]$/g).exec(val)) { // CIF
      var even = 0, odd = 0, sum, last, num, chr = new Array("J", "A", "B", "C", "D", "E", "F", "G", "H", "I"), ctl;
      var retval = true;
      var exp = new RegExp(/^[ABCDEFGHKLMNPQS]\d\d\d\d\d\d\d[0-9,A-J]$/g);
      if(exp.exec(val)) {
        last = val.substr(8,1);
          ctl = (2 * parseInt(val.substr(cont++, 1))).toString()  + "0";
        for(var cont = 1; cont < 7; cont++){
          odd += parseInt(ctl.substr(0, 1)) + parseInt(ctl.substr(1, 1));
          even+= parseInt(val.substr(cont, 1));
        }
        ctl = (2 * parseInt(val.substr(cont, 1))).toString() + "0";
        odd += parseInt(ctl.substr(0, 1)) + parseInt(ctl.substr(1, 1));
        sum = (even + odd).toString();
        num = (10 - parseInt(sum.substr(sum.length - 1, 1))).toString();
        if(num == 10) num = 0;
        retval = (last == num) || (last == chr[num]); 
      }
      return retval;
    } else {
      return false;
    }
  },
  null, // zipcode
  null, // phone
  null, // url
  null, // email
  null // password
];

/**
 * Lista de identificadores para las expresiones regulares del validador.
 * @var array FormManager.regidz
 */
FormManager.regidz = [
  'date',
  'text',
  'char',
  'absint',
  'int',
  'absfloat',
  'float',
  'abspercent',
  'percent',
  'path',
  'filename',
  'credential',
  'zipcode',
  'phone',
  'url',
  'email',
  'password'
];

/**
 * Lista de mensajes de error para las expresiones regulares del validador.
 * @var array FormManager.regerr
 */
FormManager.regerr = [
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Fecha inv&aacute;lida.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Campo obligatorio.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Car&aacute;cter inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Valor inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Valor inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Valor inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Valor inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Porcentaje inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Porcentaje inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Ruta inv&aacute;lida.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Archivo inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">DNI, NIF o CIF inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">C&oacute;digo postal inv&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">N&uacute;mero de tel&eacute;fono no v&aacute;lido.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Direcci&oacute;n URL inv&aacute;lida.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Direcci&oacute;n de correo electr&oacute;nico inv&aacute;lida.</span>',
  '<img src="/img/exclamation.gif" alt="Error" title="Error" />&nbsp;<span class="error">Contrase&ntilde;a inv&aacute;lida.</span>'
];