;(function ($, window, document, undefined) {

    var tours = [];

    // API

    $.wcpTourRegister = function(options) {
        var t = new WCPTour(options);
        tours[options.name] = t;
    }
    $.wcpTourSimpleRegister = function(options) {
        var t = new WCPTourSimple(options);
        tours[options.name] = t;
    }
    $.wcpTourStart = function(tourName) {
        tours[tourName].start();
    }
    $.wcpTourEnd = function(tourName) {
        tours[tourName].endTour();
    }
    $.wcpTourDisable = function(tourName) {
        tours[tourName].disableTour();
    }
    $.wcpTourRestart = function(tourName) {
        tours[tourName].restart();
    }
    $.wcpTourIsFinished = function(tourName) {
        return tours[tourName].isFinished();
    }

    // API Events

    $.wcpTourEventStepWillChange = function(stepName) {

    }
    $.wcpTourEventStepDidChange = function(stepName) {

    }
    $.wcpTourEventStarted = function() {

    }
    $.wcpTourEventFinished = function() {

    }
    $.wcpTourCoordinatesForTipForStep = function(stepName) {
        return undefined;
    }
    $.wcpTourCoordinatesForHighlightRect = function(stepName) {
        return undefined;
    }

    function WCPTourSimple(options) {
        this.id = Math.floor(Math.random() * 99999) + 1;
        this.options = options;
        this.currentStep = -1;
        this.root = undefined;
    }
    WCPTourSimple.prototype.start = function() {
        var html = '';

        html += '<div id="wcp-tour-'+ this.id +'" class="wcp-tour-root-simple">';
        html += '   <div class="wcp-tour-background-simple">';
        html += '   </div>';

        // Content

        html += '   <div class="wcp-tour-simple-container" style="width: '+ this.options.width +'px; height: '+ this.options.height +'px;">';
        html += '       <div class="wcp-tour-simple-slide-content"></div>';
        html += '       <div class="wcp-tour-simple-button" id="wcp-tour-simple-button-skip">Skip</div>';
        html += '       <div class="wcp-tour-simple-button" id="wcp-tour-simple-button-done">Done</div>';
        html += '       <div class="wcp-tour-simple-click-anywhere">Click anywhere to continue</div>';
        html += '       <div class="wcp-tour-simple-nav">';

        for (var i=0; i<this.options.slides.length; i++) {
            var active = '';
            if (i == 0) active = 'wcp-tour-simple-nav-circle-active';

            html += '<div class="wcp-tour-simple-nav-circle" data-index="'+ i +'"></div>';
        }

        html += '       </div>';
        html += '   </div>';

        html += '</div>';

        $('body').prepend(html);
        this.root = $('#wcp-tour-'+ this.id);

        this.events();
        this.presentSlide(0);
        localStorage[this.options.name] = 'seen';
    };
    WCPTourSimple.prototype.events = function() {
        var self = this;

        $(document).off('mouseup.wcotoursimple');
        $(document).on('mouseup.wcotoursimple', function(e) {
            // Clicked on nav circle?
            if ($(e.target).hasClass('wcp-tour-simple-nav-circle')) {
                var index = $(e.target).data('index');
                self.presentSlide(index);
            } else if ($(e.target).hasClass('wcp-tour-simple-button')) {
                // Clicked on skip/done?
                self.endTour();
            } else {
                // If else, next slide
                self.nextSlide();
            }
        });
    };
    WCPTourSimple.prototype.nextSlide = function() {
        this.presentSlide(this.currentStep + 1);
    };
    WCPTourSimple.prototype.presentSlide = function(slideIndex) {
        if (slideIndex > this.options.slides.length - 1) {
            // slideIndex = this.options.slides.length - 1;
            this.endTour();
            return;
        }
        if (slideIndex < 0) {
            slideIndex = 0;
        }
        this.currentStep = slideIndex;

        // Update content
        this.root.find('.wcp-tour-simple-slide-content').html(this.options.slides[this.currentStep].html);

        // Update nav circles
        this.root.find('.wcp-tour-simple-nav-circle').removeClass('wcp-tour-simple-nav-circle-active');
        this.root.find('.wcp-tour-simple-nav-circle[data-index="'+ this.currentStep +'"]').addClass('wcp-tour-simple-nav-circle-active');

        // Update buttons
        if (this.currentStep == this.options.slides.length - 1) {
            // Show done
            $('#wcp-tour-simple-button-skip').hide();
            $('#wcp-tour-simple-button-done').show();
        } else {
            // Show skip
            $('#wcp-tour-simple-button-skip').show();
            $('#wcp-tour-simple-button-done').hide();
        }
    };
    WCPTourSimple.prototype.endTour = function() {
        $('#wcp-tour-'+ this.id).remove();
        localStorage[this.options.name] = 'seen';
        $.wcpTourEventFinished(this.options.name);
    };
    WCPTourSimple.prototype.disableTour = function() {
        localStorage[this.options.name] = 'seen';
    };
    WCPTourSimple.prototype.isFinished = function() {
        if (localStorage[this.options.name] == 'seen') return true;

        return false;
    };

    function WCPTour(options) {
        this.id = Math.floor(Math.random() * 99999) + 1;
        this.options = options;
        this.currentStep = -1;
        this.reachedStep = -1;

        // DOM
        this.root = undefined;

        this.init();
    }
    WCPTour.prototype.init = function() {
        if (!localStorage[this.options.name]) {
            localStorage[this.options.name] = -1;
        }
    };
    WCPTour.prototype.start = function() {
        if (localStorage[this.options.name] == 'finished') {
            // Tour finished
            return;
        } else if (localStorage[this.options.name] >= 0) {
            // Tour is still active
            this.reachedStep = -1;
            this.currentStep = -1;
            this.drawContent();
            this.presentStep(localStorage[this.options.name]);

            // Send event
            $.wcpTourEventStarted();
        } else {
            // Tour has not started yet
            this.reachedStep = -1;
            this.drawContent();
            this.presentWelcomeScreen();

            // Send event
            $.wcpTourEventStarted();
        }
    };
    WCPTour.prototype.restart = function() {
        localStorage[this.options.name] = -1;
        this.start();
    };
    WCPTour.prototype.drawContent = function() {
        if (this.root) this.root.remove();

        var html = '';

        html += '<div id="wcp-tour-'+ this.id +'" class="wcp-tour-root">';
        html += '   <div class="wcp-tour-background">';
        html += '       <div class="wcp-tour-highlight-rect" id="wcp-tour-highlight-rect-1"></div>';
        html += '       <div class="wcp-tour-highlight-rect" id="wcp-tour-highlight-rect-2"></div>';
        html += '       <div class="wcp-tour-highlight-rect" id="wcp-tour-highlight-rect-3"></div>';
        html += '       <div class="wcp-tour-highlight-rect" id="wcp-tour-highlight-rect-4"></div>';
        html += '   </div>';

        // welcome screen

        html += '   <div class="wcp-tour-welcome-screen wcp-tour-centered-content">';
        html += '       <img class="wcp-tour-icon" src="data:image/png;base64, ">';
        html += '       <div class="wcp-tour-title">' + this.options.welcomeScreen.title + '</div>';
        html += '       <div class="wcp-tour-text">' + this.options.welcomeScreen.text + '</div>';
        html += '       <div class="wcp-tour-begin">' + this.options.welcomeScreen.startButtonTitle + '</div>';
        html += '       <div class="wcp-tour-skip">' + this.options.welcomeScreen.cancelButtonTitle + '</div>';
        html += '   </div>';

        // step
        html += '   <div class="wcp-tour-step wcp-tour-centered-content">';
        html += '       <div class="wcp-tour-step-nav"></div>';
        html += '       <div class="wcp-tour-step-title"></div>';
        html += '       <div class="wcp-tour-step-text"></div>';
        html += '       <div class="wcp-tour-step-click-anywhere">Click anywhere to continue</div>';
        html += '       <div class="wcp-tour-step-skip">Or skip this guide</div>';
        html += '   </div>';

        html += '</div>';

        $('body').append(html);

        if (!$('body').hasClass('wcp-tour-active')) {
            $('body').addClass('wcp-tour-active');
        }

        this.root = $('#wcp-tour-' + this.id);

        this.events();
    };
    WCPTour.prototype.events = function() {
        var self = this;

        this.root.find('.wcp-tour-begin').on('click', function() {
            // go to step 0
            self.presentStep(0);
        });
        this.root.find('.wcp-tour-skip').on('click', function() {
            // end tour
            self.endTour();
        });
        this.root.find('.wcp-tour-step-skip').on('click', function() {
            // end tour
            self.endTour();
        });
        $(document).off('click.' + this.id);
        $(document).on('click.' + this.id, function(e) {
            if ($(e.target).hasClass('wcp-tour-step') || $(e.target).hasClass('wcp-tour-step-title') || $(e.target).hasClass('wcp-tour-step-text') || $(e.target).hasClass('wcp-tour-step-click-anywhere')) {
                self.nextStep();
            }
        });
        $(document).off('click.' + this.id, '.wcp-tour-step-circle');
        $(document).on('click.' + this.id, '.wcp-tour-step-circle', function() {
            i = $(this).data('wcp-tour-circle-index');
            self.presentStep(i);
        });
        var visibleContainer = undefined;
        $(document).off('mouseover.' + this.id, '.wcp-tour-tip-media-button');
        $(document).on('mouseover.' + this.id, '.wcp-tour-tip-media-button', function() {
            visibleContainer = $(this).siblings('.wcp-tour-tip-media-container');
            visibleContainer.show();
            self.limitMediaContainer(visibleContainer);

            if (visibleContainer.find('video').length > 0) {
                visibleContainer.find('video').get(0).play();
            }
        });
        $(document).off('mousemove.' + this.id);
        $(document).on('mousemove.' + this.id, function(e) {
            if (visibleContainer && $(e.target).closest('.wcp-tour-tip-media-button').length == 0 && $(e.target).closest('.wcp-tour-tip-media-container').length == 0) {
                visibleContainer.hide();

                if (visibleContainer.find('video').length > 0) {
                    visibleContainer.find('video').get(0).pause();
                }

                visibleContainer = undefined;
            }
        });
        $(window).off('resize.wcp-tour');
        $(window).on('resize.wcp-tour', function() {
            $('.wcp-tour-highlight-rect').addClass('wcp-tour-highlight-rect-no-transition');
            self.updateHighlightRect();
            setTimeout(function() {
                $('.wcp-tour-highlight-rect').removeClass('wcp-tour-highlight-rect-no-transition');
            }, 10);
        });
    };
    WCPTour.prototype.nextStep = function() {
        if (parseInt(this.currentStep, 10) == this.options.steps.length - 1) {
            // done
            this.endTour();
        } else {
            // next step
            this.presentStep(parseInt(this.currentStep, 10) + 1);
        }
    };
    WCPTour.prototype.presentStep = function(stepIndex) {
        // is the step different?
        if (parseInt(this.currentStep, 10) == parseInt(stepIndex, 10)) return;

        if (this.currentStep == -1) {
            var self = this;

            // Hide welcome screen
            this.root.find('.wcp-tour-welcome-screen').css({ opacity: 0 });
            setTimeout(function() {
                self.root.find('.wcp-tour-welcome-screen').hide();
            }, 330);

            // Show step screen
            this.root.find('.wcp-tour-step').css({ display: 'flex' });
            setTimeout(function() {
                self.root.find('.wcp-tour-step').css({ opacity: 1 });
            }, 10);
        }


        localStorage[this.options.name] = stepIndex;
        this.currentStep = stepIndex;

        $.wcpTourEventStepWillChange(this.options.steps[this.currentStep].title);

        // Update navigation
        this.updateNav();

        // Set step content
        this.updateStep();

        // Update tip
        this.updateTip();

        // Send event
        $.wcpTourEventStepDidChange(this.options.steps[this.currentStep].title);
    };
    WCPTour.prototype.presentWelcomeScreen = function(stepIndex) {
        // Set current step to welcome screen
        localStorage[this.options.name] = -1;
        this.currentStep = -1;

        // Set the initial position of the highlight rects
        $('.wcp-tour-highlight-rect').addClass('wcp-tour-highlight-rect-no-transition');
        var rect = $.wcpTourCoordinatesForHighlightRect(this.options.steps[0].title);

        var windowWidth = $(window).width();
        var windowHeight = $(window).height();

        $('#wcp-tour-highlight-rect-1').css({
            left: 0,
            top: 0,
            width: '100%',
            height: rect.y + rect.height/2
        });
        $('#wcp-tour-highlight-rect-2').css({
            left: rect.x + rect.width/2,
            top: rect.y + rect.height/2,
            width: windowWidth - rect.x - rect.width/2,
            height: 0
        });
        $('#wcp-tour-highlight-rect-3').css({
            left: 0,
            top: rect.y + rect.height/2,
            width: '100%',
            height: windowHeight - rect.y - rect.height/2
        });
        $('#wcp-tour-highlight-rect-4').css({
            left: 0,
            top: rect.y + rect.height/2,
            width: rect.x + rect.width/2,
            height: 0
        });

        setTimeout(function() {
            $('.wcp-tour-highlight-rect').removeClass('wcp-tour-highlight-rect-no-transition');
        }, 50);
    };
    WCPTour.prototype.endTour = function(stepIndex) {
        // Set current step to welcome screen
        localStorage[this.options.name] = 'finished';
        this.currentStep = -1;

        // Send event
        $.wcpTourEventFinished(this.options.name);

        // Fade out root
        this.root.addClass('wcp-tour-hidden');
        var self = this;
        setTimeout(function() {
            self.root.remove();
            $('body').removeClass('wcp-tour-active');
        }, 330);
    };
    WCPTour.prototype.isFinished = function() {
        if (localStorage[this.options.name] == 'finished') {
            return true;
        }

        return false;
    };

    WCPTour.prototype.updateNav = function() {
        // does the number of circles need to be updated?
        while (parseInt(this.currentStep, 10) > this.reachedStep) {
            // this.reachedStep = parseInt(this.currentStep, 10);
            this.reachedStep++;

            // Add a new circle
            var html = '<div class="wcp-tour-step-circle" data-wcp-tour-circle-index="'+ this.reachedStep +'"><div class="wcp-tour-step-circle-inner">'+ (this.reachedStep + 1) +'</div></div>';
            this.root.find('.wcp-tour-step-nav').append(html);

            // Present the circle
            var self = this;
            setTimeout(presentCircle.bind(null, this.reachedStep), 10);
        }

        function presentCircle(index) {
            $('.wcp-tour-step-circle[data-wcp-tour-circle-index="'+ index +'"]').addClass('wcp-tour-circle-presented');
        }

        // set the currently active circle
        $('.wcp-tour-step-circle').removeClass('wcp-tour-circle-active');
        $('.wcp-tour-step-circle[data-wcp-tour-circle-index="'+ parseInt(this.currentStep, 10) +'"]').addClass('wcp-tour-circle-active');
    };
    WCPTour.prototype.updateStep = function() {
        this.root.find('.wcp-tour-step-title').html(this.options.steps[this.currentStep].title);
        this.root.find('.wcp-tour-step-text').html(this.options.steps[this.currentStep].text);
    };
    WCPTour.prototype.updateTip = function() {
        if (this.root.find('.wcp-tour-tip[data-wcp-tip-index='+ parseInt(this.currentStep, 10) +']').length == 0) {
            // Add HTML
            var html = '';

            html += '   <div class="wcp-tour-tip" data-wcp-tip-index="'+ parseInt(this.currentStep, 10) +'">';

            if (this.options.steps[this.currentStep].tip.position == 'bottom-left' || this.options.steps[this.currentStep].tip.position == 'bottom-right') {
                html += '       <div class="wcp-tour-tip-arrow"><img src="data:image/png;base64, "></div>';
                html += '       <div class="wcp-tour-clear"></div>';
            }

            html += '       <div class="wcp-tour-tip-media-button"></div>';
            html += '       <div class="wcp-tour-tip-title-wrap">';
            html += '           <div class="wcp-tour-tip-title"></div>';
            html += '           <div class="wcp-tour-tip-subtitle"></div>';
            html += '       </div>';

            if (this.options.steps[this.currentStep].tip.position == 'top-left' || this.options.steps[this.currentStep].tip.position == 'top-right') {
                html += '       <div class="wcp-tour-clear"></div>';
                html += '       <div class="wcp-tour-tip-arrow"><img src="data:image/png;base64, "></div>';
            }

            if (this.options.steps[this.currentStep].tip.media != undefined) {
                html += '       <div class="wcp-tour-tip-media-container">';

                if (this.options.steps[this.currentStep].tip.media.type == 'video') {
                    html += '<video loop>';
                    html += '   <source src="'+ this.options.steps[this.currentStep].tip.media.url_mp4 +'" type="video/mp4">';
                    html += '   <source src="'+ this.options.steps[this.currentStep].tip.media.url_webm +'" type="video/webm">';
                    html += '   <source src="'+ this.options.steps[this.currentStep].tip.media.url_ogv +'" type="video/ogv">';
                    html += '</video>';
                }
                if (this.options.steps[this.currentStep].tip.media.type == 'image') {
                    html += '<img src="'+ this.options.steps[this.currentStep].tip.media.url +'">';
                }
            }

            html += '       </div>';
            html += '   </div>';

            this.root.append(html);
        }

        var tip = this.root.find('.wcp-tour-tip[data-wcp-tip-index='+ parseInt(this.currentStep, 10) +']');

        tip.find('.wcp-tour-tip-title').html(this.options.steps[this.currentStep].tip.title);
        tip.find('.wcp-tour-tip-subtitle').html(this.options.steps[this.currentStep].tip.subtitle);

        // Set media
        if (this.options.steps[this.currentStep].tip.media != undefined) {
            tip.find('.wcp-tour-tip-media-button').show();

            if (this.options.steps[this.currentStep].tip.media.type == 'video') {
                tip.find('.wcp-tour-tip-media-button').html('<i class="fa fa-play" aria-hidden="true"></i>');
            }
            if (this.options.steps[this.currentStep].tip.media.type == 'image') {
                tip.find('.wcp-tour-tip-media-button').html('<i class="fa fa-camera" aria-hidden="true"></i>');
            }
        } else {
            tip.find('.wcp-tour-tip-media-button').hide();
        }

        // Position tip
        var c = this.options.steps[this.currentStep].tip.coordinates;

        if (c == undefined) {
            c = $.wcpTourCoordinatesForTipForStep(this.options.steps[parseInt(this.currentStep, 10)].title);
        }

        var x, y;
        if (this.options.steps[this.currentStep].tip.position == 'bottom-right') {
            x = c.x;
            y = c.y;
        }
        if (this.options.steps[this.currentStep].tip.position == 'bottom-left') {
            x = c.x - tip.width();
            y = c.y;
        }
        if (this.options.steps[this.currentStep].tip.position == 'top-right') {
            x = c.x;
            y = c.y - tip.height();
        }
        if (this.options.steps[this.currentStep].tip.position == 'top-left') {
            x = c.x - tip.width();
            y = c.y - tip.height();
        }

        tip.css({
            left: x,
            top: y
        });

        // position arrow
        if (this.options.steps[this.currentStep].tip.position == 'bottom-left') {
            tip.find('.wcp-tour-tip-arrow').css({
                transform: 'scaleX(-1)',
                float: 'right'
            });
        }
        if (this.options.steps[this.currentStep].tip.position == 'bottom-right') {
            tip.find('.wcp-tour-tip-arrow').css({
                transform: 'scaleX(1)',
            });
        }
        if (this.options.steps[this.currentStep].tip.position == 'top-left') {
            tip.find('.wcp-tour-tip-arrow').css({
                transform: 'scale(-1, -1)',
                float: 'right'
            });
        }
        if (this.options.steps[this.currentStep].tip.position == 'top-right') {
            tip.find('.wcp-tour-tip-arrow').css({
                transform: 'scaleY(-1)',
            });
        }

        // Apply extra arrow styles
        if (this.options.steps[this.currentStep].tip.arrowStyle) {
            tip.find('.wcp-tour-tip-arrow').attr('style', tip.find('.wcp-tour-tip-arrow').attr('style') + ' ' + this.options.steps[this.currentStep].tip.arrowStyle);
        }

        // Highlight rect
        this.updateHighlightRect();

        // If this is the first step, blink the media button
        if (this.currentStep == 0 && this.options.steps[this.currentStep].tip.media) {
            setTimeout(function() {
                $('.wcp-tour-tip-media-button').addClass('wcp-tour-tip-media-button-blink');
            }, 1000);
        }

        // Update tip classes
        for (var i=0; i<=parseInt(this.reachedStep, 10); i++) {
            var t = this.root.find('.wcp-tour-tip[data-wcp-tip-index='+ i +']');
            if (i == parseInt(this.currentStep, 10)) {
                t.addClass('wcp-tour-tip-visible');
                var animatedTip = t;
                setTimeout(function() {
                    animatedTip.addClass('wcp-tour-tip-animated');
                }, 10);
            } else {
                t.removeClass('wcp-tour-tip-animated');
                t.removeClass('wcp-tour-tip-visible');
            }
        }
    };
    WCPTour.prototype.updateHighlightRect = function() {
        if (this.currentStep >= 0 && this.options.steps[this.currentStep].tip.highlightRect) {
            var rect = $.wcpTourCoordinatesForHighlightRect(this.options.steps[this.currentStep].title);

            var windowWidth = $(window).width();
            var windowHeight = $(window).height();

            $('#wcp-tour-highlight-rect-1').css({
                left: 0,
                top: 0,
                width: '100%',
                height: rect.y
            });
            $('#wcp-tour-highlight-rect-2').css({
                left: rect.x + rect.width,
                top: rect.y,
                width: windowWidth - rect.x - rect.width,
                height: rect.height
            });
            $('#wcp-tour-highlight-rect-3').css({
                left: 0,
                top: rect.y + rect.height,
                width: '100%',
                height: windowHeight - rect.y - rect.height
            });
            $('#wcp-tour-highlight-rect-4').css({
                left: 0,
                top: rect.y,
                width: rect.x,
                height: rect.height
            });
        } else {
            // Set the initial position of the highlight rects
            $('.wcp-tour-highlight-rect').addClass('wcp-tour-highlight-rect-no-transition');
            var rect = $.wcpTourCoordinatesForHighlightRect(this.options.steps[0].title);

            var windowWidth = $(window).width();
            var windowHeight = $(window).height();

            $('#wcp-tour-highlight-rect-1').css({
                left: 0,
                top: 0,
                width: '100%',
                height: rect.y + rect.height/2
            });
            $('#wcp-tour-highlight-rect-2').css({
                left: rect.x + rect.width/2,
                top: rect.y + rect.height/2,
                width: windowWidth - rect.x - rect.width/2,
                height: 0
            });
            $('#wcp-tour-highlight-rect-3').css({
                left: 0,
                top: rect.y + rect.height/2,
                width: '100%',
                height: windowHeight - rect.y - rect.height/2
            });
            $('#wcp-tour-highlight-rect-4').css({
                left: 0,
                top: rect.y + rect.height/2,
                width: rect.x + rect.width/2,
                height: 0
            });

            setTimeout(function() {
                $('.wcp-tour-highlight-rect').removeClass('wcp-tour-highlight-rect-no-transition');
            }, 50);
        }
    };
    WCPTour.prototype.limitMediaContainer = function(container) {
        var dx = 0, dy = 0;

        container.css({ transform: 'translate('+ dx +'px, '+ dy +'px)' });

        if (container.offset().left < 0) {
            dx = container.offset().left;
        }
        if (container.offset().left + container.width() > $(window).width()) {
            dx = $(window).width() - (container.offset().left + container.width());
        }
        if (container.offset().top < 0) {
            dy = container.offset().left;
        }
        if (container.offset().top + container.height() > $(window).height()) {
            dy = $(window).height() - (container.offset().top + container.height());
        }

        container.css({ transform: 'translate('+ dx +'px, '+ dy +'px)' });
    }
})(jQuery, window, document);
