/**
 * @namespace GA_project
 * @sdoc ga.sdoc
 * @id GA
 */
typeof GA == 'undefined' && (GA = {})
GA.JsHttpRequest = function() {}
GA.JsHttpRequest.aSessions = [{}];
GA.JsHttpRequest.prototype.send = function(url, callbackMethodName, aSessionParams) {
  var sessID, fn;
  if (this.requestScriptNode) {
    this.requestScriptNode.parentNode.removeChild(this.requestScriptNode);
  }
  sessID=0;
  fn = GA.JsHttpRequest.makeOnLoadProcessor(this, callbackMethodName, aSessionParams.slice(0));
  this.requestScriptNode = (function(sessID){
    var n, t = document.createElement('DIV');
    t.style.display = 'none';
    document.body.insertBefore(t, document.body.firstChild);
    t.innerHTML = 't<s'+'cript type="text/javascript" language="JavaScript" charset="utf-8"></' + 'script>';
    n = t.removeChild(t.lastChild);
    document.body.replaceChild(n, t);
    n.onreadystatechange = n.onload = fn;
    return n
  })(sessID);
  if (this.requestScriptNode.setAttribute) {
    this.requestScriptNode.setAttribute('src', url)
  } else {
    this.requestScriptNode.src = url
  }
}
GA.JsHttpRequest.makeOnLoadProcessor = function (obj, callbackMethodName, oParams) {
  var isDone = 0;
  return function(e) {
    var a = GA.JsHttpRequest.aSessions, v = [null];
    e = window.event || e;
    if (
      isDone ||
      (e.type == 'readystatechange' && !/loaded|complete/.test(this.readyState))
    ) return;
    isDone = 1;
    if ( callbackMethodName && (typeof obj[callbackMethodName] != 'undefined') ) {
      typeof a[0].value != 'undefined' && (v[0] = a[0].value);
      obj[callbackMethodName].apply( obj, v.concat(oParams) );
    }
    delete a[0].value
  }
}

GA.eventWatcherClass = function(eventTypes, path, onInMethodName, onOutMethodName) {
  //если нет параметров выходим.
  if (!eventTypes || !path) return;
  var a, k,
  evtWPrms = {
    'onIn': onInMethodName || false,
    'onOut': onOutMethodName || false,
    'test':[]
  };
  this.watchedEvents = {};
  a = path.split(/\s+/);
  for (k = a.length; k--; ) {
    evtWPrms.test[evtWPrms.test.length] = (function(a) {
      var t = (a[2]||'') + (a[5]||''), c = {}, k;
      a[1] && (a[1] = a[1].toUpperCase());
      t = t.substr(1).split('.');
      if (t[0]) for (k = t.length; k--;) {
        c[t[k]]=1
      }
      return function(oNode) {
        var k, o={}, m;
        if (t[0]) {
          if (!oNode.className) return false;
          m = oNode.className.split(/\s/);
          for (k = m.length; k--; ) {o[m[k]]=1}
          for (k in c) {
            if (!o[k]) {
              return false
            }
          }
        }
        return (!a[1] || oNode.nodeName == a[1]) && (!a[3] || (oNode.nodeType == 1 && oNode.getAttribute([a[3]]) == a[4]) )
      }
    })(/^(\w+|)(\.[\.\w]+)*(?:\[\s*@(\w+)=(\w+)\]|[^\.]*)(\.[\.\w]+)*/.exec(a[k]));
  }
  eventTypes.constructor != Array && (eventTypes = [eventTypes]);
  for (var i = eventTypes.length; i--; ) {
    this.watchedEvents[eventTypes[i]] = 
      this.methodIntoEventProcessing('eventProcessing', eventTypes[i], document, evtWPrms)
  }
}
GA.eventWatcherClass.removeEventProcessing = document.addEventListener ?
  function(sEvent, handler, oNode) {
    oNode.removeEventListener(sEvent, handler, false)
  }:
  function(sEvent, handler, oNode){
    oNode.detachEvent('on'+sEvent, handler)
  }
GA.eventWatcherClass.prototype = {
  'eventProcessing': function(oNode, pos, e, evtWPrms) {
    var initialNode = oNode, k = 0, nod;
    do {
      if ( evtWPrms.test[k](oNode) ) {
        !k && (nod = oNode);
        if ((++k) == evtWPrms.test.length) {
          return evtWPrms.onIn ?
            this[evtWPrms.onIn](nod, pos, e):
            null
        }
      }
    } while (oNode = oNode.parentNode);
    // событие произошло вне узла с заданным классом.
    return evtWPrms.onOut?
      this[evtWPrms.onOut](initialNode, pos, e):
      null
  },
  'methodIntoEventProcessing': document.addEventListener ?
  function(methodName, sEvent, oNode, oParams) {
    var handler = (
      function(obj, methodName, oParams) {
        return function(e) {
          obj[methodName](e.target, {'x': e.pageX, 'y': e.pageY}, e, oParams) === false && e.preventDefault()
        }
      }
    )(this, methodName, oParams || null);
    oNode.addEventListener( sEvent, handler, false );
    return handler
  }:
  function(methodName, sEvent, oNode, oParams) {
    var handler = (
      function(obj, methodName, oParams) {
        return function() {
          var e = window.event,
          t = document.documentElement,
          r = {
            'x': e.clientX + t.scrollLeft ,
            'y': e.clientY + t.scrollTop
          };
          if (t = document.body) {
            r.x += t.scrollLeft;
            r.y += t.scrollTop
          }
          e.srcElement &&
          obj[methodName](e.srcElement, r, e, oParams) === false &&
            (e.returnValue = false)
        }
      }
    )(this, methodName, oParams || null);
    oNode.attachEvent('on'+sEvent, handler);
    return handler
  }
}

GA.validateClass = function(formPatch, oElemetsParamsOfValidate, errorClass){
  var i, o,
  b = Number(arguments.length > 2),
  s = '(?:\\s|^)'+arguments[1+b]+'(\\s|$)';
  function validateParams(obj) {
    var i;
    for (i in obj) {
      this[i] = obj[i]
    }
  };
  validateParams.prototype = {
    'pattern': false,
    'maxLength': false,
    'minLength': false,
    'max': false,
    'min': false,
    'test': function(sValue) {
      var i , o;
      if ((o = this.pattern) && !o[0].test(sValue)) {
        this.errorText = o[1];
        return false
      } else if ((o = this.maxLength) && o[0] < sValue.length) {
        this.errorText = o[1];
        return false
      } else if ((o = this.minLength) && o[0] > sValue.length) {
        this.errorText = o[1];
        return false
      } else if ((o = this.max) && o[0] < Number(sValue)) {
        this.errorText = o[1];
        return false
      } else if ((o = this.min) && o[0] > Number(sValue)) {
        this.errorText = o[1];
        return false
      }
      return true
    }
  };
  this.oElemetsParamsOfValidate = {};
  o = arguments[0+b];
  for (i in o) {
    if (o[i].constructor == Array) {
      this.oElemetsParamsOfValidate[i]= new validateParams({'pattern': o[i]})
    } else {
      this.oElemetsParamsOfValidate[i] = new validateParams(o[i])
    }
  }
  this.errorClass = arguments[1+b];
  this.regExpErrClass = new RegExp(s);
  if (typeof this.regExpErrClass.compile != 'undefined') {
    this.regExpErrClass.compile(s)
  }
  //подключим обработчики на формы.
  GA.eventWatcherClass.call(this, ['keyup','mousedown','activate'], b? formPatch: 'form', 'addWathingForm');
}
GA.validateClass.prototype = {
  'addWathingForm': (document.attachEvent && !window.opera)?
    function(oForm) {
      var k;
      if (!this.aForms) this.aForms = [];
      for (k = this.aForms.length; k--; ) {
        if (this.aForms[k] == oForm) return
      }
      this.aForms[this.aForms.length] = oForm;
      
      this.methodIntoEventProcessing('onSubmit', 'submit', oForm);
      //подключаем_к_событиям_обработчики, проверяющие_значения_в_полях_ввода.
      for(k in this.oElemetsParamsOfValidate) {
        typeof oForm[k] != 'undefined' &&
        this.methodIntoEventProcessing('toggleErrorClass', 'propertychange', oForm[k])
      }
    }:
    function(oForm) {
      var k, evs = {'input': 0, 'keydown':0, 'change':0};
      if (!this.aForms) this.aForms = [];
      for (k = this.aForms.length; k--; ) {
        if (this.aForms[k] == oForm) return
      }
      this.aForms[this.aForms.length] = oForm;
      
      this.methodIntoEventProcessing('onSubmit', 'submit', oForm);
      //подключаем_к_событиям_обработчики, проверяющие_значения_в_полях_ввода.
      for (k in evs) {
        this.methodIntoEventProcessing('toggleErrorClass', k, oForm)
      }
    },
  'shake': function(node) {
    var n = 6;
    //node.style.position = 'relative'; - глюки.
    (
      function closureFunc() {
        if (--n) {
          if (n % 2) {
            node.style.left = '-1px'
          } else {
            node.style.left = '1px'
          }
          window.setTimeout(closureFunc, 100 / (n+1))
        } else {
          node.style.left = '';
        }
      }
    )()
  },
  'toggleErrorClass': function(node, pos, e) {
    var b = this.regExpErrClass.test(node.className),
    o = this.oElemetsParamsOfValidate[node.getAttribute('name')] || false;
    if (
      typeof node.value == 'undefined' ||
      !o ||
      (e.type == 'propertychange' && e.propertyName != 'value') ||
      node.form.haveStopSubmit
    ) return;
    if ( node.value === '' || o.test(node.value)) {
      b && (node.className = node.className.replace(this.regExpErrClass, '$1'))
    } else if (!b) {
      node.className += ' '+this.errorClass;
      node.focus();
      this.shake(node)
    }
    return
  },
  'onSubmit': function(node, pos, e) {
    var o = this.oElemetsParamsOfValidate;
    if (node.nodeName != 'FORM') return;
    for (var eName in o) {
      if(!node[eName]) continue;
      if (!o[eName].test(node[eName].value)){;
        node.haveStopSubmit = true;
        this.regExpErrClass.test(node[eName].className) || (
          node[eName].className += ' '+this.errorClass
        );
        node[eName].focus();
        if (node[eName].select) node[eName].select();
        this.shake(node[eName]);
        alert(o[eName].errorText);
        node.haveStopSubmit = false;
        return false
      }
    }
    return
  }
};
(function (){
  for (var k in GA.eventWatcherClass.prototype) {
    if (!GA.validateClass.prototype[k]) {
      GA.validateClass.prototype[k] = GA.eventWatcherClass.prototype[k]
    }
  }
})();
