var appIntent = (function() {
  var _intentElem = null;
  var _pieMenu = null;
  var _iconElem = null;
  var _iconSize = 32;
  var _blurIconTimeout = null;

  function _getIntentElemPos() {
    return [parseInt(_intentElem.style.left), parseInt(_intentElem.style.top)]
  }

  var _isMouseDown = false;
  var _hideTimeout = null;

  function _hidePieMenu() {
    window.clearTimeout(_hideTimeout);
    window.clearTimeout(_blurIconTimeout);
    _hideTimeout = window.setTimeout(function() {
      if (_pieMenu) {
        _pieMenu.hide();
      }
      if (_intentElem) {
        _intentElem.classList.remove("livemargins-bubble-box-showpie");
      }
    }, 100);

    _blurIconTimeout = window.setTimeout(function() {
      _intentElem.classList.add("livemargins-bubble-box-bluricon");
    }, 200);
  }

  function _cancelHide() {
     window.clearTimeout(_hideTimeout);
     window.clearTimeout(_blurIconTimeout);
  }

  function _showPieMenu() {
    window.clearTimeout(_hideTimeout);
    window.clearTimeout(_blurIconTimeout);
    if (_pieMenu) {
       var pos = _getIntentElemPos();
       _pieMenu.show();
    }
    if (_intentElem) {
      _intentElem.classList.add("livemargins-bubble-box-showpie");
      _intentElem.classList.remove("livemargins-bubble-box-bluricon");
    }
  }

  function _onMouseDownIcon(event) {
    _addMovingEventListeners();
    _isMouseDown = true;
    event.stopPropagation();
    event.preventDefault();
  }

  function _onMouseMoveIcon(event) {
    if (!_isMouseDown) {
      return;
    }
    _moveIconTo(event.pageX - _iconSize / 2, event.pageY - _iconSize / 2);
    event.stopPropagation();
    event.preventDefault();
  }

  function _onMouseUpIcon(event) {
    _isMouseDown = false;
    _onMouseUpDoc();
    event.stopPropagation();
    event.preventDefault();
  }

  function _onMouseUpDoc(event) {
    _removeMovingEventListeners();
  }

  function _addMovingEventListeners() {
    _removeMovingEventListeners();
    document.body.addEventListener("mousemove", _onMouseMoveIcon, false);
    document.body.addEventListener("mouseup", _onMouseUpDoc, false);
  }

  function _removeMovingEventListeners() {
    document.body.addEventListener("mousemove", _onMouseMoveIcon, false);
    document.body.addEventListener("mouseup", _onMouseUpDoc, false);
  }

  function _onMouseOverIcon(event) {
    if (null == _pieMenu) {
      var radius = 42;
      var options = {
        placeIn: _intentElem,
        radian: 360,
        left: _iconSize / 2,
        top: _iconSize / 2,
        radius: radius,
        items: [],
        onmousedown: function(event) {
          event.stopPropagation();
          event.preventDefault();
        },
        onmouseup: function(event) {
          event.stopPropagation();
          event.preventDefault();
        },
        onmouseout: _hidePieMenu,
        onmouseover: _cancelHide,
        onclick: function() {
          _pieMenu.hide();
        }
      };

      var intents = contentAPI.getIntents(event, this.selStr, this.selDOM);
      var i = 0;
      var self = this;
      intents.forEach(function(intent) {
        options.items.push({
           imgsrc: intent.icon,
           tooltip: intent.label,
           onclick: function() {
            let data = {
              type: this.type,
              text: self.selStr,
              html: self.selDOM,
            };

            if (document.location.href.indexOf("http") == 0) {
              data.title = document.title;
              data.href = document.location.href;
            }

            var activity = {
              action: this.action,
              message: this.message,
              href: this.href,
              data: data,
              from: "piemenu"
            };
            // duplicate all the objects that activity object referes
            // Or and permission denied exception will be thrown.
            contentAPI.startActivity(activity);
          }.bind(intent)
         });
         ++i;
      });
      _pieMenu = new PieMenu(options);
      _showPieMenu();
    } else {
      _showPieMenu();
    }
  }

  function _moveIconTo(left, top) {
    if (null == _intentElem) {
      return;
    }

    // check if body's position, if position is relative or obsolute, the position of icon should be adjusted.
    // like: http://tupian.hudong.com/99/10.html?prd=zutu_qian_auto
    let position = window.getComputedStyle(document.body).position;
    switch (position) {
    case "relative":
    case "absolute":
      left -= document.body.getBoundingClientRect().left + window.scrollX;
      top -= document.body.getBoundingClientRect().top + window.scrollY;
      break;
    }

    _intentElem.style.left = left + "px";
    _intentElem.style.top = top + "px";
  }

  function _showIntent(event, selStr, selDOM, docPos, direction, rangeRect) {
    if (!selStr) {
      return;
    }

    if (null == _intentElem) {
      _intentElem = document.createElement("div");
      _intentElem.className = "livemargins-bubble-box";

      _iconElem = document.createElement("div");
      _iconElem.className = "livemargins-bubble-icon";
      _iconElem.title = contentAPI.getString("intent.icon.title");
      _intentElem.appendChild(_iconElem);

      _iconElem.addEventListener("mousedown", _onMouseDownIcon, true);
      _iconElem.addEventListener("mouseup", _onMouseUpIcon, true);
      _iconElem.addEventListener("mouseout", _hidePieMenu, false);
       _iconElem.addEventListener("mouseover", _onMouseOverIcon, false);

       // set transform scale based on the page zoom factor.
       _handleResize();
    }
    document.body.appendChild(_intentElem);
    _intentElem.classList.remove("livemargins-bubble-box-bluricon");

    /**
     * docPos: the relative position of the owner document of the original target, from the top left corner of the document.
     */
    var elem = event.target;
    let pos = {
      left: event.pageX + docPos.left + window.scrollX - 33,
      top: event.pageY + docPos.top + window.scrollY
    };

    // Display icon align with the top of the bounding client rect of the selection.
    if (rangeRect && pos.top - (docPos.top + window.scrollY + rangeRect.top) < 20) {
      pos.top = docPos.top + window.scrollY + rangeRect.top - 38;
    } else {
      pos.top -= 46;
    }

    // Check if icon and piemenu will be shown inside the visible area
    let MIN_GAP_RIGHT_BOTTOM = 58; /* height_of_pie / 2 + height_of_icon / 2 */
    let MIN_GAP_TOP_LEFT = 26;   /* height_of_pie / 2 - height_of_icon / 2 */
    let gapLeft = pos.left - window.scrollX;
    let gapTop = pos.top - window.scrollY;
    let gapRight = window.scrollX + window.innerWidth - pos.left;
    let gapBottom = window.scrollY + window.innerHeight - pos.top;
    if (gapLeft < MIN_GAP_TOP_LEFT) {
      pos.left = window.scrollX + MIN_GAP_TOP_LEFT;
    }

    if (gapTop < MIN_GAP_RIGHT_BOTTOM) {
      pos.top = window.scrollY + MIN_GAP_TOP_LEFT;
    }

    if (gapRight < MIN_GAP_RIGHT_BOTTOM) {
      pos.left = window.scrollX + window.innerWidth - MIN_GAP_RIGHT_BOTTOM;
    }

    if (gapBottom < MIN_GAP_RIGHT_BOTTOM) {
      pos.top = window.scrollY + window.innerHeight - MIN_GAP_RIGHT_BOTTOM;
    }

    _moveIconTo(pos.left, pos.top, direction);
    _intentElem.style.display = "";
    _iconElem.selStr = selStr;
    _iconElem.selDOM = selDOM;

    // Have to set an timeout, or transition animation does not work.
    window.clearTimeout(_blurIconTimeout);
    _blurIconTimeout = window.setTimeout(function() {
      _intentElem.classList.add("livemargins-bubble-box-bluricon");
    }, 1000);
  }

  // Handle resizing event, recalculate the size of intent element.
  // Make sure intent element do not zoom in/out with the whole page.
  function _handleResize(evt) {
    if (_intentElem) {
      let zoom = contentAPI.getZoom(window);
      _intentElem.style.MozTransform = "scale("  + (1 / zoom) + ")";
    }
  }

  function _onresize(event) {
    // have to reset the scale of icon here
    _handleResize();
    // Resizing window may cause piemenu icon goes too far
    _hide(event);
  }

  window.addEventListener("resize", _onresize, false);
  window.addEventListener("unload", function() {
     window.removeEventListener("resize", _onresize, false);
  }, false);

  function _hide(evt) {
    window.clearTimeout(_blurIconTimeout);
    if (null != _intentElem) {
      _intentElem.style.display = "none";
      _intentElem.classList.remove("livemargins-bubble-box-bluricon");
      _intentElem.classList.remove("livemargins-bubble-box-showpie");
      if (_intentElem.parentNode) {
        _intentElem.parentNode.removeChild(_intentElem);
      }
    }
    if (null != _pieMenu) {
      _pieMenu.hide();
    }
  }

  return {
    /**
     * @param evt
     *  Event object
     * @param selStr
     *  selection string
     * @param selDOM
     *  selection DOM innerHTML
     * @param docPos
     *  the cordinates of document element related to the top left corner.
     * @param direction
     *  direction of mouse moving: top_left, top_right, bottom_left, bottom_right
     * @param rangeRect
     *  The bounding client rect of last selection range.
     */
    show: function(evt, selStr, selDOM, docPos, direction, rangeRect) {
      _showIntent(evt, selStr, selDOM, docPos, direction, rangeRect);
    },

    hide: function(evt) {
      _hide(evt);
    },

    rebuildPieMenu: function() {
      if (_pieMenu) {
        _pieMenu.destroy();
        _pieMenu = null;
      }
    }
  };
})();
