/*******************************************************************************
* description  Проверка формы на правильность заполнения полей
*              Выделение цветом фона поля в фокусе или в случае ошибки
*              Поля, к которым нет доступа (disabled=true), а так же скрытые поля (hidden) не проверяются
* dependencies none
* browsers     DOM browsers
* version      2.0.4 (26.04.2003-)
* author       Nasibullin Rinat <rin at pgcms dot com>, http://rin.pgcms.com
*******************************************************************************/

/**
* Конструктор объекта.
* @param  string  formName     объект формы
* @param  string  attrPref     префикс атрибутов (например "v_")
* @param  string  classNormal  имя класса в CSS для поля ввода вне фокуса
* @param  string  classFocus   имя класса в CSS для поля ввода в фокусе
* @param  string  classError   имя класса в CSS для поля ввода в случае ошибки
* @access public
*/
FormAdv = function(formName, attrPref, classNormal, classFocus, classError){

  /**
  * Меняет изображение в картинке предварительного просмотра
  * @param   object      objFile     объект поля формы файлового типа
  * @access  private
  */
  this._changeImg = function(objFile) {
    var objImg = document.images[this.imgPref + objFile.name];
    if (objFile.value) {
      objImg.src = objFile.value;
      return;
    }
    objImg.src = (objImg.getAttribute(this.attrPref + 'orig_src') || 'file://');
  }

  /**
  * Перехватывает события для поля формы
  * @param   object      obj     объект поля формы
  * @access  private
  */
  this._setEvents = function(obj) {
    var chclass = Number(obj.getAttribute(this.attrPref + 'chclass'));
    if (obj.type == 'file' && Number(obj.getAttribute(this.attrPref + 'is_file_img'))) {
      var s = this.objName + '._changeImg(this);';
      obj.onchange = new Function(s);
      obj.onfocus  = new Function(s + (chclass ? 'this.className = "' + this.classFocus  + '";' : ''));
      obj.onblur   = new Function(s + (chclass ? 'this.className = "' + this.classNormal + '";' : ''));
      return;
    }
    if (chclass) {
      obj.onfocus = new Function('this.className = "' + this.classFocus  + '";');
      obj.onblur  = new Function('this.className = "' + this.classNormal + '";');
    }
  }

  /**
  * Информация об изображении при наведении курсора мыши
  * @param   object      objImg      объект изображения
  * @param   string      eventType   тип события (mouseover|mouseout)
  * @access  private
  */
  this._imageInfo = function(objImg, eventType) {
    objImg.alt = '';
    if (eventType == 'mouseover' && objImg.complete && objImg.fileSize > 0) {
      objImg.alt = objImg.fileSize + ' bytes\r\n' +
                   objImg.mimeType + '\r\n' +
                   objImg.width + 'x' + objImg.height + 'px';
    }
    return false;
  }

  /**
  * Событие, вызываемое при ошибке
  * @param   object   elemObj  объект элемента, на котором произошла ошибка
  * @access  public
  */
  this.onError = function(elemObj) {
  }

  /**
  * Событие, вызываемое после успешной проверки формы
  * @param   object   formObj     объект формы
  * @return  bool     true/false  значение, возвращаемое в событие onsubmit формы
  * @access  public
  */
  this.onOK = function(formObj) {
    return true;
  }

  /**
  * Метод, вызываемый при ошибке.
  * Ставит фокус на элемент формы и показывает сообщение об ошибке методом "alert"
  * @param   object   obj      объект поля формы
  * @param   string   errmsg   сообщение (если не указано, то берется из атрибута поля "errmsg")
  * @return  false
  * @access  public
  */
  this.raiseError = function(obj, errmsg) {
    //alert(obj.name)
    var chclass = Number(obj.getAttribute(this.attrPref + 'chclass'));
    if (chclass) {
      obj.onblur  = null;
      obj.onfocus = null;
      obj.className = this.classError;
    }
    this.onError(obj);
    obj.focus();
    if (! errmsg) {
      errmsg = obj.getAttribute(this.attrPref + 'errmsg');
    }
    alert(errmsg);
    this._setEvents(obj);
    if (chclass) {
      obj.blur();
      obj.focus();
    }
    return false;
  }

  /**
  * Проверка полей формы на корректность введенных данных.
  * Условия проверки берутся из атрибутов полей.
  * В случае ошибки вызывается метод this.raiseError()
  * Определены следующие атрибуты:
  *   <attrPref>chclass     bool     менять класс при попадании в фокус?
  *   <attrPref>minlength   int      минимальная длина для текста
  *   <attrPref>maxlength   int      максимальная длина для текста
  *   maxlength             int      максимальная длина для текста
  *   <attrPref>min         int      минимальное значение для числа
  *   <attrPref>max         int      максимальное значение для числа
  *   <attrPref>pregexp     string   регулярное выражение (perl совместимого типа)
  *   <attrPref>is_null     bool     значение может быть NULL?
  *   <attrPref>errmsg      string   сообщение в случае ошибки
  *   Для элемента формы файлового типа:
  *   <attrPref>is_file_img     bool  файл является изображением?
  *   <attrPref>img_min_width   int   минимальная ширина изображения
  *   <attrPref>img_min_height  int   минимальная высота изображения
  *   <attrPref>img_max_width   int   максимальная ширина изображения
  *   <attrPref>img_max_height  int   максимальная высота изображения
  *   <attrPref>file_max_size   int   максимальный размер файла
  *   * Если <attrPref>is_file_img = true, то должен быть элемент предпросмотра изображения,
  *     который имеет тоже название с префиксом this.imgPref
  * @return bool         true     поля заполнены верно
  *                      false    поля заполнены не верно
  * @access private
  */
  this._check = function() {
    for (var i = 0; i < this.elems.length; i++) {
      var obj = this.elems[i];
      if (obj.disabled) {
        continue;
      }
      var value = obj.value;
      var minlength = obj.getAttribute(this.attrPref + 'minlength');
      var maxlength = obj.getAttribute(this.attrPref + 'maxlength') || obj.getAttribute('maxlength');
      var min = obj.getAttribute(this.attrPref + 'min');
      var max = obj.getAttribute(this.attrPref + 'max');
      var pregexp = obj.getAttribute(this.attrPref + 'pregexp');
      var is_null = obj.getAttribute(this.attrPref + 'is_null');
      if (/^text/i.test(obj.type)) {  //text, textarea
        if ( (Boolean(minlength) && value.length < minlength) ||
             (Boolean(maxlength) && value.length > maxlength) ||
             (Boolean(min) && value.length && Number(value) < min) ||
             (Boolean(max) && value.length && Number(value) > max) ||
             (Boolean(pregexp) && value.length && value != 'NULL' && !(eval(pregexp)).test(value)) ||
             (! Boolean(is_null) && value == 'NULL')
           ) {
          return this.raiseError(obj);
        }
      }

      //проверяем поле для загрузки изображения
      if (obj.type == 'file' && obj.value && Number(obj.getAttribute(this.attrPref + 'is_file_img'))) {
        var img_min_width  = Number(obj.getAttribute(this.attrPref + 'img_min_width'));
        var img_min_height = Number(obj.getAttribute(this.attrPref + 'img_min_height'));
        var img_max_width  = Number(obj.getAttribute(this.attrPref + 'img_max_width'));
        var img_max_height = Number(obj.getAttribute(this.attrPref + 'img_max_height'));
        var file_max_size  = Number(obj.getAttribute(this.attrPref + 'file_max_size'));
        var objImg = document.images[this.imgPref + obj.name];
        if (!objImg.complete || !objImg.fileSize) {
          continue;
        }
        if ( (objImg.width < img_min_width) || (objImg.height < img_min_height) ||
             (img_max_width && objImg.width > img_max_width) || (img_max_height && objImg.height > img_max_height) ||
             (objImg.fileSize > file_max_size) ) {
          return this.raiseError(obj);
        }
      }
    }//for

    if (!this.onOK(this.formObj)) {
      return false;
    }
    this.disableButtons(true);
    return true;
  }

  /**
  * Устанавливает свойство "disabled" у кнопок формы
  * @param   bool   isDisable
  * @return  void
  * @access  public
  */
  this.disableButtons = function(isDisable) {
    for (var i = 0; i < this.buttons.length; i++) {
      this.buttons[i].disabled = isDisable;
    }
  }

  //constructor
  //{{{
  if (!document.getElementById) {
    window.status = 'FormAdv::__constructor() Error: this browser not support DOM!';
    return;
  }
  this.formObj = document.forms[formName];
  if (typeof(this.formObj) != 'object') {
    window.status = 'FormAdv::__constructor() Error: form "' + formName + '" not found!';
    return;
  }
  this.imgPref  = 'img_preview_';
  this.attrPref = attrPref;
  this.classNormal = classNormal;
  this.classFocus = classFocus;
  this.classError = classError;
  this.elems = [];
  this.buttons = [];

  this.objName = '_FormAdv_' + formName;
  eval(this.objName + ' = this');

  //для всех элементов ввода перехватываем события onfocus и onblur
  for (var i = 0; i < this.formObj.elements.length; i++) {
    var obj = this.formObj.elements[i];
    if (/^(text|password|select|radio|checkbox|file).*/i.test(obj.type)) {
      this.elems[this.elems.length] = obj;
      this._setEvents(obj);
      if (obj.type == 'file' && Number(obj.getAttribute(this.attrPref + 'is_file_img'))) {
        var imgObj = document.images[this.imgPref + obj.name];
        if (typeof(imgObj) != 'object') {
          window.status = 'FormAdv::__constructor() Error: preview image for form field "' + obj.name + '" not found!';
          return;
        }
        imgObj.onmouseover = new Function(this.objName + '._imageInfo(this, "mouseover")');
        imgObj.onmouseout  = new Function(this.objName + '._imageInfo(this, "mouseout")');
      }
      continue;
    }
    if (/^(reset|submit|button)/i.test(obj.type)) {
      this.buttons[this.buttons.length] = obj;
    }
  }
  this.formObj.onsubmit = new Function('return ' + this.objName + '._check()');
  //}}}

}//class
