/**
 * Constructeur
 *
 * @param {string} fId Identifiant HTML du formulaire à valider
 * @constructor
 * @public
 * @todo : passer en modèle objet AI.obj
 */
function CheckForm(fId)
{
 var F = AI.DOM.getById(fId);

 if ( !F ) { AI.console.stop(CheckForm.l10n('formulaire_introuvable')); }

 this.confirmer = false;
 this.fId = fId;
 this.champs = [];
 
 F._oldonsubmit = F.onsubmit;
 F.instance = this;
 F.onsubmit = CheckForm._onsubmit;
 
 this.onBeforeValidate = function() { return []; };
 this.onAfterValidate = function() { return []; };

 CheckForm.indicateur = AI.DOM.createElement('div', {}, {height:'3px', overflow:'hidden', backgroundColor:'white'});
 CheckForm.indicateur_container = document.body.appendChild( AI.DOM.createElement('div', { id:'indicateur_chars_AIERP', className:'cacher' }, { backgroundColor:'#C0C0C0', position:'absolute' }, [CheckForm.indicateur] ) );
}

function Field(fId, obj)
{
 var
  element, value;
 if ( !obj.name ) { return null; }

 element = AI.DOM.getById(fId).elements[obj.name];
 if ( !element ) { return null; }

 this.fId = fId;
 this.name = obj.name;
 this.required = CheckForm.param('required', obj, false);
 this.label = CheckForm.param('label', obj, obj.name.toLowerCase());
 this.type = element.type;
 this.CarTyp = CheckForm.param('CarTyp', obj, null);
 value = this.getValue();
 this.defaultValue = value;
 this.lastValue = value;
 this.mini = CheckForm.param('mini', obj, null);
 this.maxi = CheckForm.param('maxi', obj, null);
 this.format = CheckForm.param('format', obj, null);
 this.errors = [];
 if ( 'CarCha' == this.CarTyp || 'CarUniCha' == this.CarTyp || 'CarTxt' == this.CarTyp || 'CarUniTxt'  == this.CarTyp )
 {
  element.maxi = this.maxi ? this.maxi : 65534;
  if ( !AI.DOM.CSS.has('Xinha', element) )
  {
   element.$oldfocus = element.onfocus;
   element.$oldblur = element.onblur;
   element.$oldkeypress = element.onkeypress;
   element.onfocus = Field._onfocus;
   element.onblur = Field._onblur;
   element.onkeypress = Field._onkeypress;
  }
 }
  return this;
}

CheckForm.RE_checkEmail = /^[\w\-][\w\-\.]+@[\w\-]+\.[a-zA-Z]{2,6}$/gi;
CheckForm.i18n = {};
CheckForm.l10n = function(cle)
{
 if ( typeof CheckForm.i18n[cle] == 'string' ) { return CheckForm.i18n[cle]; }
 return cle;
};
/**
 * Handler de soumission du formulaire
 * @param {event} e (evt) L'event de soumission
 * @private
 */
CheckForm._onsubmit = function(e)
{
 return CheckForm.__onsubmit.call(this.instance, e);
};

/**
 * Handler interne de soumission du formulaire
 *
 * Le scope d'application est l'instance de l'objet CheckForm
 *
 * @param {object} evt L'event de soumission
 * @private
 */
CheckForm.__onsubmit = function(evt)
{
 var
  i, j, v, reussite,
  msg = CheckForm.l10n('formulaire_non_soumis_suite_a_erreurs') + CR,
  formulaire = AI.DOM.getById(this.fId),
  errors = [],
  firstErrorField = null,
  errorBefore = this.onBeforeValidate(),
  errorAfter = this.onAfterValidate();

 for ( i = 0; i < this.champs.length; i++ )
 {
  v = this.champs[i].valider();
  if ( firstErrorField === null && v.length !== 0 )
  {
   firstErrorField = this.champs[i];
  }
  for ( j = 0; j < v.length; j++ )
  {
   errors.push(' - ' + v[j]);
  }
 }

 if ( errors.length === 0 && errorBefore.length === 0 && errorAfter.length === 0)
 {
  v = AI.DOM.getById(this.fId);
  if ( typeof v._oldonsubmit == 'function' )
  {
   return v._oldonsubmit(evt);
  }
  return true;
 }

 if ( this.confirmer ) { msg += CheckForm.l10n('confirmez_vous_soumission_formulaire'); }
 else { msg += CheckForm.l10n('veuillez_corriger_formulaire'); }
 msg += CR + CR;
 if ( errorBefore.length > 0 ) { msg += errorBefore.join(CR) + CR; }
 msg += errors.join(CR);
 if ( errorAfter.length > 0 ) { msg += CR + errorAfter.join(CR); }
 if ( this.confirmer )
 {
  if (confirm(msg))
  {
   reussite = true;
   if ( typeof formulaire._oldonsubmit == 'function' ) { reussite = formulaire._oldonsubmit(evt); }
   if ( reussite ) { CheckForm.disableSubmit(formulaire); }
   return reussite;
  }
  else
  {
   if ( firstErrorField ) { firstErrorField.focus(); }
   return false;
  }
 }
 alert(msg);
 if ( firstErrorField ) { firstErrorField.focus(); }
 return false;
};

CheckForm.disableSubmit = function(frm)
{
 for ( var i = 0; i < frm.elements.length; i++ )
 {
  frm.elements[i].disabled = true;
 }
};

CheckForm.prototype.addField = function(param)
{
 var champ = new Field(this.fId, param);
 if ( champ ) { this.champs.push(champ); }
};

/**
 *
 * @private
 */
CheckForm.param = function(etat, obj, defaut)
{
 return typeof obj[etat] != 'undefined' ? obj[etat] : defaut;
};


Field.prototype._getElement = function()
{
 return AI.DOM.getById(this.fId).elements[this.name];
};

/**
 * Place la barre d'indicateur de caractères
 * @param {HTMLElement} E (Element) L'élément textarea/input
 * @param {integer}     T (Top)     La position Top
 * @param {integer}     L (Left)    La position Left
 * @param (integer)     W (Width)   La taille
 * @param {boolean}     X (isXinha) true si c'est un éditeur Xinha, false si c'est un input/textarea standard
 * TODO : laid, ce IS.IE, lui préférer un calcul de position qui marche vraiment
 */
Field._setIndicateurPos = function(E, T, L, W, X)
{
  var C = CheckForm.indicateur_container;
//  C.style.top = DOM.pix(T, -3);
  if ( IS.IE )
  {
    C.style.top = DOM.pix(T);
  }
  else
  {
    C.style.top = DOM.pix(T, -3);
  }
//  C.style.top = DOM.pix( IS.IE ? T : T - 3);
  C.style.left = DOM.pix(L);
  C.style.width = DOM.pix(W);
  Field._synchroCaracs(E, W, X);
  DOM.show(C);
};

/**
 * Synchronize la barre d'indicateur de caractères
 * @param {HTMLElement} E (Element) Le textarea
 * @param {integer}     W (Width)   La taille
 * @param {boolean}     X (isXinha) true si c'est un éditeur Xinha, false si c'est un input/textarea standard
 * @private
 */
Field._synchroCaracs = function(E, W, X)
{
 var
  V = X === false ? E.value : 'contenu xinha',
  I = CheckForm.indicateur.style,
  P = (V.length * 100 ) / E.maxi,
  c = '#00FF80';
 if ( P >= 100 )
 {
  if ( X )
  {
    // resize le content xinha
  }
  else { E.value = V.substr(0, E.maxi); }
  P = 100;
  c = '#C40000';
 }
 else if ( P > 90 ) { c = '#FF0000'; }
 else if ( P > 75 ) { c = '#FF8040'; }
 else if ( P > 50 ) { c = '#FFFF80'; }
 I.width = intval(W * P / 100) + 'px';
 I.backgroundColor = c;
};

/**
 * Gestion du focus
 * @param {event} e (event) L'événement
 * @private
 */
Field._onfocus = function(e)
{
 if ( this.type == 'textarea' || this.type == 'text' )
 {
  if ( !AI.DOM.CSS.has('not_auto', this) && this.maxi > 0 ) { Field._setIndicateurPos(this, AI.DOM.getY(this), AI.DOM.getX(this), this.offsetWidth, false); }
  if ( typeof this.$oldfocus == 'function' ) { this.$oldfocus.call(this, e); }
 }
};

/**
 * Gestion du blur
 * @param {event} e (event) L'événement
 * @private
 */
Field._onblur = function(e)
{
 AI.DOM.hide(CheckForm.indicateur_container);
 if ( typeof this.$oldblur == 'function' ) { this.$oldblur.call(this, e); }
};

/**
 * Gestion du keypress
 * @param {event} e (event) L'événement
 * @private
 */
Field._onkeypress = function(e)
{
 Field._synchroCaracs(this, this.offsetWidth, false);
 if ( typeof this.$oldkeypress == 'function' ) { this.$oldkeypress.call(this, e); }
};

/**
 * @private
 */
Field.prototype.valider = function()
{
 this.resetCSS();
 this.errors = [];
 if (typeof this['valider_' + this.CarTyp] !== 'undefined')
 {
  this['valider_' + this.CarTyp]();
 }
 else
 {
  alert('format inconnu : ' + this.CarTyp + '/' + this.name + '/' + this.label);
 }
 return this.errors;
};

Field.prototype.valider_CarBoo = function()
{
 var v = this.getValue();
 if ( v === '' && this.required)
 {
  this.errors.push(this.label + ' ' + CheckForm.l10n('est_obligatoire'));
  this.showErrorCSS('input_vide');
 }
};

Field.prototype.valider_CarBin = function()
{
 var v = this.getValue();
 if ( v === '' && this.required )
 {
  this.errors.push(this.label + ' ' + CheckForm.l10n('est_obligatoire'));
  this.showErrorCSS('input_vide');
 }
};

Field.prototype.valider_CarCha = function()
{
 var v = this.getValue();
 // TODO : même quand c'est vide et pas obligatoire on aimerait peut etre vérifier la longueur maxi/mini. non ?
 if ( v === '' )
 {
  if ( this.required )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('est_obligatoire'));
   this.showErrorCSS('input_vide');
  }
 }
 else
 {
  if ( this.mini !== null && v.length < this.mini )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_avoir_caracteres_minimum') + ' ' + this.mini);
   this.showErrorCSS('input_incorrect');
  }
  if ( this.maxi !== null && v.length > this.maxi )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_avoir_caracteres_maximum') + ' ' + this.maxi);
   this.showErrorCSS('input_incorrect');
  }
  if (this.format == 'email')
  {
   if ( v.search(CheckForm.RE_checkEmail) )
   {
    this.errors.push(this.label + ' ' + CheckForm.l10n('est_pas_email_valide'));
    this.showErrorCSS('input_incorrect');
   }
  }
 }
};

Field.prototype.valider_CarDat = function()
{
 var v = this.getValue();
 if (v === '' && this.required )
 {
  this.errors.push(this.label + ' ' + CheckForm.l10n('est_obligatoire'));
  this.showErrorCSS('input_vide');
 }
};

Field.prototype.valider_CarFlo = function()
{
 var v = this.getValue();
 // TODO : même quand c'est vide et pas obligatoire on aimerait peut etre vérifier la longueur maxi/mini. non ?
 if ( v === '' )
 {
  if ( this.required )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('est_obligatoire'));
   this.showErrorCSS('input_vide');
  }
 }
 else
 {
  if ( v === '*' ) { v = 1e+37; }
  if ( parseFloat(v) != v )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_etre_flottant'));
   this.showErrorCSS('input_incorrect');
  }
  v = parseFloat(v);
  if ( this.mini !== null && v < parseFloat(this.mini) )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_etre_superieur') + ' ' + this.mini);
   this.showErrorCSS('input_incorrect');
  }
  if ( this.maxi !== null && v > parseFloat(this.maxi) )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_etre_inferieur') + ' ' + this.maxi);
   this.showErrorCSS('input_incorrect');
  }
 }
};

Field.prototype.valider_CarInt = function()
{
 var v = this.getValue();
 // TODO : même quand c'est vide et pas obligatoire on aimerait peut etre vérifier la longueur maxi/mini. non ?
 if ( v === '' )
 {
  if ( this.required )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('est_obligatoire'));
   this.showErrorCSS('input_vide');
  }
 }
 else
 {
  if ( v === '*' ) { v = 2147483647; }
  if ( parseInt(v, 10) != v )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_etre_entier'));
   this.showErrorCSS('input_incorrect');
  }
  if ( this.mini !== null && v < parseInt(this.mini, 10) )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_etre_superieur') + ' ' + this.mini);
   this.showErrorCSS('input_incorrect');
  }
  if ( this.maxi !== null && v > parseInt(this.maxi, 10) )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_etre_inferieur') + ' ' + this.maxi);
   this.showErrorCSS('input_incorrect');
  }
 }
};

Field.prototype.valider_CarObj = function()
{
 var v = this.getValue();
 if ( v === '' || parseInt(v, 10) === 0 || isNaN(parseInt(v, 10)) )
 {
  if ( this.required )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('est_obligatoire'));
   this.showErrorCSS('input_vide');
  }
 }
};

Field.prototype.valider_CarTim = function()
{
 var v = this.getValue();
 if (v === '' && this.required )
 {
  this.errors.push(this.label + ' ' + CheckForm.l10n('est_obligatoire'));
  this.showErrorCSS('input_vide');
 }
};

Field.prototype.valider_CarTxt = function()
{
 var v = this.getValue();
 if ( this.format == 'WYSIWYG' ) { v = v.stripTags(); }
 if ( v === '' )
 {
  if ( this.required )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('est_obligatoire'));
   this.showErrorCSS('input_vide');
  }
 }
 else
 {
  if ( this.mini !== null && v.length < this.mini )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_avoir_caracteres_minimum') + ' ' + this.mini);
   this.showErrorCSS('input_incorrect');
  }
  if ( this.maxi !== null && v.length > this.maxi )
  {
   this.errors.push(this.label + ' ' + CheckForm.l10n('doit_avoir_caracteres_maximum') + ' ' + this.maxi);
   this.showErrorCSS('input_incorrect');
  }
 }
};

Field.prototype.resetCSS = function()
{
 var elt = this._getElement();
 AI.DOM.CSS.remove('input_vide', elt);
 AI.DOM.CSS.remove('input_incorrect', elt);
};

Field.prototype.showErrorCSS = function(css)
{
 this.resetCSS();
 AI.DOM.CSS.add(css, this._getElement());
};

Field.prototype.focus = function()
{
 AI.HTML.safeFocus(this._getElement());
/*
 var elt = this._getElement();
 var old_autocomplete = elt.autocomplete;
 elt.autocomplete = 'off';
 elt.focus();
 if ( old_autocomplete )
 {
  elt.autocomplete = old_autocomplete;
 }
*/
};

Field.prototype.getValue = function ()
{
 var
  i,
  elt = this._getElement(),
  type = (this.type.substring(0,6) == "select") ? "select" : this.type,
  value = [];

 if ( type == "select" )
 {
  if ( this.type == "select-one" )
  {
   value.push((elt.selectedIndex == -1) ? "" : elt.options[elt.selectedIndex].value);
  }
  else
  {
   for ( i = 0; i < elt.length; i++ )
   {
    if ( elt[i].selected )
    {
     value.push(elt.options[i].value.trim());
    }
   }
  }
 }
 else if ( type == "checkbox" || type == "radio" )
 {
  // if more then one checkbox
  if( !!elt[0] && !elt.value.trim() )
  {
   for ( i = 0; i < elt.length; i++ )
   {
    if ( elt.options[i].checked )
    {
     value.push(elt.options[i].value.trim());
    }
   }
  }
  else if ( elt.checked )
  {
   value.push(elt.value.trim());
  }
 }
 else
 {
  value.push(elt.value.trim());
 }
 return value.join('§').trim();
};