"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
// Utilities
var React = require("react");
var Utilities_1 = require("../../Utilities");
var Styling_1 = require("../../Styling");
var positioning_1 = require("../../utilities/positioning");
// Component Dependencies
var index_1 = require("./PositioningContainer/index");
var Beak_1 = require("./Beak/Beak");
var Coachmark_styles_1 = require("./Coachmark.styles");
var FocusTrapZone_1 = require("../FocusTrapZone");
var getClassNames = Utilities_1.classNamesFunction();
exports.COACHMARK_ATTRIBUTE_NAME = 'data-coachmarkid';
var Coachmark = /** @class */ (function (_super) {
    tslib_1.__extends(Coachmark, _super);
    function Coachmark(props) {
        var _this = _super.call(this, props) || this;
        /**
         * The cached HTMLElement reference to the Entity Inner Host
         * element.
         */
        _this._entityInnerHostElement = Utilities_1.createRef();
        _this._translateAnimationContainer = Utilities_1.createRef();
        _this._ariaAlertContainer = Utilities_1.createRef();
        _this._positioningContainer = Utilities_1.createRef();
        _this._onKeyDown = function (e) {
            // Open coachmark if user presses ALT + C (arbitrary keypress for now)
            if ((e.altKey && e.which === 67 /* c */) ||
                (e.which === 13 /* enter */ &&
                    _this._translateAnimationContainer.current &&
                    _this._translateAnimationContainer.current.contains(e.target))) {
                _this._onFocusHandler();
            }
        };
        _this._onFocusHandler = function () {
            if (_this.state.isCollapsed) {
                _this._openCoachmark();
            }
        };
        _this._onPositioned = function (positionData) {
            _this._async.requestAnimationFrame(function () {
                _this.setState({
                    targetAlignment: positionData.alignmentEdge,
                    targetPosition: positionData.targetEdge
                });
            });
        };
        _this._setBeakPosition = function () {
            var beakLeft;
            var beakTop;
            var beakRight;
            var beakBottom;
            var transformOriginX;
            var transformOriginY;
            var targetAlignment = _this.state.targetAlignment;
            var distanceAdjustment = '3px'; // Adjustment distance for Beak to shift towards Coachmark bubble.
            switch (_this._beakDirection) {
                // If Beak is pointing Up or Down
                case positioning_1.RectangleEdge.top:
                case positioning_1.RectangleEdge.bottom:
                    // If there is no target alignment, then beak is X-axis centered in callout
                    if (!targetAlignment) {
                        beakLeft = "calc(50% - " + Beak_1.BEAK_WIDTH / 2 + "px)";
                        transformOriginX = 'center';
                    }
                    else {
                        // Beak is aligned to the left of target
                        if (targetAlignment === positioning_1.RectangleEdge.left) {
                            beakLeft = Coachmark_styles_1.COACHMARK_WIDTH / 2 - Beak_1.BEAK_WIDTH / 2 + "px";
                            transformOriginX = 'left';
                        }
                        else {
                            // Beak is aligned to the right of target
                            beakRight = Coachmark_styles_1.COACHMARK_WIDTH / 2 - Beak_1.BEAK_WIDTH / 2 + "px";
                            transformOriginX = 'right';
                        }
                    }
                    if (_this._beakDirection === positioning_1.RectangleEdge.top) {
                        beakTop = distanceAdjustment;
                        transformOriginY = 'top';
                    }
                    else {
                        beakBottom = distanceAdjustment;
                        transformOriginY = 'bottom';
                    }
                    break;
                // If Beak is pointing Left or Right
                case positioning_1.RectangleEdge.left:
                case positioning_1.RectangleEdge.right:
                    // If there is no target alignment, then beak is Y-axis centered in callout
                    if (!targetAlignment) {
                        beakTop = "calc(50% - " + Beak_1.BEAK_WIDTH / 2 + "px)";
                        transformOriginY = "center";
                    }
                    else {
                        // Beak is aligned to the top of target
                        if (targetAlignment === positioning_1.RectangleEdge.top) {
                            beakTop = Coachmark_styles_1.COACHMARK_WIDTH / 2 - Beak_1.BEAK_WIDTH / 2 + "px";
                            transformOriginY = "top";
                        }
                        else {
                            // Beak is aligned to the bottom of target
                            beakBottom = Coachmark_styles_1.COACHMARK_WIDTH / 2 - Beak_1.BEAK_WIDTH / 2 + "px";
                            transformOriginY = "bottom";
                        }
                    }
                    if (_this._beakDirection === positioning_1.RectangleEdge.left) {
                        beakLeft = distanceAdjustment;
                        transformOriginX = 'left';
                    }
                    else {
                        beakRight = distanceAdjustment;
                        transformOriginX = 'right';
                    }
                    break;
            }
            _this.setState({
                beakLeft: beakLeft,
                beakRight: beakRight,
                beakBottom: beakBottom,
                beakTop: beakTop,
                transformOrigin: transformOriginX + " " + transformOriginY
            });
        };
        _this._openCoachmark = function () {
            _this.setState({
                isCollapsed: false
            });
            if (_this.props.onAnimationOpenStart) {
                _this.props.onAnimationOpenStart();
            }
            _this._entityInnerHostElement.current &&
                _this._entityInnerHostElement.current.addEventListener('transitionend', function () {
                    // Need setTimeout to trigger narrator
                    _this._async.setTimeout(function () {
                        if (_this.props.teachingBubbleRef) {
                            _this.props.teachingBubbleRef.focus();
                        }
                    }, 500);
                    if (_this.props.onAnimationOpenEnd) {
                        _this.props.onAnimationOpenEnd();
                    }
                });
        };
        // Set defaults for state
        _this.state = {
            isCollapsed: props.isCollapsed,
            isBeaconAnimating: true,
            isMeasuring: true,
            entityInnerHostRect: {
                width: 0,
                height: 0
            },
            isMouseInProximity: false
        };
        return _this;
    }
    Object.defineProperty(Coachmark.prototype, "_beakDirection", {
        get: function () {
            var targetPosition = this.state.targetPosition;
            if (targetPosition === undefined) {
                return positioning_1.RectangleEdge.bottom;
            }
            return positioning_1.getOppositeEdge(targetPosition);
        },
        enumerable: true,
        configurable: true
    });
    Coachmark.prototype.render = function () {
        var _a = this.props, children = _a.children, target = _a.target, color = _a.color, positioningContainerProps = _a.positioningContainerProps, ariaDescribedBy = _a.ariaDescribedBy, ariaDescribedByText = _a.ariaDescribedByText, ariaLabelledBy = _a.ariaLabelledBy, ariaLabelledByText = _a.ariaLabelledByText, ariaAlertText = _a.ariaAlertText;
        var _b = this.state, beakLeft = _b.beakLeft, beakTop = _b.beakTop, beakRight = _b.beakRight, beakBottom = _b.beakBottom, isCollapsed = _b.isCollapsed, isBeaconAnimating = _b.isBeaconAnimating, isMeasuring = _b.isMeasuring, entityInnerHostRect = _b.entityInnerHostRect, transformOrigin = _b.transformOrigin, alertText = _b.alertText;
        var classNames = getClassNames(Coachmark_styles_1.getStyles, {
            isCollapsed: isCollapsed,
            isBeaconAnimating: isBeaconAnimating,
            isMeasuring: isMeasuring,
            entityHostHeight: entityInnerHostRect.height + "px",
            entityHostWidth: entityInnerHostRect.width + "px",
            width: Coachmark_styles_1.COACHMARK_WIDTH + "px",
            height: Coachmark_styles_1.COACHMARK_HEIGHT + "px",
            color: color,
            transformOrigin: transformOrigin
        });
        var finalHeight = isCollapsed ? Coachmark_styles_1.COACHMARK_HEIGHT : entityInnerHostRect.height;
        return (React.createElement(index_1.PositioningContainer, tslib_1.__assign({ target: target, offsetFromTarget: Beak_1.BEAK_HEIGHT, componentRef: this._positioningContainer, finalHeight: finalHeight, onPositioned: this._onPositioned, bounds: this._getBounds() }, positioningContainerProps),
            React.createElement("div", { className: classNames.root },
                ariaAlertText && (React.createElement("div", { className: classNames.ariaContainer, role: "alert", ref: this._ariaAlertContainer, "aria-hidden": !isCollapsed }, alertText)),
                React.createElement("div", { className: classNames.pulsingBeacon }),
                React.createElement("div", { className: classNames.translateAnimationContainer, ref: this._translateAnimationContainer },
                    React.createElement("div", { className: classNames.scaleAnimationLayer },
                        React.createElement("div", { className: classNames.rotateAnimationLayer },
                            this._positioningContainer.current && (React.createElement(Beak_1.Beak, { left: beakLeft, top: beakTop, right: beakRight, bottom: beakBottom, direction: this._beakDirection, color: color })),
                            React.createElement(FocusTrapZone_1.FocusTrapZone, { isClickableOutsideFocusTrap: true },
                                React.createElement("div", { className: classNames.entityHost, tabIndex: -1, "data-is-focusable": true, role: "dialog", "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy },
                                    isCollapsed && [
                                        ariaLabelledBy && (React.createElement("p", { id: ariaLabelledBy, className: classNames.ariaContainer }, ariaLabelledByText)),
                                        ariaDescribedBy && (React.createElement("p", { id: ariaDescribedBy, className: classNames.ariaContainer }, ariaDescribedByText))
                                    ],
                                    React.createElement("div", { className: classNames.entityInnerHost, ref: this._entityInnerHostElement, "aria-hidden": isCollapsed }, children)))))))));
    };
    Coachmark.prototype.componentWillReceiveProps = function (newProps) {
        if (this.props.isCollapsed && !newProps.isCollapsed) {
            // The coachmark is about to open
            this._openCoachmark();
        }
    };
    Coachmark.prototype.shouldComponentUpdate = function (newProps, newState) {
        return !Utilities_1.shallowCompare(newProps, this.props) || !Utilities_1.shallowCompare(newState, this.state);
    };
    Coachmark.prototype.componentDidUpdate = function (prevProps, prevState) {
        if (prevState.targetAlignment !== this.state.targetAlignment ||
            prevState.targetPosition !== this.state.targetPosition) {
            this._setBeakPosition();
        }
    };
    Coachmark.prototype.componentDidMount = function () {
        var _this = this;
        this._async.requestAnimationFrame(function () {
            if (_this._entityInnerHostElement.current &&
                _this.state.entityInnerHostRect.width + _this.state.entityInnerHostRect.width === 0) {
                _this.setState({
                    isMeasuring: false,
                    entityInnerHostRect: {
                        width: _this._entityInnerHostElement.current.offsetWidth,
                        height: _this._entityInnerHostElement.current.offsetHeight
                    }
                });
                _this._setBeakPosition();
                _this.forceUpdate();
            }
            _this._events.on(document, 'keydown', _this._onKeyDown, true);
            // We dont want to the user to immediatley trigger the coachmark when it's opened
            _this._async.setTimeout(function () {
                _this._addProximityHandler(_this.props.mouseProximityOffset);
            }, _this.props.delayBeforeMouseOpen);
            // Need to add setTimeout to have narrator read change in alert container
            if (_this.props.ariaAlertText) {
                _this._async.setTimeout(function () {
                    if (_this.props.ariaAlertText && _this._ariaAlertContainer.current) {
                        _this.setState({
                            alertText: _this.props.ariaAlertText
                        });
                    }
                }, 0);
            }
        });
    };
    Coachmark.prototype.componentWillUnmount = function () {
        this._events.off(document, 'keydown', this._onKeyDown, true);
    };
    Coachmark.prototype._getBounds = function () {
        var _a = this.props, isPositionForced = _a.isPositionForced, positioningContainerProps = _a.positioningContainerProps;
        if (isPositionForced) {
            // If directionalHint direction is the top or bottom auto edge, then we want to set the left/right bounds
            // to the window x-axis to have auto positioning work correctly.
            if (positioningContainerProps &&
                (positioningContainerProps.directionalHint === 3 /* topAutoEdge */ ||
                    positioningContainerProps.directionalHint === 7 /* bottomAutoEdge */)) {
                return {
                    left: 0,
                    top: -Infinity,
                    bottom: Infinity,
                    right: window.innerWidth,
                    width: window.innerWidth,
                    height: Infinity
                };
            }
            else {
                return {
                    left: -Infinity,
                    top: -Infinity,
                    bottom: Infinity,
                    right: Infinity,
                    width: Infinity,
                    height: Infinity
                };
            }
        }
        else {
            return undefined;
        }
    };
    Coachmark.prototype._addProximityHandler = function (mouseProximityOffset) {
        var _this = this;
        if (mouseProximityOffset === void 0) { mouseProximityOffset = 0; }
        /**
         * An array of cached ids returned when setTimeout runs during
         * the window resize event trigger.
         */
        var timeoutIds = [];
        // Take the initial measure out of the initial render to prevent
        // an unnecessary render.
        this._async.setTimeout(function () {
            _this._setTargetElementRect();
            // When the window resizes we want to async
            // get the bounding client rectangle.
            // Every time the event is triggered we want to
            // setTimeout and then clear any previous instances
            // of setTimeout.
            _this._events.on(window, 'resize', function () {
                timeoutIds.forEach(function (value) {
                    clearInterval(value);
                });
                timeoutIds.push(_this._async.setTimeout(function () {
                    _this._setTargetElementRect();
                }, 100));
            });
        }, 10);
        // Every time the document's mouse move is triggered
        // we want to check if inside of an element and
        // set the state with the result.
        this._events.on(document, 'mousemove', function (e) {
            if (_this.state.isCollapsed) {
                var mouseY = e.pageY;
                var mouseX = e.pageX;
                _this._setTargetElementRect();
                var isMouseInProximity = _this._isInsideElement(mouseX, mouseY, mouseProximityOffset);
                if (isMouseInProximity !== _this.state.isMouseInProximity) {
                    _this._openCoachmark();
                }
            }
            if (_this.props.onMouseMove) {
                _this.props.onMouseMove(e);
            }
        });
    };
    Coachmark.prototype._setTargetElementRect = function () {
        if (this._translateAnimationContainer && this._translateAnimationContainer.current) {
            this._targetElementRect = this._translateAnimationContainer.current.getBoundingClientRect();
        }
    };
    Coachmark.prototype._isInsideElement = function (mouseX, mouseY, mouseProximityOffset) {
        if (mouseProximityOffset === void 0) { mouseProximityOffset = 0; }
        return (mouseX > this._targetElementRect.left - mouseProximityOffset &&
            mouseX < this._targetElementRect.left + this._targetElementRect.width + mouseProximityOffset &&
            mouseY > this._targetElementRect.top - mouseProximityOffset &&
            mouseY < this._targetElementRect.top + this._targetElementRect.height + mouseProximityOffset);
    };
    Coachmark.defaultProps = {
        isCollapsed: true,
        mouseProximityOffset: 10,
        delayBeforeMouseOpen: 3600,
        color: Styling_1.DefaultPalette.themePrimary,
        isPositionForced: true,
        positioningContainerProps: {
            directionalHint: 7 /* bottomAutoEdge */
        }
    };
    return Coachmark;
}(Utilities_1.BaseComponent));
exports.Coachmark = Coachmark;
//# sourceMappingURL=Coachmark.js.map