define(["require", "exports", "tslib", "../../Utilities", "./positioning.types"], function (require, exports, tslib_1, Utilities_1, positioning_types_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var Rectangle = /** @class */ (function (_super) {
        tslib_1.__extends(Rectangle, _super);
        function Rectangle() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        return Rectangle;
    }(Utilities_1.Rectangle));
    exports.Rectangle = Rectangle;
    function _createPositionData(targetEdge, alignmentEdge, isAuto) {
        return {
            targetEdge: targetEdge,
            alignmentEdge: alignmentEdge,
            isAuto: isAuto
        };
    }
    // Currently the beakPercent is set to 50 for all positions meaning that it should tend to the center of the target
    var DirectionalDictionary = (_a = {},
        _a[0 /* topLeftEdge */] = _createPositionData(positioning_types_1.RectangleEdge.top, positioning_types_1.RectangleEdge.left),
        _a[1 /* topCenter */] = _createPositionData(positioning_types_1.RectangleEdge.top),
        _a[2 /* topRightEdge */] = _createPositionData(positioning_types_1.RectangleEdge.top, positioning_types_1.RectangleEdge.right),
        _a[3 /* topAutoEdge */] = _createPositionData(positioning_types_1.RectangleEdge.top, undefined, true),
        _a[4 /* bottomLeftEdge */] = _createPositionData(positioning_types_1.RectangleEdge.bottom, positioning_types_1.RectangleEdge.left),
        _a[5 /* bottomCenter */] = _createPositionData(positioning_types_1.RectangleEdge.bottom),
        _a[6 /* bottomRightEdge */] = _createPositionData(positioning_types_1.RectangleEdge.bottom, positioning_types_1.RectangleEdge.right),
        _a[7 /* bottomAutoEdge */] = _createPositionData(positioning_types_1.RectangleEdge.bottom, undefined, true),
        _a[8 /* leftTopEdge */] = _createPositionData(positioning_types_1.RectangleEdge.left, positioning_types_1.RectangleEdge.top),
        _a[9 /* leftCenter */] = _createPositionData(positioning_types_1.RectangleEdge.left),
        _a[10 /* leftBottomEdge */] = _createPositionData(positioning_types_1.RectangleEdge.left, positioning_types_1.RectangleEdge.bottom),
        _a[11 /* rightTopEdge */] = _createPositionData(positioning_types_1.RectangleEdge.right, positioning_types_1.RectangleEdge.top),
        _a[12 /* rightCenter */] = _createPositionData(positioning_types_1.RectangleEdge.right),
        _a[13 /* rightBottomEdge */] = _createPositionData(positioning_types_1.RectangleEdge.right, positioning_types_1.RectangleEdge.bottom),
        _a);
    /**
     * @deprecated will be removed in 6.0.
     */
    var SLIDE_ANIMATIONS = (_b = {},
        _b[positioning_types_1.RectangleEdge.top] = 'slideUpIn20',
        _b[positioning_types_1.RectangleEdge.bottom] = 'slideDownIn20',
        _b[positioning_types_1.RectangleEdge.left] = 'slideLeftIn20',
        _b[positioning_types_1.RectangleEdge.right] = 'slideRightIn20',
        _b);
    /**
     * Do not call methods from this directly, use either positionCallout or positionElement or make another function that
     * utilizes them.
     */
    var positioningFunctions;
    (function (positioningFunctions) {
        function _isRectangleWithinBounds(rect, boundingRect) {
            if (rect.top < boundingRect.top) {
                return false;
            }
            if (rect.bottom > boundingRect.bottom) {
                return false;
            }
            if (rect.left < boundingRect.left) {
                return false;
            }
            if (rect.right > boundingRect.right) {
                return false;
            }
            return true;
        }
        /**
         * Gets all of the edges of a rectangle that are outside of the given bounds.
         * If there are no out of bounds edges it returns an empty array.
         */
        function _getOutOfBoundsEdges(rect, boundingRect) {
            var outOfBounds = new Array();
            if (rect.top < boundingRect.top) {
                outOfBounds.push(positioning_types_1.RectangleEdge.top);
            }
            if (rect.bottom > boundingRect.bottom) {
                outOfBounds.push(positioning_types_1.RectangleEdge.bottom);
            }
            if (rect.left < boundingRect.left) {
                outOfBounds.push(positioning_types_1.RectangleEdge.left);
            }
            if (rect.right > boundingRect.right) {
                outOfBounds.push(positioning_types_1.RectangleEdge.right);
            }
            return outOfBounds;
        }
        function _getEdgeValue(rect, edge) {
            return rect[positioning_types_1.RectangleEdge[edge]];
        }
        function _setEdgeValue(rect, edge, value) {
            rect[positioning_types_1.RectangleEdge[edge]] = value;
            return rect;
        }
        /**
         * Returns the middle value of an edge. Only returns 1 value rather than xy coordinates as
         * the itself already contains the other coordinate.
         * For instance, a bottom edge's current value is it's y coordinate, so the number returned is the x.
         *
         * @param {Rectangle} rect
         * @param {RectangleEdge} edge
         * @returns {number}
         */
        function _getCenterValue(rect, edge) {
            var edges = _getFlankingEdges(edge);
            return (_getEdgeValue(rect, edges.positiveEdge) + _getEdgeValue(rect, edges.negativeEdge)) / 2;
        }
        /**
         * Flips the value depending on the edge.
         * If the edge is a "positive" edge, Top or Left, then the value should stay as it is.
         * If the edge is a "negative" edge, Bottom or Right, then the value should be flipped.
         * This is to account for the fact that the coordinates are effectively reveserved in certain cases for the "negative" edges.
         * For example, when testing to see if a bottom edge 1 is within the bounds of another bottom edge 2.
         * If edge 1 is greater than edge 2 then it is out of bounds. This is reversed for top edge 1 and top edge 2.
         * If top edge 1 is less than edge 2 then it is out of bounds.
         *
         *
         * @param {RectangleEdge} edge
         * @param {number} value
         * @returns {number}
         */
        function _getRelativeEdgeValue(edge, value) {
            if (edge > 0) {
                return value;
            }
            else {
                return value * -1;
            }
        }
        function _getRelativeRectEdgeValue(edge, rect) {
            return _getRelativeEdgeValue(edge, _getEdgeValue(rect, edge));
        }
        function _getRelativeEdgeDifference(rect, hostRect, edge) {
            var edgeDifference = _getEdgeValue(rect, edge) - _getEdgeValue(hostRect, edge);
            return _getRelativeEdgeValue(edge, edgeDifference);
        }
        /**
         * Moves the edge of a rectangle to the value given. It only moves the edge in a linear direction based on that edge.
         * For example, if it's a bottom edge it will only change y coordinates.
         *
         * @param {Rectangle} rect
         * @param {RectangleEdge} edge
         * @param {number} newValue
         * @returns {Rectangle}
         */
        function _moveEdge(rect, edge, newValue) {
            var difference = _getEdgeValue(rect, edge) - newValue;
            rect = _setEdgeValue(rect, edge, newValue);
            rect = _setEdgeValue(rect, edge * -1, _getEdgeValue(rect, edge * -1) - difference);
            return rect;
        }
        /**
         * Aligns the edge on the passed in rect to the target. If there is a gap then it will have that space between the two.
         *
         * @param {Rectangle} rect
         * @param {Rectangle} target
         * @param {RectangleEdge} edge
         * @param {number} [gap=0]
         * @returns {Rectangle}
         */
        function _alignEdges(rect, target, edge, gap) {
            if (gap === void 0) { gap = 0; }
            return _moveEdge(rect, edge, _getEdgeValue(target, edge) + _getRelativeEdgeValue(edge, gap));
        }
        /**
         * Aligns the targetEdge on the passed in target to the rects corresponding opposite edge.
         * For instance if targetEdge is bottom, then the rects top will be moved to match it.
         *
         * @param {Rectangle} rect
         * @param {Rectangle} target
         * @param {RectangleEdge} targetEdge
         * @param {number} [gap=0]
         * @returns {Rectangle}
         */
        function _alignOppositeEdges(rect, target, targetEdge, gap) {
            if (gap === void 0) { gap = 0; }
            var oppositeEdge = targetEdge * -1;
            var adjustedGap = _getRelativeEdgeValue(oppositeEdge, gap);
            return _moveEdge(rect, targetEdge * -1, _getEdgeValue(target, targetEdge) + adjustedGap);
        }
        /**
         * Tests to see if the given edge is within the bounds of the given rectangle.
         *
         * @param {Rectangle} rect
         * @param {Rectangle} bounds
         * @param {RectangleEdge} edge
         * @returns {boolean}
         */
        function _isEdgeInBounds(rect, bounds, edge) {
            var adjustedRectValue = _getRelativeRectEdgeValue(edge, rect);
            return adjustedRectValue > _getRelativeRectEdgeValue(edge, bounds);
        }
        /**
         * Attempts to move the rectangle through various sides of the target to find a place to fit.
         * If no fit is found, the original position should be returned.
         *
         * @param {Rectangle} rect
         * @param {Rectangle} target
         * @param {Rectangle} bounding
         * @param {IPositionDirectionalHintData} positionData
         * @param {number} [gap=0]
         * @returns {IElementPosition}
         */
        function _flipToFit(rect, target, bounding, positionData, gap) {
            if (gap === void 0) { gap = 0; }
            var directions = [positioning_types_1.RectangleEdge.left, positioning_types_1.RectangleEdge.right, positioning_types_1.RectangleEdge.bottom, positioning_types_1.RectangleEdge.top];
            var currentEstimate = rect;
            var currentEdge = positionData.targetEdge;
            var currentAlignment = positionData.alignmentEdge;
            // Keep switching sides until one is found with enough space. If all sides don't fit then return the unmodified element.
            for (var i = 0; i < 4; i++) {
                if (!_isEdgeInBounds(currentEstimate, bounding, currentEdge)) {
                    directions.splice(directions.indexOf(currentEdge), 1);
                    if (directions.indexOf(currentEdge * -1) > -1) {
                        currentEdge = currentEdge * -1;
                    }
                    else {
                        currentAlignment = currentEdge;
                        currentEdge = directions.slice(-1)[0];
                    }
                    currentEstimate = _estimatePosition(rect, target, { targetEdge: currentEdge, alignmentEdge: currentAlignment }, gap);
                }
                else {
                    return {
                        elementRectangle: currentEstimate,
                        targetEdge: currentEdge,
                        alignmentEdge: currentAlignment
                    };
                }
            }
            return {
                elementRectangle: rect,
                targetEdge: positionData.targetEdge,
                alignmentEdge: currentAlignment
            };
        }
        /**
         * Adjusts a element rectangle to fit within the bounds given. If directionalHintFixed or covertarget is passed in
         * then the element will not flip sides on the target. They will, however, be nudged to fit within the bounds given.
         *
         * @param {Rectangle} element
         * @param {Rectangle} target
         * @param {Rectangle} bounding
         * @param {IPositionDirectionalHintData} positionData
         * @param {number} [gap=0]
         * @param {boolean} [directionalHintFixed]
         * @param {boolean} [coverTarget]
         * @returns {IElementPosition}
         */
        function _adjustFitWithinBounds(element, target, bounding, positionData, gap, directionalHintFixed, coverTarget) {
            if (gap === void 0) { gap = 0; }
            var alignmentEdge = positionData.alignmentEdge;
            var elementEstimate = {
                elementRectangle: element,
                targetEdge: positionData.targetEdge,
                alignmentEdge: alignmentEdge
            };
            if (!directionalHintFixed && !coverTarget) {
                elementEstimate = _flipToFit(element, target, bounding, positionData, gap);
            }
            var outOfBounds = _getOutOfBoundsEdges(element, bounding);
            for (var _i = 0, outOfBounds_1 = outOfBounds; _i < outOfBounds_1.length; _i++) {
                var direction = outOfBounds_1[_i];
                elementEstimate.elementRectangle = _alignEdges(elementEstimate.elementRectangle, bounding, direction);
            }
            return elementEstimate;
        }
        /**
         * Moves the middle point on an edge to the point given.
         * Only moves in one direction. For instance if a bottom edge is passed in, then
         * the bottom edge will be moved in the x axis to match the point.
         *
         * @param {Rectangle} rect
         * @param {RectangleEdge} edge
         * @param {number} point
         * @returns {Rectangle}
         */
        function _centerEdgeToPoint(rect, edge, point) {
            var positiveEdge = _getFlankingEdges(edge).positiveEdge;
            var elementMiddle = _getCenterValue(rect, edge);
            var distanceToMiddle = elementMiddle - _getEdgeValue(rect, positiveEdge);
            return _moveEdge(rect, positiveEdge, point - distanceToMiddle);
        }
        /**
         * Moves the element rectangle to be appropriately positioned relative to a given target.
         * Does not flip or adjust the element.
         *
         * @param {Rectangle} elementToPosition
         * @param {Rectangle} target
         * @param {IPositionDirectionalHintData} positionData
         * @param {number} [gap=0]
         * @param {boolean} [coverTarget]
         * @returns {Rectangle}
         */
        function _estimatePosition(elementToPosition, target, positionData, gap, coverTarget) {
            if (gap === void 0) { gap = 0; }
            var estimatedElementPosition;
            var alignmentEdge = positionData.alignmentEdge, targetEdge = positionData.targetEdge;
            var elementEdge = coverTarget ? targetEdge : targetEdge * -1;
            estimatedElementPosition = coverTarget ? _alignEdges(elementToPosition, target, targetEdge, gap) :
                _alignOppositeEdges(elementToPosition, target, targetEdge, gap);
            // if no alignment edge is provided it's supposed to be centered.
            if (!alignmentEdge) {
                var targetMiddlePoint = _getCenterValue(target, targetEdge);
                estimatedElementPosition = _centerEdgeToPoint(estimatedElementPosition, elementEdge, targetMiddlePoint);
            }
            else {
                estimatedElementPosition = _alignEdges(estimatedElementPosition, target, alignmentEdge);
            }
            return estimatedElementPosition;
        }
        /**
         * Returns the non-opposite edges of the target edge.
         * For instance if bottom is passed in then left and right will be returned.
         *
         * @param {RectangleEdge} edge
         * @returns {{ firstEdge: RectangleEdge, secondEdge: RectangleEdge }}
         */
        function _getFlankingEdges(edge) {
            if (edge === positioning_types_1.RectangleEdge.top || edge === positioning_types_1.RectangleEdge.bottom) {
                return {
                    positiveEdge: positioning_types_1.RectangleEdge.left,
                    negativeEdge: positioning_types_1.RectangleEdge.right
                };
            }
            else {
                return {
                    positiveEdge: positioning_types_1.RectangleEdge.top,
                    negativeEdge: positioning_types_1.RectangleEdge.bottom
                };
            }
        }
        /**
         * Finalizes the element positon based on the hostElement. Only returns the
         * rectangle values to position such that they are anchored to the target.
         * This helps prevent resizing from looking very strange.
         * For instance, if the target edge is top and aligned with the left side then
         * the bottom and left values are returned so as the callou shrinks it shrinks towards that corner.
         *
         * @param {Rectangle} elementRectangle
         * @param {HTMLElement} hostElement
         * @param {RectangleEdge} targetEdge
         * @param {RectangleEdge} [alignmentEdge]
         * @returns {IPartialIRectangle}
         */
        function _finalizeElementPosition(elementRectangle, hostElement, targetEdge, alignmentEdge) {
            var returnValue = {};
            var hostRect = _getRectangleFromHTMLElement(hostElement);
            var elementEdge = targetEdge * -1;
            var elementEdgeString = positioning_types_1.RectangleEdge[elementEdge];
            var returnEdge = alignmentEdge ? alignmentEdge : _getFlankingEdges(targetEdge).positiveEdge;
            returnValue[elementEdgeString] = _getRelativeEdgeDifference(elementRectangle, hostRect, elementEdge);
            returnValue[positioning_types_1.RectangleEdge[returnEdge]] = _getRelativeEdgeDifference(elementRectangle, hostRect, returnEdge);
            return returnValue;
        }
        // Since the beak is rotated 45 degrees the actual height/width is the length of the diagonal.
        // We still want to position the beak based on it's midpoint which does not change. It will
        // be at (beakwidth / 2, beakwidth / 2)
        function _calculateActualBeakWidthInPixels(beakWidth) {
            return Math.sqrt(beakWidth * beakWidth * 2);
        }
        positioningFunctions._calculateActualBeakWidthInPixels = _calculateActualBeakWidthInPixels;
        /**
         * Returns the appropriate IPositionData based on the props altered for RTL.
         * If directionalHintForRTL is passed in that is used if the page is RTL.
         * If a directionalHint is specified and no directionalHintForRTL is available and the page is RTL the hint will be flipped.
         * For instance bottomLeftEdge would become bottomRightEdge.
         * If there is no directionalHint passed in bottomAutoEdge is chosen automatically.
         *
         * @param {IPositionProps} props
         * @returns {IPositionDirectionalHintData}
         */
        function _getPositionData(directionalHint, directionalHintForRTL) {
            if (directionalHint === void 0) { directionalHint = 7 /* bottomAutoEdge */; }
            var positionInformation = tslib_1.__assign({}, DirectionalDictionary[directionalHint]);
            if (Utilities_1.getRTL()) {
                // If alignment edge exists and that alignment edge is -2 or 2, right or left, then flip it.
                positionInformation.alignmentEdge = positionInformation.alignmentEdge && positionInformation.alignmentEdge % 2 === 0
                    ? positionInformation.alignmentEdge * -1 : undefined;
                return directionalHintForRTL !== undefined ?
                    DirectionalDictionary[directionalHintForRTL] :
                    positionInformation;
            }
            return positionInformation;
        }
        positioningFunctions._getPositionData = _getPositionData;
        /**
         * Get's the alignment data for the given information. This only really matters if the positioning is Auto.
         * If it is auto then the alignmentEdge should be chosen based on the target edge's position relative to
         * the center of the page.
         *
         * @param {IPositionDirectionalHintData} positionData
         * @param {Rectangle} target
         * @param {Rectangle} boundingRect
         * @param {boolean} [coverTarget]
         * @returns {IPositionDirectionalHintData}
         */
        function _getAlignmentData(positionData, target, boundingRect, coverTarget) {
            if (positionData.isAuto) {
                positionData.alignmentEdge = getClosestEdge(positionData.targetEdge, target, boundingRect);
            }
            return positionData;
        }
        function getClosestEdge(targetEdge, target, boundingRect) {
            var targetCenter = _getCenterValue(target, targetEdge);
            var boundingCenter = _getCenterValue(boundingRect, targetEdge);
            var _a = _getFlankingEdges(targetEdge), positiveEdge = _a.positiveEdge, negativeEdge = _a.negativeEdge;
            if (targetCenter <= boundingCenter) {
                return positiveEdge;
            }
            else {
                return negativeEdge;
            }
        }
        function _positionElementWithinBounds(elementToPosition, target, bounding, positionData, gap, directionalHintFixed, coverTarget) {
            var estimatedElementPosition = _estimatePosition(elementToPosition, target, positionData, gap, coverTarget);
            if (_isRectangleWithinBounds(estimatedElementPosition, bounding)) {
                return {
                    elementRectangle: estimatedElementPosition,
                    targetEdge: positionData.targetEdge,
                    alignmentEdge: positionData.alignmentEdge
                };
            }
            else {
                return _adjustFitWithinBounds(elementToPosition, target, bounding, positionData, gap, directionalHintFixed, coverTarget);
            }
        }
        positioningFunctions._positionElementWithinBounds = _positionElementWithinBounds;
        function _finalizeBeakPosition(elementPosition, positionedBeak) {
            var targetEdge = elementPosition.targetEdge * -1;
            // The "host" element that we will use to help position the beak.
            var actualElement = new Rectangle(0, elementPosition.elementRectangle.width, 0, elementPosition.elementRectangle.height);
            var returnEdge = elementPosition.alignmentEdge ? elementPosition.alignmentEdge : _getFlankingEdges(targetEdge).positiveEdge;
            var returnValue = {};
            returnValue[positioning_types_1.RectangleEdge[targetEdge]] = _getEdgeValue(positionedBeak, targetEdge);
            returnValue[positioning_types_1.RectangleEdge[returnEdge]] = _getRelativeEdgeDifference(positionedBeak, actualElement, returnEdge);
            return {
                elementPosition: tslib_1.__assign({}, returnValue),
                closestEdge: getClosestEdge(elementPosition.targetEdge, positionedBeak, actualElement),
                targetEdge: targetEdge
            };
        }
        positioningFunctions._finalizeBeakPosition = _finalizeBeakPosition;
        function _positionBeak(beakWidth, elementPosition) {
            var target = elementPosition.targetRectangle;
            /** Note about beak positioning: The actual beak width only matters for getting the gap between the callout and target, it does not impact the beak placement within the callout. For example example, if the beakWidth is 8, then the actual beakWidth is sqrroot(8^2 + 8^2) = 11.31x11.31. So the callout will need to be an extra 3 pixels away from its target. While the beak is being positioned in the callout it still acts as though it were 8x8.*/
            var _a = _getFlankingEdges(elementPosition.targetEdge), positiveEdge = _a.positiveEdge, negativeEdge = _a.negativeEdge;
            var beakTargetPoint = _getCenterValue(target, elementPosition.targetEdge);
            var elementBounds = new Rectangle(beakWidth / 2, elementPosition.elementRectangle.width - beakWidth / 2, beakWidth / 2, elementPosition.elementRectangle.height - beakWidth / 2);
            var beakPositon = new Rectangle(0, beakWidth, 0, beakWidth);
            beakPositon = _moveEdge(beakPositon, (elementPosition.targetEdge * -1), -beakWidth / 2);
            beakPositon = _centerEdgeToPoint(beakPositon, elementPosition.targetEdge * -1, beakTargetPoint - _getRelativeRectEdgeValue(positiveEdge, elementPosition.elementRectangle));
            if (!_isEdgeInBounds(beakPositon, elementBounds, positiveEdge)) {
                beakPositon = _alignEdges(beakPositon, elementBounds, positiveEdge);
            }
            else if (!_isEdgeInBounds(beakPositon, elementBounds, negativeEdge)) {
                beakPositon = _alignEdges(beakPositon, elementBounds, negativeEdge);
            }
            return beakPositon;
        }
        positioningFunctions._positionBeak = _positionBeak;
        function _getRectangleFromHTMLElement(element) {
            var clientRect = element.getBoundingClientRect();
            return new Rectangle(clientRect.left, clientRect.right, clientRect.top, clientRect.bottom);
        }
        positioningFunctions._getRectangleFromHTMLElement = _getRectangleFromHTMLElement;
        function _getRectangleFromIRect(rect) {
            return new Rectangle(rect.left, rect.right, rect.top, rect.bottom);
        }
        positioningFunctions._getRectangleFromIRect = _getRectangleFromIRect;
        function _getTargetRect(bounds, target) {
            var targetRectangle;
            if (target) {
                if (target.preventDefault) {
                    var ev = target;
                    targetRectangle = new Rectangle(ev.clientX, ev.clientX, ev.clientY, ev.clientY);
                }
                else if (target.getBoundingClientRect) {
                    targetRectangle = _getRectangleFromHTMLElement(target);
                    // HTMLImgElements can have x and y values. The check for it being a point must go last.
                }
                else {
                    var point = target;
                    targetRectangle = new Rectangle(point.x, point.x, point.y, point.y);
                }
                if (!_isRectangleWithinBounds(targetRectangle, bounds)) {
                    var outOfBounds = _getOutOfBoundsEdges(targetRectangle, bounds);
                    for (var _i = 0, outOfBounds_2 = outOfBounds; _i < outOfBounds_2.length; _i++) {
                        var direction = outOfBounds_2[_i];
                        targetRectangle[positioning_types_1.RectangleEdge[direction]] = bounds[positioning_types_1.RectangleEdge[direction]];
                    }
                }
            }
            else {
                targetRectangle = new Rectangle(0, 0, 0, 0);
            }
            return targetRectangle;
        }
        positioningFunctions._getTargetRect = _getTargetRect;
        /**
         * If max height is less than zero it returns the bounds height instead.
         */
        function _getMaxHeightFromTargetRectangle(targetRectangle, targetEdge, gapSpace, bounds) {
            var maxHeight = 0;
            switch (targetEdge) {
                case 7 /* bottomAutoEdge */:
                case 5 /* bottomCenter */:
                case 4 /* bottomLeftEdge */:
                case 6 /* bottomRightEdge */:
                    maxHeight = bounds.bottom - targetRectangle.bottom - gapSpace;
                    break;
                case 3 /* topAutoEdge */:
                case 1 /* topCenter */:
                case 0 /* topLeftEdge */:
                case 2 /* topRightEdge */:
                    maxHeight = targetRectangle.top - bounds.top - gapSpace;
                    break;
                default:
                    maxHeight = bounds.bottom - targetRectangle.top - gapSpace;
                    break;
            }
            return maxHeight > 0 ? maxHeight : bounds.height;
        }
        positioningFunctions._getMaxHeightFromTargetRectangle = _getMaxHeightFromTargetRectangle;
        function _positionElementRelative(props, hostElement, elementToPosition) {
            var gap = props.gapSpace ? props.gapSpace : 0;
            var boundingRect = props.bounds ?
                _getRectangleFromIRect(props.bounds) :
                new Rectangle(0, window.innerWidth - Utilities_1.getScrollbarWidth(), 0, window.innerHeight);
            var targetRect = _getTargetRect(boundingRect, props.target);
            var positionData = _getAlignmentData(_getPositionData(props.directionalHint, props.directionalHintForRTL), targetRect, boundingRect, props.coverTarget);
            var positionedElement = _positionElementWithinBounds(_getRectangleFromHTMLElement(elementToPosition), targetRect, boundingRect, positionData, gap, props.directionalHintFixed, props.coverTarget);
            return tslib_1.__assign({}, positionedElement, { targetRectangle: targetRect });
        }
        positioningFunctions._positionElementRelative = _positionElementRelative;
        function _finalizePositionData(positionedElement, hostElement) {
            var finalizedElement = _finalizeElementPosition(positionedElement.elementRectangle, hostElement, positionedElement.targetEdge, positionedElement.alignmentEdge);
            return {
                elementPosition: finalizedElement,
                targetEdge: positionedElement.targetEdge
            };
        }
        positioningFunctions._finalizePositionData = _finalizePositionData;
        function _positionElement(props, hostElement, elementToPosition) {
            var positionedElement = _positionElementRelative(props, hostElement, elementToPosition);
            return _finalizePositionData(positionedElement, hostElement);
        }
        positioningFunctions._positionElement = _positionElement;
        function _positionCallout(props, hostElement, callout) {
            var beakWidth = !props.isBeakVisible ? 0 : (props.beakWidth || 0);
            var gap = _calculateActualBeakWidthInPixels(beakWidth) / 2 + (props.gapSpace ? props.gapSpace : 0);
            var positionProps = props;
            positionProps.gapSpace = gap;
            var positionedElement = _positionElementRelative(positionProps, hostElement, callout);
            var beakPositioned = _positionBeak(beakWidth, positionedElement);
            var finalizedBeakPosition = _finalizeBeakPosition(positionedElement, beakPositioned);
            return tslib_1.__assign({}, _finalizePositionData(positionedElement, hostElement), { beakPosition: finalizedBeakPosition });
        }
        positioningFunctions._positionCallout = _positionCallout;
        /**
         * @deprecated Do not use, this will be removed in 6.0
         * use either _positionCallout or _positionElement.
         * @export
         * @param {IPositionProps} props
         * @param {HTMLElement} hostElement
         * @param {HTMLElement} elementToPosition
         * @returns
         */
        function _getRelativePositions(props, hostElement, elementToPosition) {
            var positions = _positionCallout(props, hostElement, elementToPosition);
            var beakPosition = positions && positions.beakPosition ? positions.beakPosition.elementPosition : undefined;
            return {
                calloutPosition: positions.elementPosition,
                beakPosition: { position: tslib_1.__assign({}, beakPosition), display: 'block' },
                directionalClassName: SLIDE_ANIMATIONS[positions.targetEdge],
                submenuDirection: (positions.targetEdge * -1) === positioning_types_1.RectangleEdge.right ? 10 /* leftBottomEdge */ : 13 /* rightBottomEdge */
            };
        }
        positioningFunctions._getRelativePositions = _getRelativePositions;
    })(positioningFunctions = exports.positioningFunctions || (exports.positioningFunctions = {}));
    /**
     * @deprecated Do not use, this will be removed in 6.0.
     * Use either positionElement, or positionCallout
     *
     * @export
     * @param {IPositionProps} props
     * @param {HTMLElement} hostElement
     * @param {HTMLElement} calloutElement
     * @returns
     */
    function getRelativePositions(props, hostElement, calloutElement) {
        return positioningFunctions._getRelativePositions(props, hostElement, calloutElement);
    }
    exports.getRelativePositions = getRelativePositions;
    /**
     * Used to position an element relative to the given positioning props.
     *
     * @export
     * @param {IPositionProps} props
     * @param {HTMLElement} hostElement
     * @param {HTMLElement} elementToPosition
     * @returns
     */
    function positionElement(props, hostElement, elementToPosition) {
        return positioningFunctions._positionElement(props, hostElement, elementToPosition);
    }
    exports.positionElement = positionElement;
    function positionCallout(props, hostElement, elementToPosition) {
        return positioningFunctions._positionCallout(props, hostElement, elementToPosition);
    }
    exports.positionCallout = positionCallout;
    /**
     * Get's the maximum height that a rectangle can have in order to fit below or above a target.
     * If the directional hint specifies a left or right edge (i.e. leftCenter) it will limit the height to the topBorder
     * of the target given.
     * If no bounds are provided then the window is treated as the bounds.
     */
    function getMaxHeight(target, targetEdge, gapSpace, bounds) {
        if (gapSpace === void 0) { gapSpace = 0; }
        var mouseTarget = target;
        var elementTarget = target;
        var pointTarget = target;
        var targetRect;
        var boundingRectangle = bounds ?
            positioningFunctions._getRectangleFromIRect(bounds) :
            new Rectangle(0, window.innerWidth - Utilities_1.getScrollbarWidth(), 0, window.innerHeight);
        if (mouseTarget.stopPropagation) {
            targetRect = new Rectangle(mouseTarget.clientX, mouseTarget.clientX, mouseTarget.clientY, mouseTarget.clientY);
        }
        else if (pointTarget.x !== undefined && pointTarget.y !== undefined) {
            targetRect = new Rectangle(pointTarget.x, pointTarget.x, pointTarget.y, pointTarget.y);
        }
        else {
            targetRect = positioningFunctions._getRectangleFromHTMLElement(elementTarget);
        }
        return positioningFunctions._getMaxHeightFromTargetRectangle(targetRect, targetEdge, gapSpace, boundingRectangle);
    }
    exports.getMaxHeight = getMaxHeight;
    var _a, _b;
});
//# sourceMappingURL=positioning.js.map