(function() {
  var dt, dta;

  this.def_class('DTouch',DObject,function(__scope,__class){

    this.__ctor__ = function DTouch(event) {
      this["@start"] = null;
      this["@event"] = null;
      this["@prev"] = null;
      this["@target"] = null;
      this["@dragtarget"] = null;
      this["@droptarget"] = null;
      return this;
    }; this.__ctor__.prototype = this.prototype;;

    this.prototype["event="] = function(event) {
      if (!this["@event"]) {
        this["@start"] = event;
        this["@node"] = event.target;
        this["@startX"] = event.clientX;
        this["@startY"] = event.clientY;
        this["@timestamp"] = new (__ctor(__scope.Date))();
      }
      this["@prev"] = this["@event"];
      this["@event"] = event;
      this["@x"] = event.clientX;
      this["@y"] = event.clientY;
      this["@offsetX"] = event.offsetX;
      this["@offsetY"] = event.offsetY;
      this["@movedX"] = this["@x"] - this["@startX"];
      this["@movedY"] = this["@y"] - this["@startY"];
      return event;
    }; __method_added(this,"event=");

    this.prototype["target="] = function(view) {
      return this["@target"] = view;
    }; __method_added(this,"target=");

    this.prototype["delegate="] = function(delegate) {
      if (this["@delegate"] = delegate) {
        return this["emit!"]('touchstart', nil, this["@delegate"]);
      }
    }; __method_added(this,"delegate=");

    this.prototype.receiver = function() {
      return this["@delegate"] || this["@target"];
    }; __method_added(this,"receiver");

    this.prototype["emit!"] = function(name, node, view) {
      var args, body, delegator, handler, meth;
      if (!node && !view) return;
      meth = "on" + name;
      if (view) {
        handler = view[meth];
        if (handler instanceof __scope.Function) {
          return view[meth](this);
        } else if (typeof handler === 'string') {
          return view[handler](this);
        }
        return;
      }
      if (node === $doc.documentElement) return;
      delegator = void 0;
      body = $doc.body;
      args = [this];
      while (node !== body) {
        view = node["@view"];
        if (view && (handler = view[meth])) {
          if (handler instanceof __scope.Function) {
            if (handler.apply(view, args)) return view;
          } else if (typeof handler === 'string') {
            meth = handler;
            args.push(view);
            continue;
          } else if (handler instanceof __scope.Array) {
            meth = handler[0];
            args = handler.clone();
            args.shift();
            args.push(this, view);
            continue;
          }
        }
        node = node.parentNode;
      }
      return nil;
    }; __method_added(this,"emit!");

    this.prototype["touchstart!"] = function(event) {
      this["event="](event);
      if (this["@target"] = this["emit!"]('touchstart', event.target)) {
        this["@target_bbox"] = this["@target"].bbox();
      }
      return this["@target"];
    }; __method_added(this,"touchstart!");

    this.prototype["touchmove!"] = function(event) {
      this["event="](event);
      this["emit!"]('touchmove', nil, this.receiver());
      if (this["dragdrop?"]()) {
        this["dragmove!"]();
        this["dragenter?"]();
      }
    }; __method_added(this,"touchmove!");

    this.prototype["touchend!"] = function(event) {
      this["event="](event);
      this["emit!"]('touchend', nil, this.receiver());
      if (this["dragdrop?"]()) {
        this["dragenter?"]();
        this["dragend!"](event);
        this["drop!"](event);
      } else {
        if (this.moved().r < 5 && this.duration() < 200) {
          this["emit!"]('tap', this["@node"]);
        }
      }
      return this;
    }; __method_added(this,"touchend!");

    this.prototype["touchcancel!"] = function() {
      return this["emit!"]('touchcancel', nil, this["@target"]);
    }; __method_added(this,"touchcancel!");

    this.prototype["dragtarget="] = function(target) {
      var bbox;
      if (this["@dragtarget"] = target) {
        bbox = target.bbox();
        this["@elStartX"] = bbox.left;
        this["@elStartY"] = bbox.top;
        this["dragstart!"]();
      }
      return target;
    }; __method_added(this,"dragtarget=");

    this.prototype["droptarget="] = function(target) {
      if (this["@droptarget"] !== target) this["dragleave!"]();
      return this["@droptarget"] = target;
    }; __method_added(this,"droptarget=");

    this.prototype["dragstart!"] = function() {
      if (this["@dragtarget"]) {
        return this["emit!"]('dragstart', nil, this["@dragtarget"]);
      }
    }; __method_added(this,"dragstart!");

    this.prototype["dragmove!"] = function() {
      if (this["@dragtarget"]) {
        return this["emit!"]('dragmove', nil, this["@dragtarget"]);
      }
    }; __method_added(this,"dragmove!");

    this.prototype["dragleave!"] = function() {
      if (this["@droptarget"]) {
        this["emit!"]('dragleave', nil, this["@droptarget"]);
      }
      return this["@droptarget"] = nil;
    }; __method_added(this,"dragleave!");

    this.prototype["dragend!"] = function() {
      if (this["@dragtarget"]) {
        return this["emit!"]('dragend', nil, this["@dragtarget"]);
      }
    }; __method_added(this,"dragend!");

    this.prototype["dragcancel!"] = function() {
      if (this["@dragtarget"]) {
        return this["emit!"]('dragcancel', nil, this["@dragtarget"]);
      }
    }; __method_added(this,"dragcancel!");

    this.prototype["dragfinish!"] = function() {
      if (this["@dragtarget"]) {
        return this["emit!"]('dragfinish', nil, this["@dragtarget"]);
      }
    }; __method_added(this,"dragfinish!");

    this.prototype["drop!"] = function() {
      if (!this["@droptarget"]) return this["dragcancel!"]();
      if (this["emit!"]('drop', nil, this["@droptarget"])) {
        return this["dragfinish!"]();
      } else {
        return this["dragcancel!"]();
      }
    }; __method_added(this,"drop!");

    this.prototype["dragenter?"] = function() {
      var node, prev;
      node = this["@event"].target;
      prev = this["@prev"].target;
      if (prev !== node && node && node["@view"] !== this["@droptarget"]) {
        return this["droptarget="](this["emit!"]('dragenter', node));
      }
      return nil;
    }; __method_added(this,"dragenter?");

    this.prototype.duration = function() {
      return new (__ctor(__scope.Date))().getTime() - this["@timestamp"].getTime();
    }; __method_added(this,"duration");

    this.prototype.moved = function() {
      var r, x, y;
      x = this["@x"] - this["@startX"];
      y = this["@y"] - this["@startY"];
      r = __scope.Math.abs(x) + __scope.Math.abs(y);
      return {
        x: x,
        y: y,
        r: r
      };
    }; __method_added(this,"moved");

    this.prototype["meta?"] = function() {
      return this["@event"].metaKey;
    }; __method_added(this,"meta?");

    this.prototype["shift?"] = function() {
      return this["@event"].shiftKey;
    }; __method_added(this,"shift?");

    this.prototype["alt?"] = function() {
      return this["@event"].altKey;
    }; __method_added(this,"alt?");

    this.prototype["dragdrop?"] = function() {
      return !!this["@dragtarget"];
    }; __method_added(this,"dragdrop?");

    this.prototype.x = function() {
      return this["@x"];
    }; __method_added(this,"x");

    this.prototype.y = function() {
      return this["@y"];
    }; __method_added(this,"y");

  });

  this.def_class('DEvent',DObject,function(__scope,__class){

    this.handle = function(event, name) {
      return new (__ctor(this))(event, name)["emit!"]();
    };__singleton_method_added(this,"handle");

    this.__ctor__ = function DEvent(event, name) {
      this["@name"] = name;
      this["@event"] = event;
      this["@node"] = event['target'];
      return this;
    }; this.__ctor__.prototype = this.prototype;;

    this.prototype["emit!"] = function() {
      var args, delegator, handler, meth, node, view;
      node = this["@node"];
      meth = "on" + this["@name"];
      delegator = nil;
      if (node === $doc.documentElement) return;
      while (node !== $doc['body']) {
        if ((view = node["@view"]) && (handler = view[meth])) {
          if (typeof handler === 'string') {
            meth = handler;
            delegator = view;
            continue;
          } else if (handler instanceof __scope.Array) {
            meth = handler[0];
            args = handler;
          } else if (handler instanceof __scope.Function) {
            if (handler.call(view, this, delegator)) return view;
          }
        }
        node = node.parentNode;
      }
      return this;
    }; __method_added(this,"emit!");

    this.prototype["meta?"] = function() {
      return this["@event"].metaKey;
    }; __method_added(this,"meta?");

    this.prototype["shift?"] = function() {
      return this["@event"].shiftKey;
    }; __method_added(this,"shift?");

    this.prototype["alt?"] = function() {
      return this["@event"].altKey;
    }; __method_added(this,"alt?");

    this.prototype.char = function() {
      if (this["@event"].keyCode < 48) return "";
      return this["@char"] || (this["@char"] = __scope.String.fromCharCode(this["@event"].keyCode));
    }; __method_added(this,"char");

  });

  if (!$win.Touch) {
    dt = __scope.DTouch;
    dta = null;
    $doc.onmousedown = function(event) {
      if (event.which === 1) {
        dta = new (__ctor(dt))(event);
        return dta["touchstart!"](event);
      }
    };
    $doc.onmousemove = function(event) {
      if (dta) return dta["touchmove!"](event);
    };
    $doc.onmouseup = function(event) {
      if (dta) dta["touchend!"](event);
      return dta = null;
    };
    $doc.onchange = function(event) {
      return __scope.DEvent.handle(event, 'formchange');
    };
    $doc.onkeydown = function(event) {
      return __scope.DEvent.handle(event, 'keydown');
    };
    $doc.onkeyup = function(event) {
      return __scope.DEvent.handle(event, 'keyup');
    };
    $doc.addEventListener("DOMFocusIn", (function(event) {
      return __scope.DEvent.handle(event, 'focus');
    }), true);
    $doc.addEventListener("DOMFocusOut", (function(event) {
      return __scope.DEvent.handle(event, 'blur');
    }), true);
  }

}).call($$base);

