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); 
            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
                        };
                        
                        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(JSON.parse(JSON.stringify(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, 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;
        
        // 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 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, docPos, direction, rangeRect) {
            _showIntent(evt, selStr, docPos, direction, rangeRect);
        },
        
        hide: function(evt) {
            _hide(evt);
        },
        
        rebuildPieMenu: function() {
            if (_pieMenu) {
                _pieMenu.destroy();
                _pieMenu = null;
            }
        }
    };
})();