// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/**
 * @fileoverview A Mouse-event abtraction that waits for
 *   mousedown, then watches for subsequent mousemove events
 *   until the next mouseup event, then waits again.
 *   State changes are signaled with
 *      'mouse-tracker-start' : mousedown and tracking
 *      'mouse-tracker-move' : mouse move
 *      'mouse-tracker-end' : mouseup and not tracking.
 */

base.exportTo('ui', function() {

  /**
   * @constructor
   * @param {HTMLElement} targetElement will recv events 'mouse-tracker-start',
   *     'mouse-tracker-move', 'mouse-tracker-end'.
   */
  function MouseTracker(opt_targetElement) {
    this.targetElement = opt_targetElement;

    this.onMouseDown_ = this.onMouseDown_.bind(this);
    this.onMouseMove_ = this.onMouseMove_.bind(this);
    this.onMouseUp_ = this.onMouseUp_.bind(this);

  }

  MouseTracker.prototype = {

    get targetElement() {
      return this.targetElement_;
    },

    set targetElement(targetElement) {
      if (this.targetElement_)
        this.targetElement_.removeEventListener('mousedown', this.onMouseDown_);
      this.targetElement_ = targetElement;
      if (this.targetElement_)
        this.targetElement_.addEventListener('mousedown', this.onMouseDown_);
    },

    onMouseDown_: function(e) {
      if (e.button !== 0)
        return true;

      e = this.remakeEvent_(e, 'mouse-tracker-start');
      this.targetElement_.dispatchEvent(e);
      document.addEventListener('mousemove', this.onMouseMove_);
      document.addEventListener('mouseup', this.onMouseUp_);
      this.targetElement_.addEventListener('blur', this.onMouseUp_);
      e.preventDefault();
      return true;
    },

    onMouseMove_: function(e) {
      e = this.remakeEvent_(e, 'mouse-tracker-move');
      this.targetElement_.dispatchEvent(e);
    },

    onMouseUp_: function(e) {
      document.removeEventListener('mousemove', this.onMouseMove_);
      document.removeEventListener('mouseup', this.onMouseUp_);
      this.targetElement_.removeEventListener('blur', this.onMouseUp_);
      e = this.remakeEvent_(e, 'mouse-tracker-end');
      this.targetElement_.dispatchEvent(e);
    },

    remakeEvent_: function(e, newType) {
      var remade = new base.Event(newType, true, true);
      remade.x = e.x;
      remade.y = e.y;
      remade.offsetX = e.offsetX;
      remade.offsetY = e.offsetY;
      remade.clientX = e.clientX;
      remade.clientY = e.clientY;
      return remade;
    }

  };

  function trackMouseMovesUntilMouseUp(mouseMoveHandler, opt_mouseUpHandler) {
    function cleanupAndDispatchToMouseUp(e) {
      document.removeEventListener('mousemove', mouseMoveHandler);
      document.removeEventListener('mouseup', cleanupAndDispatchToMouseUp);
      if (opt_mouseUpHandler)
        opt_mouseUpHandler(e);
    }
    document.addEventListener('mousemove', mouseMoveHandler);
    document.addEventListener('mouseup', cleanupAndDispatchToMouseUp);
  }

  return {
    MouseTracker: MouseTracker,
    trackMouseMovesUntilMouseUp: trackMouseMovesUntilMouseUp
  };
});

@@ -793,53 +793,8 @@
 ) %7B%0A
-    this.targetElement = opt_targetElement;%0A%0A
     
@@ -948,16 +948,60 @@
 this);%0A%0A
+    this.targetElement = opt_targetElement;%0A
   %7D%0A%0A  M

Set the MouseTracker targetElement after binding.