define(['ace/autocompletion/SymbolTooltipCompleter'], function(SymbolTooltipCompleter) {

    /**
     * The tooltip specialized for displaying prototypes.
     * @param {object} tooltipCompleter The object responsible to change the content of the tooltip.
     * @param {object} $tooltipElement The element in the html corresponding to the tooltip.
     * @param {object} editor The ace instance.
     */
    function PrototypeTooltip(tooltipCompleter, $tooltipElement, editor) {
        var _this = this;
        _this.methodOrIndexer = "";
        _this.currentSymbols = [];
        _this.currentIndex = 0;
        $tooltipElement.css('display', 'none');

        _this.close = function() {
            _this.hide();
            _this.currentSymbols = [];
            _this.currentPrototypeName = "";
        };

        _this.resetCache = function() {
            _this.close();
            _this.methodPrototypeCache = {};
            _this.indexerPrototypeCache = {};
        };

        /**
         * Display the prototype tooltip based on the given information on the symbol.
         * @param {Array} symbolInfo: A list of symbol(s for possible overload) describing what should go in the prototype tooltip.
         */
        _this.display = function(symbolInfo) {
            if (_this.currentSymbols.length > 0 && symbolInfo[0].Name === _this.currentSymbols[0].Name) {
                return;
            }
            _this.currentSymbols = symbolInfo;
            var symbolCategory = symbolInfo[0].Category;
            switch (symbolCategory) {
                case "Method":
                    _this.show(0, "method");
                    break;
                case "Property":
                    _this.show(0, "indexer");
                    break;
            };
        };


        _this.show = function(prototypeIndex, methodOrIndexer) {
            // var currentIndex = parseInt(_this.prototypeNumber()[0]) -1;
            _this.methodOrIndexer = methodOrIndexer;
            $tooltipElement.css('display', 'inline-block');
            var overloadsNumber = _this.currentSymbols.length;
            var currentSymbol = _this.currentSymbols[prototypeIndex];
            tooltipCompleter.updateInfo(currentSymbol, overloadsNumber, prototypeIndex + 1, methodOrIndexer);
            _this.setTooltipPosition();
            $tooltipElement.css('visibility', 'visible');
            editor.focus();
        };

        //Hides the tooltip.
        _this.hide = function(e) {
            $tooltipElement.css('visibility', 'hidden');
            editor.focus();
        };


        _this.switchPrototype = function(previousOrNext) {
            var overloadsNumber = _this.currentSymbols.length;
            if (previousOrNext === "previous") {
                _this.currentIndex -= 1;
            } else if (previousOrNext === "next") {
                _this.currentIndex += 1;
            }
            var newIndex = _this.currentIndex % overloadsNumber;
            if (newIndex < 0) {
                newIndex += overloadsNumber;
            }
            _this.show(newIndex, _this.methodOrIndexer);
        };


        _this.setTooltipPosition = function() {
            $tooltipElement.css('top', '0px');
            $tooltipElement.css('left', '0px');
            $tooltipElement.css('height', 'auto');
            $tooltipElement.css('width', 'auto');
            var renderer = editor.renderer;
            var cursorPixelPosition = renderer.$cursorLayer.getPixelPosition();
            var containerDimension = editor.container.getBoundingClientRect();
            var cursorLeftPosition = cursorPixelPosition.left;
            var containerWidth = containerDimension.right;
            var lineHeight = renderer.layerConfig.lineHeight;
            var tooltipWidth = $tooltipElement.width();
            var topPosition = cursorPixelPosition.top;
            var leftPosition = cursorPixelPosition.left;
            topPosition += containerDimension.top - renderer.layerConfig.offset;
            leftPosition += containerDimension.left - editor.renderer.scrollLeft;
            leftPosition += renderer.gutterWidth;
            //check available space to position the tooltip on the left, right or just besides the text.
            var isCursorAfterMiddleOfContainer = cursorLeftPosition > containerWidth / 2 ? true : false;
            if (isCursorAfterMiddleOfContainer) {
                //tooltip aligned with cursor
                if (cursorLeftPosition - tooltipWidth > 0) {
                    leftPosition = cursorLeftPosition - tooltipWidth;
                } else {
                    //tooltip attached to right side
                    leftPosition = containerWidth - tooltipWidth - 12;
                }
            } else {
                //tooltip aligned with cursor
                if (cursorLeftPosition + tooltipWidth < containerWidth) {
                    leftPosition = cursorLeftPosition;
                } else {
                    //tooltip attached to the left
                    leftPosition = 0;
                }
            }
            //Move the tooltip horizontaly first to take the word wrapping into consideration for the height.
            if (leftPosition < 0) {
                leftPosition = 0;
            }
            $tooltipElement.css("left", leftPosition);
            if (tooltipWidth >= containerWidth) {
                $tooltipElement.css('width', '100%');
            }
            //check available space to know if the tooltip must be above or below text.
            if (topPosition + lineHeight + $tooltipElement.prop("scrollHeight") + 5 > containerDimension.bottom) {
                topPosition -= $tooltipElement.prop("scrollHeight");
            } else {
                topPosition += lineHeight;
            }

            $tooltipElement.css("top", topPosition);
        };


    }


    return PrototypeTooltip;
});
