define(["appRouter", "focusManager", "browser", "layoutManager", "inputManager", "dom", "css!./dialoghelper.css", "scrollStyles"], function(appRouter, focusManager, browser, layoutManager, inputManager, dom) {
    "use strict";

    function enableAnimation() {
        return !browser.tv && browser.supportsCssAnimation()
    }

    function removeCenterFocus(dlg) {
        layoutManager.tv && (dlg.classList.contains("scrollX") ? centerFocus(dlg, !0, !1) : dlg.classList.contains("smoothScrollY") && centerFocus(dlg, !1, !1))
    }

    function tryRemoveElement(elem) {
        var parentNode = elem.parentNode;
        if (parentNode) try {
            parentNode.removeChild(elem)
        } catch (err) {
            console.log("Error removing dialog element: " + err)
        }
    }

    function DialogHashHandler(dlg, hash, resolve) {
        function onHashChange(e) {
            var isBack = self.originalUrl === window.location.href;
            !isBack && isOpened(dlg) || window.removeEventListener("popstate", onHashChange), isBack && (self.closedByBack = !0, closeDialog(dlg))
        }

        function onBackCommand(e) {
            "back" === e.detail.command && (self.closedByBack = !0, e.preventDefault(), e.stopPropagation(), closeDialog(dlg))
        }

        function onDialogClosed() {
            if (isHistoryEnabled(dlg) || inputManager.off(dlg, onBackCommand), window.removeEventListener("popstate", onHashChange), removeBackdrop(dlg), dlg.classList.remove("opened"), removeScrollLockOnClose && document.body.classList.remove("noScroll"), !self.closedByBack && isHistoryEnabled(dlg)) {
                (history.state || {}).dialogId === hash && history.back()
            }
            if (layoutManager.tv && focusManager.focus(activeElement), "false" !== dlg.getAttribute("data-removeonclose")) {
                removeCenterFocus(dlg);
                var dialogContainer = dlg.dialogContainer;
                dialogContainer ? (tryRemoveElement(dialogContainer), dlg.dialogContainer = null) : tryRemoveElement(dlg)
            }
            setTimeout(function() {
                resolve({
                    element: dlg,
                    closedByBack: self.closedByBack
                })
            }, 1)
        }
        var self = this;
        self.originalUrl = window.location.href;
        var activeElement = document.activeElement,
            removeScrollLockOnClose = !1;
        dlg.addEventListener("close", onDialogClosed), !dlg.classList.contains("dialog-fixedSize") && dlg.classList.add("centeredDialog"), dlg.classList.remove("hide"), addBackdropOverlay(dlg), dlg.classList.add("opened"), dlg.dispatchEvent(new CustomEvent("open", {
            bubbles: !1,
            cancelable: !1
        })), "true" !== dlg.getAttribute("data-lockscroll") || document.body.classList.contains("noScroll") || (document.body.classList.add("noScroll"), removeScrollLockOnClose = !0), animateDialogOpen(dlg), isHistoryEnabled(dlg) ? (appRouter.pushState({
            dialogId: hash
        }, "Dialog", "#" + hash), window.addEventListener("popstate", onHashChange)) : inputManager.on(dlg, onBackCommand)
    }

    function addBackdropOverlay(dlg) {
        var backdrop = document.createElement("div");
        backdrop.classList.add("dialogBackdrop");
        var backdropParent = dlg.dialogContainer || dlg;
        backdropParent.parentNode.insertBefore(backdrop, backdropParent), dlg.backdrop = backdrop, backdrop.offsetWidth, backdrop.classList.add("dialogBackdropOpened"), dom.addEventListener(dlg.dialogContainer || backdrop, "click", function(e) {
            e.target === dlg.dialogContainer && close(dlg)
        }, {
            passive: !0
        })
    }

    function isHistoryEnabled(dlg) {
        return "true" === dlg.getAttribute("data-history")
    }

    function open(dlg) {
        globalOnOpenCallback && globalOnOpenCallback(dlg);
        var parent = dlg.parentNode;
        parent && parent.removeChild(dlg);
        var dialogContainer = document.createElement("div");
        return dialogContainer.classList.add("dialogContainer"), dialogContainer.appendChild(dlg), dlg.dialogContainer = dialogContainer, document.body.appendChild(dialogContainer), new Promise(function(resolve, reject) {
            new DialogHashHandler(dlg, "dlg" + (new Date).getTime(), resolve)
        })
    }

    function isOpened(dlg) {
        return !dlg.classList.contains("hide")
    }

    function close(dlg) {
        isOpened(dlg) && (isHistoryEnabled(dlg) ? history.back() : closeDialog(dlg))
    }

    function closeDialog(dlg) {
        if (!dlg.classList.contains("hide")) {
            dlg.dispatchEvent(new CustomEvent("closing", {
                bubbles: !1,
                cancelable: !1
            }));
            animateDialogClose(dlg, function() {
                focusManager.popScope(dlg), dlg.classList.add("hide"), dlg.dispatchEvent(new CustomEvent("close", {
                    bubbles: !1,
                    cancelable: !1
                }))
            })
        }
    }

    function animateDialogOpen(dlg) {
        var onAnimationFinish = function() {
            focusManager.pushScope(dlg), "true" === dlg.getAttribute("data-autofocus") && focusManager.autoFocus(dlg)
        };
        if (enableAnimation()) {
            var onFinish = function() {
                dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
                    once: !0
                }), onAnimationFinish()
            };
            return void dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
                once: !0
            })
        }
        onAnimationFinish()
    }

    function animateDialogClose(dlg, onAnimationFinish) {
        if (enableAnimation()) {
            var animated = !0;
            switch (dlg.animationConfig.exit.name) {
                case "fadeout":
                    dlg.style.animation = "fadeout " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both";
                    break;
                case "scaledown":
                    dlg.style.animation = "scaledown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both";
                    break;
                case "slidedown":
                    dlg.style.animation = "slidedown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both";
                    break;
                default:
                    animated = !1
            }
            var onFinish = function() {
                dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
                    once: !0
                }), onAnimationFinish()
            };
            if (dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
                    once: !0
                }), animated) return
        }
        onAnimationFinish()
    }

    function shouldLockDocumentScroll(options) {
        return !(supportsOverscrollBehavior && (options.size || !browser.touch)) && (null != options.lockScroll ? options.lockScroll : "fullscreen" === options.size || (!!options.size || browser.touch))
    }

    function removeBackdrop(dlg) {
        var backdrop = dlg.backdrop;
        if (backdrop) {
            dlg.backdrop = null;
            var onAnimationFinish = function() {
                tryRemoveElement(backdrop)
            };
            if (enableAnimation()) return backdrop.classList.remove("dialogBackdropOpened"), void setTimeout(onAnimationFinish, 300);
            onAnimationFinish()
        }
    }

    function centerFocus(elem, horiz, on) {
        require(["scrollHelper"], function(scrollHelper) {
            var fn = on ? "on" : "off";
            scrollHelper.centerFocus[fn](elem, horiz)
        })
    }

    function createDialog(options) {
        options = options || {};
        var dlg = document.createElement("div");
        dlg.classList.add("focuscontainer"), dlg.classList.add("hide"), shouldLockDocumentScroll(options) && dlg.setAttribute("data-lockscroll", "true"), !1 !== options.enableHistory && appRouter.enableNativeHistory() && dlg.setAttribute("data-history", "true"), !1 !== options.modal && dlg.setAttribute("modal", "modal"), !1 !== options.autoFocus && dlg.setAttribute("data-autofocus", "true");
        var defaultEntryAnimation, defaultExitAnimation;
        defaultEntryAnimation = "scaleup", defaultExitAnimation = "scaledown";
        var entryAnimation = options.entryAnimation || defaultEntryAnimation,
            exitAnimation = options.exitAnimation || defaultExitAnimation,
            entryAnimationDuration = options.entryAnimationDuration || ("fullscreen" !== options.size ? 180 : 280),
            exitAnimationDuration = options.exitAnimationDuration || ("fullscreen" !== options.size ? 120 : 220);
        if (dlg.animationConfig = {
                entry: {
                    name: entryAnimation,
                    timing: {
                        duration: entryAnimationDuration,
                        easing: "ease-out"
                    }
                },
                exit: {
                    name: exitAnimation,
                    timing: {
                        duration: exitAnimationDuration,
                        easing: "ease-out",
                        fill: "both"
                    }
                }
            }, dlg.classList.add("dialog"), options.scrollX ? (dlg.classList.add("scrollX"), dlg.classList.add("smoothScrollX"), layoutManager.tv && centerFocus(dlg, !0, !0)) : !1 !== options.scrollY && (dlg.classList.add("smoothScrollY"), layoutManager.tv && centerFocus(dlg, !1, !0)), options.removeOnClose && dlg.setAttribute("data-removeonclose", "true"), options.size && (dlg.classList.add("dialog-fixedSize"), dlg.classList.add("dialog-" + options.size)), enableAnimation()) switch (dlg.animationConfig.entry.name) {
            case "fadein":
                dlg.style.animation = "fadein " + entryAnimationDuration + "ms ease-out normal";
                break;
            case "scaleup":
                dlg.style.animation = "scaleup " + entryAnimationDuration + "ms ease-out normal both";
                break;
            case "slideup":
                dlg.style.animation = "slideup " + entryAnimationDuration + "ms ease-out normal";
                break;
            case "slidedown":
                dlg.style.animation = "slidedown " + entryAnimationDuration + "ms ease-out normal"
        }
        return dlg
    }
    var globalOnOpenCallback, supportsOverscrollBehavior = "overscroll-behavior-y" in document.body.style;
    return {
        open: open,
        close: close,
        createDialog: createDialog,
        setOnOpen: function(val) {
            globalOnOpenCallback = val
        }
    }
});