"use strict";
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
    if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
    return cooked;
};
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __spreadArrays = (this && this.__spreadArrays) || function () {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = __importStar(require("react"));
var styled_components_1 = __importStar(require("styled-components"));
var Child_1 = __importDefault(require("./Child"));
var util_1 = require("./util");
var Container = styled_components_1.default.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n  position: relative;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  flex-wrap: nowrap;\n"], ["\n  position: relative;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  flex-wrap: nowrap;\n"])));
var marqueeAnimRtl = styled_components_1.keyframes(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n  0% {\n    transform: translate(0, 0);\n  }\n\n  100% {\n    transform: translate(-100%, 0);\n  }\n"], ["\n  0% {\n    transform: translate(0, 0);\n  }\n\n  100% {\n    transform: translate(-100%, 0);\n  }\n"])));
var marqueeAnimLtr = styled_components_1.keyframes(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n  0% {\n    transform: translate(0, 0);\n  }\n\n  100% {\n    transform: translate(100%, 0);\n  }\n"], ["\n  0% {\n    transform: translate(0, 0);\n  }\n\n  100% {\n    transform: translate(100%, 0);\n  }\n"])));
var __safePerformanceNow = function () {
    if (typeof window !== "undefined" && window !== undefined) {
        return performance.now();
    }
    return 0;
};
var Mirror = styled_components_1.default.div(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n  min-width: 100%;\n  flex-shrink: 0;\n  animation: ", " linear\n    infinite;\n"], ["\n  min-width: 100%;\n  flex-shrink: 0;\n  animation: ", " linear\n    infinite;\n"])), function (props) { return (props.direction === "rtl" ? marqueeAnimRtl : marqueeAnimLtr); });
var NESTED_UPDATE_LIMIT = 50;
var Marquee = function (_a) {
    var children = _a.children, direction = _a.direction, velocity = _a.velocity, scatterRandomly = _a.scatterRandomly, resetAfterTries = _a.resetAfterTries, onFinish = _a.onFinish, debug = _a.debug;
    var _b = react_1.useState(0), retryAfterExceedingUpdateDepthTrigger = _b[0], setRetryAfterExceedingUpdateDepthTrigger = _b[1];
    var _c = react_1.useState(0), animationDuration = _c[0], setAnimationDuration = _c[1];
    var _d = react_1.useState(0), nestedUpdateCount = _d[0], setNestedUpdateCount = _d[1];
    var _e = react_1.useState(0), totalTries = _e[0], setTotalTries = _e[1];
    var _f = react_1.useState({ width: 0, height: 0 }), containerSize = _f[0], setContainerSize = _f[1];
    var _g = react_1.useState([]), childrenPosition = _g[0], setChildrenPosition = _g[1];
    var containerRef = react_1.useRef(null);
    var marqueeRef = react_1.useRef(null);
    var t0 = react_1.useState(__safePerformanceNow())[0];
    react_1.useEffect(function () {
        if (scatterRandomly) {
            setContainerSize({
                width: containerRef.current.clientWidth,
                height: containerRef.current.clientHeight,
            });
        }
        setAnimationDuration(containerRef.current.clientWidth / velocity);
    }, [scatterRandomly, velocity]);
    react_1.useEffect(function () {
        if (scatterRandomly && nestedUpdateCount < NESTED_UPDATE_LIMIT) {
            var siblings = marqueeRef.current.childNodes;
            if (siblings.length > 0) {
                var containerRect = containerRef.current.getBoundingClientRect();
                var childRect = siblings[siblings.length - 1].getBoundingClientRect();
                if (util_1.outOfContainerBounds(childRect, containerRect)) {
                    setChildrenPosition(function (state) { return state.slice(0, -1); });
                    setNestedUpdateCount(nestedUpdateCount + 1);
                    setTotalTries(totalTries + 1);
                }
                else {
                    var hasOverlaps = false;
                    for (var i = 0; i + 1 < siblings.length; i++) {
                        var rect1 = siblings[i].getBoundingClientRect();
                        var rect2 = siblings[siblings.length - 1].getBoundingClientRect();
                        if (util_1.doesOverlap(rect1, rect2, containerRect)) {
                            hasOverlaps = true;
                            setChildrenPosition(function (state) { return state.slice(0, -1); });
                            setNestedUpdateCount(nestedUpdateCount + 1);
                            setTotalTries(totalTries + 1);
                        }
                    }
                    if (!hasOverlaps &&
                        siblings.length === childrenPosition.length &&
                        childrenPosition.length === children.length) {
                        if (debug) {
                            var t1 = __safePerformanceNow();
                            console.log("FINISH");
                            console.log("Marquee took " + (t1 - t0) / totalTries + " milliseconds per try.");
                            console.log("Marquee took " + (t1 - t0) + " milliseconds and " + totalTries + " tries total.");
                        }
                        onFinish();
                    }
                }
            }
            if (containerSize.width > 0 &&
                containerSize.height > 0 &&
                childrenPosition.length < children.length) {
                setChildrenPosition(function (state) { return __spreadArrays(state, [
                    {
                        x: util_1.randomIntFromInterval(0, containerSize.width),
                        y: util_1.randomIntFromInterval(0, containerSize.height),
                    },
                ]); });
                setNestedUpdateCount(nestedUpdateCount + 1);
                setTotalTries(totalTries + 1);
            }
            // reset
            if (totalTries > 0 && totalTries % resetAfterTries === 0) {
                setChildrenPosition([]);
            }
        }
    }, [
        nestedUpdateCount,
        childrenPosition,
        childrenPosition.length,
        children.length,
        containerSize,
        scatterRandomly,
    ]);
    react_1.useEffect(function () {
        if (nestedUpdateCount >= NESTED_UPDATE_LIMIT) {
            var resetRenderTimer_1 = setTimeout(function () {
                setNestedUpdateCount(0);
                setRetryAfterExceedingUpdateDepthTrigger(retryAfterExceedingUpdateDepthTrigger + 1);
            });
            return function () { return clearTimeout(resetRenderTimer_1); };
        }
    }, [nestedUpdateCount, retryAfterExceedingUpdateDepthTrigger]);
    var renderChild = function (child, index, isOriginal) {
        var pos;
        if (childrenPosition[index] !== undefined) {
            pos = childrenPosition[index];
        }
        return (react_1.default.createElement(Child_1.default, __assign({ key: (isOriginal ? "child-original" : "child-clone") + "-" + index }, pos, { scatterRandomly: scatterRandomly }), child));
    };
    var filteredChildren = children.filter(function (child, index) {
        return scatterRandomly ? childrenPosition[index] !== undefined : true;
    });
    return (react_1.default.createElement(Container, { ref: containerRef },
        react_1.default.createElement(Mirror, { style: { animationDuration: animationDuration + "s" }, direction: direction }, filteredChildren.map(function (c, i) { return renderChild(c, i, false); })),
        react_1.default.createElement(Mirror, { ref: marqueeRef, style: { animationDuration: animationDuration + "s" }, direction: direction }, filteredChildren.map(function (c, i) { return renderChild(c, i, true); })),
        react_1.default.createElement(Mirror, { style: { animationDuration: animationDuration + "s" }, direction: direction }, filteredChildren.map(function (c, i) { return renderChild(c, i, false); }))));
};
Marquee.defaultProps = {
    direction: "rtl",
    velocity: 30,
    scatterRandomly: false,
    debug: false,
    // the more elements, the higher you should put this.
    // change in hundred or thousand steps even
    resetAfterTries: 100,
    onFinish: function () { },
};
exports.default = Marquee;
var templateObject_1, templateObject_2, templateObject_3, templateObject_4;
//# sourceMappingURL=Marquee.js.map