RED.tourGuide = (function() {
    var activeListeners = [];
    var shade;
    var focus;
    var popover;
    var stepContent;
    var targetElement;
    var fullscreen;

    var tourCache = {};

    function run(tourPath, done) {
        done = done || function(err) {
            if (err) {
                console.error(err);
            }
        };
        loadTour(tourPath, function(err, tour) {
            if (err) {
                console.warn("Error loading tour:",err);
                return;
            }
            runTour(tour, done);
        })

    }

    function loadTour(tourPath, done) {
        if (tourCache[tourPath]) {
            done(null, tourCache[tourPath]);
        } else {
            /* jshint ignore:start */
            // jshint<2.13 doesn't support dynamic imports. Once grunt-contrib-jshint
            // has been updated with the new jshint, we can stop ignoring this block
            import(tourPath).then(function(module) {
                tourCache[tourPath] = module.default;
                done(null, tourCache[tourPath]);
            }).catch(function(err) {
                done(err);
            })
            /* jshint ignore:end */
        }
    }

    function repositionFocus() {
        if (targetElement) {
            if (!fullscreen) {
                var pos = targetElement[0].getBoundingClientRect();
                var dimension = Math.max(50, Math.max(pos.width,pos.height)*1.5);
                focus.css({
                    left: (pos.left+pos.width/2)+"px",
                    top: (pos.top+pos.height/2)+"px",
                    width: (2*dimension)+"px",
                    height: (2*dimension)+"px"
                })
                var flush = focus[0].offsetHeight; // Flush CSS changes
                focus.addClass("transition");
                focus.css({
                    width: dimension+"px",
                    height: dimension+"px"
                })
            } else {
                focus.css({
                    left: ($(window).width()/2)+"px",
                    top: ($(window).height()/2)+"px",
                    width: "0px",
                    height: "0px"
                })
            }
            if (popover) {
                popover.move({
                    target: targetElement,
                })
            }
        }
    }
    function runTour(tour, done) {

        shade = $('<div class="red-ui-tourGuide-shade"></div>').appendTo(document.body);
        focus = $('<div class="red-ui-tourGuide-shade-focus"></div>').appendTo(shade);

        // var resizeTimer;
        //
        $(window).on("resize.red-ui-tourGuide", function() {
            repositionFocus();
        })



        var i = 0;
        var state = {
            index: 0,
            count: tour.steps.length
        };

        function endTour(err) {
            $(window).off("resize.red-ui-tourGuide");
            $(document).off('keydown.red-ui-tourGuide');
            if (popover) {
                popover.close();
            }
            stepContent = null;
            popover = null;
            shade.remove();
            shade = null;
            done(err);
        }
        function runStep(carryOn) {
            if (carryOn === false) {
                endTour(false);
                return;
            }
            if (i === tour.steps.length) {
                endTour();
                return
            }
            state.index = i;
            // console.log("TOUR STEP",i+1,"OF",tour.steps.length)
            try {
                runTourStep(tour.steps[i++], state, runStep)
            } catch(err) {
                endTour(err);
                return;
            }
        }
        runStep();
    }

    function clearListeners() {
        activeListeners.forEach(function(listener) {
            if (listener.type === "dom-event") {
                listener.target[0].removeEventListener(listener.event,listener.listener,listener.opts);
            } else if (listener.type === "nr-event") {
                RED.events.off(listener.event, listener.listener)
            }
        })
        activeListeners = [];
    }

    function prepareStep(step, state, done) {
        if (step.prepare) {
            if (step.prepare.length === 0) {
                step.prepare.call(state);
            } else {
                if (popover) {
                    popover.element.hide();
                    if (!fullscreen) {
                        fullscreen = true;
                        repositionFocus()
                    }
                }
                step.prepare.call(state, function() {
                    if (popover) {
                        popover.element.show();
                    }
                    done();
                })
                return;
            }
        }
        done();
    }
    function completeStep(step, state, done) {
        function finish() {
            clearListeners();
            setTimeout(function() {
                done();
            },0)
        }
        if (step.complete) {
            if (step.complete.length === 0) {
                step.complete.call(state);
            } else {
                if (popover) {
                    popover.element.hide();
                    if (!fullscreen) {
                        fullscreen = true;
                        repositionFocus()
                    }
                }
                step.complete.call(state, function() {
                    if (popover) {
                        popover.element.show();
                    }
                    finish();
                })
                return;
            }
        }
        finish();

    }
    function getLocaleText(property) {
        if (typeof property === 'string') {
            return property;
        }
        var currentLang = RED.i18n.lang() || 'en-US';
        var availableLangs = Object.keys(property);
        return property[currentLang]||property['en-US']||property[availableLangs[0]]

    }
    function runTourStep(step, state, done) {
        shade.fadeIn();
        prepareStep(step, state, function() {
            var zIndex;
            var direction = step.direction || "bottom";
            fullscreen = false;

            if (typeof step.element === "string") {
                targetElement = $(step.element)
            } else if (typeof step.element === "function") {
                targetElement = step.element.call(state);
            } else if (!step.element) {
                targetElement = $(".red-ui-editor")
                fullscreen = true;
                direction = "inset";
            } else {
                targetElement = step.element;
            }

            if (targetElement.length === 0) {
                targetElement = null;
                shade.hide();
                throw new Error("Element not found")
            }
            if ($(window).width() < 400) {
                targetElement = $(".red-ui-editor");
                fullscreen = true;
                direction = "inset";
            }

            zIndex = targetElement.css("z-index");
            if (!fullscreen && (step.interactive || step.wait)) {
                targetElement.css("z-index",2002);
            }
            repositionFocus();

            if (!stepContent) {
                stepContent = $('<div style="position:relative"></div>');
            } else {
                stepContent.empty();
            }
            $('<button type="button" class="red-ui-button red-ui-button-small" style="float: right; margin-top: -4px; margin-right: -4px;"><i class="fa fa-times"></i></button>').appendTo(stepContent).click(function(evt) {
                evt.preventDefault();
                completeStep(step, state, function() {
                    done(false);
                });
            })

            var stepDescription = $('<div class="red-ui-tourGuide-popover-description"></div>').appendTo(stepContent);
            if (step.titleIcon) {
                $('<h2><i class="'+step.titleIcon+'"></i></h2>').appendTo(stepDescription);
            }
            if (step.title) {
                $('<h2>').text(getLocaleText(step.title)).appendTo(stepDescription);
            }
            $('<div>').css("text-align","left").html(getLocaleText(step.description)).appendTo(stepDescription);

            if (step.image) {
                $(`<img src="red/tours/${step.image}" />`).appendTo(stepDescription)
            }

            var stepToolbar = $('<div>',{class:"red-ui-tourGuide-toolbar"}).appendTo(stepContent);

            // var breadcrumbs = $('<div>',{class:"red-ui-tourGuide-breadcrumbs"}).appendTo(stepToolbar);
            // var bcStart = Math.max(0,state.index - 3);
            // var bcEnd = Math.min(state.count, bcStart + 7);
            // if (bcEnd === state.count) {
            //     bcStart = Math.max(0,bcEnd - 7);
            // }
            // for (var i = bcStart; i < bcEnd; i++) {
            //     var bullet = $('<i class="fa"></i>').addClass(i===state.index ? "fa-circle":"fa-circle-o").appendTo(breadcrumbs);
            //     if (i === bcStart) {
            //         if (i > 1) {
            //             bullet.css("font-size", "3px");
            //         } else if (i === 1) {
            //             bullet.css("font-size", "4px");
            //         }
            //     } else if (i === bcStart + 1) {
            //         if (i > 2) {
            //             bullet.css("font-size", "4px");
            //         }
            //     }
            //     if (i === bcEnd - 1) {
            //         if (i < state.count - 2) {
            //             bullet.css("font-size", "3px");
            //         } else if (i === state.count - 2) {
            //             bullet.css("font-size", "4px");
            //         }
            //     } else if (i === bcEnd - 2) {
            //         if (i < state.count - 3) {
            //             bullet.css("font-size", "4px");
            //         }
            //     }
            //     // if (i === bcEnd - 1) {
            //     //     if (i < state.count - 2) {
            //     //         bullet.css("font-size", "3px");
            //     //     } else if (i === state.count - 2) {
            //     //         bullet.css("font-size", "4px");
            //     //     }
            //     // }
            // }

            $('<small>').text((state.index+1)+"/"+state.count).appendTo(stepToolbar)
            var nextButton;
            if (fullscreen || !step.wait) {
                nextButton = $('<button type="button" class="red-ui-button" style="position: absolute; right:0;bottom:0;"></button>').appendTo(stepToolbar).one('click',function(evt) {
                    evt.preventDefault();
                    stepEventListener();
                });
                if (state.index === state.count - 1) {
                    $('<span></span>').text(RED._("common.label.close")).appendTo(nextButton);
                } else if (state.index === 0) {
                    $('<span>start</span>').text(RED._("tourGuide.start")).appendTo(nextButton);
                    $('<span style="margin-left: 6px"><i class="fa fa-chevron-right"></i></span>').appendTo(nextButton);
                } else if (state.index < state.count-1) {
                    $('<span></span>').text(RED._("tourGuide.next")).appendTo(nextButton);
                    $('<span style="margin-left: 6px"><i class="fa fa-chevron-right"></i></span>').appendTo(nextButton);
                }
            }

            var width = step.width;
            if (fullscreen) {
                width = 500;
            }
            var maxWidth = Math.min($(window).width()-10,Math.max(width || 0, 300));
            if (!popover) {
                popover = RED.popover.create({
                    target: targetElement,
                    width: width || "auto",
                    maxWidth: maxWidth+"px",
                    direction: direction,
                    class: "red-ui-tourGuide-popover"+(fullscreen?" ":""),
                    trigger: "manual",
                    content: stepContent
                }).open();
            }
            $(document).off('keydown.red-ui-tourGuide');
            $(document).on('keydown.red-ui-tourGuide', function(evt) {
                if (evt.key === "Escape" || evt.key === "Esc") {
                    evt.preventDefault();
                    evt.stopPropagation();
                    completeStep(step, state, function() {
                        done(false);
                    });
                }
            })
            popover.element.toggleClass("red-ui-tourGuide-popover-full",!!fullscreen);
            popover.move({
                target: targetElement,
                width: width || "auto",
                maxWidth: maxWidth+"px",
                direction: direction,
            })
            setTimeout(function() {
                var pos = popover.element.position()
                if (pos.left < 0) {
                    popover.element.css({left: 0});
                }
            },100);
            if (nextButton) {
                setTimeout(function() {
                    nextButton.focus();
                },100);
            }

            var isSVG = targetElement[0] instanceof SVGElement;
            if (step.fallback) {
                focus.one("mouseenter", function(evt) {
                    setTimeout(function() {
                        var pos = targetElement[0].getBoundingClientRect();
                        var dimension = Math.max(50, Math.max(pos.width,pos.height)*1.5);
                        focus.css({
                            width: (4*dimension)+"px",
                            height: (4*dimension)+"px"
                        })
                        shade.fadeOut();
                        popover.move({
                            target: $(".red-ui-editor"),
                            direction: step.fallback,
                            offset: 10,
                            transition: true
                        })
                        // popover.element.addClass('red-ui-tourGuide-popover-bounce');
                    },isSVG?0:500);
                })
            }

            var stepEventListener = function() {
                focus.removeClass("transition");
                targetElement.css("z-index",zIndex);
                completeStep(step, state, done);
            }

            if (step.wait) {
                if (step.wait.type === "dom-event") {
                    var eventTarget = targetElement;
                    if (step.wait.element) {
                        if (typeof step.wait.element === "string") {
                            eventTarget = $(step.wait.element);
                        } else if (typeof step.wait.element === "function") {
                            eventTarget = step.wait.element.call(state);
                        }
                    }
                    var listener = {
                        type: step.wait.type,
                        target: eventTarget,
                        event: step.wait.event,
                        listener: function() {
                            stepEventListener();
                        },
                        opts: { once: true }
                    }
                    activeListeners.push(listener)
                    eventTarget[0].addEventListener(listener.event,listener.listener,listener.opts)
                } else if (step.wait.type === "nr-event") {
                    var listener = {
                        type: step.wait.type,
                        event: step.wait.event,
                        listener: function() {
                            if (step.wait.filter) {
                                if (!step.wait.filter.apply(state,arguments)) {
                                    return;
                                }
                            }
                            stepEventListener();
                        }
                    }
                    activeListeners.push(listener);
                    RED.events.on(listener.event,listener.listener);
                }
            }
        })
    }

    function listTour() {
        return [
            {
                id: "4_1",
                label: "4.1",
                path: "./tours/welcome.js"
            },
            {
                id: "4_0",
                label: "4.0",
                path: "./tours/4.0/welcome.js"
            },
            {
                id: "3_1",
                label: "3.1",
                path: "./tours/3.1/welcome.js"
            },
            {
                id: "3_0",
                label: "3.0",
                path: "./tours/3.0/welcome.js"
            },
            {
                id: "2_2",
                label: "2.2",
                path: "./tours/2.2/welcome.js"
            },
            {
                id: "2_1",
                label: "2.1",
                path: "./tours/2.1/welcome.js"
            }
        ];
    }

    return {
        load: loadTour,
        run: run,
        list: listTour,
        reset: function() {
            RED.settings.set("editor.tours.welcome",'');
        }
    }


})();
