import * as tslib_1 from "tslib";
// Utilities
import * as React from 'react';
import { BaseComponent, classNamesFunction, createRef, shallowCompare } from '../../Utilities';
import { DefaultPalette } from '../../Styling';
import { RectangleEdge, getOppositeEdge } from 'office-ui-fabric-react/lib/utilities/positioning';
// Component Dependencies
import { PositioningContainer } from './PositioningContainer/index';
import { Beak, BEAK_HEIGHT, BEAK_WIDTH } from './Beak/Beak';
import { COACHMARK_HEIGHT, COACHMARK_WIDTH, getStyles } from './Coachmark.styles';
import { FocusZone } from '../../FocusZone';
var getClassNames = classNamesFunction();
export var 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 = createRef();
        _this._translateAnimationContainer = createRef();
        _this._positioningContainer = createRef();
        _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 RectangleEdge.top:
                case RectangleEdge.bottom:
                    // If there is no target alignment, then beak is X-axis centered in callout
                    if (!targetAlignment) {
                        beakLeft = "calc(50% - " + BEAK_WIDTH / 2 + "px)";
                        transformOriginX = 'center';
                    }
                    else {
                        // Beak is aligned to the left of target
                        if (targetAlignment === RectangleEdge.left) {
                            beakLeft = COACHMARK_WIDTH / 2 - BEAK_WIDTH / 2 + "px";
                            transformOriginX = 'left';
                        }
                        else {
                            // Beak is aligned to the right of target
                            beakRight = COACHMARK_WIDTH / 2 - BEAK_WIDTH / 2 + "px";
                            transformOriginX = 'right';
                        }
                    }
                    if (_this._beakDirection === RectangleEdge.top) {
                        beakTop = distanceAdjustment;
                        transformOriginY = 'top';
                    }
                    else {
                        beakBottom = distanceAdjustment;
                        transformOriginY = 'bottom';
                    }
                    break;
                // If Beak is pointing Left or Right
                case RectangleEdge.left:
                case RectangleEdge.right:
                    // If there is no target alignment, then beak is Y-axis centered in callout
                    if (!targetAlignment) {
                        beakTop = "calc(50% - " + BEAK_WIDTH / 2 + "px)";
                        transformOriginY = "center";
                    }
                    else {
                        // Beak is aligned to the top of target
                        if (targetAlignment === RectangleEdge.top) {
                            beakTop = COACHMARK_WIDTH / 2 - BEAK_WIDTH / 2 + "px";
                            transformOriginY = "top";
                        }
                        else {
                            // Beak is aligned to the bottom of target
                            beakBottom = COACHMARK_WIDTH / 2 - BEAK_WIDTH / 2 + "px";
                            transformOriginY = "bottom";
                        }
                    }
                    if (_this._beakDirection === 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 () {
                    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 RectangleEdge.bottom;
            }
            return 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;
        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;
        var classNames = getClassNames(getStyles, {
            isCollapsed: isCollapsed,
            isBeaconAnimating: isBeaconAnimating,
            isMeasuring: isMeasuring,
            entityHostHeight: entityInnerHostRect.height + "px",
            entityHostWidth: entityInnerHostRect.width + "px",
            width: COACHMARK_WIDTH + "px",
            height: COACHMARK_HEIGHT + "px",
            color: color,
            transformOrigin: transformOrigin
        });
        var finalHeight = isCollapsed ? COACHMARK_HEIGHT : entityInnerHostRect.height;
        return (React.createElement(PositioningContainer, tslib_1.__assign({ target: target, offsetFromTarget: BEAK_HEIGHT, componentRef: this._positioningContainer, finalHeight: finalHeight, onPositioned: this._onPositioned, bounds: this._getBounds() }, positioningContainerProps),
            React.createElement("div", { className: classNames.root },
                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, { left: beakLeft, top: beakTop, right: beakRight, bottom: beakBottom, direction: this._beakDirection, color: color })),
                            React.createElement(FocusZone, null,
                                React.createElement("div", { className: classNames.entityHost, "data-is-focusable": true, onFocus: this._onFocusHandler },
                                    React.createElement("div", { className: classNames.entityInnerHost, ref: this._entityInnerHostElement }, 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 !shallowCompare(newProps, this.props) || !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();
            }
            // 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);
        });
    };
    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: DefaultPalette.themePrimary,
        isPositionForced: true,
        positioningContainerProps: {
            directionalHint: 7 /* bottomAutoEdge */
        }
    };
    return Coachmark;
}(BaseComponent));
export { Coachmark };
//# sourceMappingURL=Coachmark.js.map