/**
 * @namespace GA_project
 * @sdoc ga.sdoc
 * @id GA
 * @version $Revision: 1103 $
 */
typeof GA == 'undefined' && (GA = {})
/** @id GA.eventWatcherClass */
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
          }
          obj[methodName](e.srcElement || document, r, e, oParams) === false &&
            (e.returnValue = false)
        }
      }
    )(this, methodName, oParams || null);
    oNode.attachEvent('on'+sEvent, handler);
    return handler
  }
}
