/**
 * @module package/quiqqer/tour/bin/classes/Tour
 *
 * Baseclass for a tour
 *
 * @require qui/QUI
 * @require qui/classes/DOM
 * @require URL_OPT_DIR + bin/quiqqer-asset/tether-shepherd/tether-shepherd/dist/js/shepherd.js
 * @require tether
 * @require css!' + URL_OPT_DIR + 'bin/quiqqer-asset/tether-shepherd/tether-shepherd/dist/css/shepherd-theme-arrows.css'
 * @require css!' + URL_OPT_DIR + 'quiqqer/tour/bin/load.css'
 */
require.config({
    paths: {
        'tether': URL_OPT_DIR + 'bin/quiqqer-asset/tether-shepherd/tether-shepherd/dist/js/tether'
    }
});

define('package/quiqqer/tour/bin/classes/Tour', [

    'qui/QUI',
    'qui/classes/DOM',
    'package/quiqqer/tour/bin/classes/Step',
    URL_OPT_DIR + 'bin/quiqqer-asset/tether-shepherd/tether-shepherd/dist/js/shepherd.js',
    'tether',
    'Locale',
    'qui/controls/windows/Alert',


    'css!' + URL_OPT_DIR + 'bin/quiqqer-asset/tether-shepherd/tether-shepherd/dist/css/shepherd-theme-arrows.css'

], function (QUI, QDOM, Step, Shepherd, tether, QUILocale, QUIAlert) {
    "use strict";

    return new Class({
        Extends: QDOM,
        Type   : 'package/quiqqer/tour/bin/classes/Tour',

        Binds: [
            'start',
            'next',
            'getShepherd',
            'addStep',
            'waitForElement',
            'execute',
            'waitForElementByType',
            'wait'
        ],

        initialize: function (options) {
            this.setAttribute('shepherd', {
                defaults: {
                    classes       : 'shepherd-theme-arrows',//'shepherd-element shepherd-open shepherd-theme-arrows shepherd-transparent-text',
                    showCancelLink: true
                }
            });

            this.parent(options);
            /**
             * Array defined in seperate Tour Scripts, contains Step Objects
             * @type {Array}
             */
            this.$tourSteps = [];
            /**
             * counter keeps track of next step instance
             * @type {number}
             */

            this.step = 0;
            this.$Tour = new Shepherd.Tour(
                this.getAttribute('shepherd')
            );
        },

        /**
         * Return the shepherd object
         *
         * @returns {Shepherd.Tour|Tour|*}
         */
        getShepherd: function () {
            return this.$Tour;
        },

        /**
         * Beendet die Tour
         */
        cancel: function () {
            this.getShepherd().cancel();
        },

        /**
         * Add a step to the shepherd tour object
         *
         * @param {Object} options
         * @return {Object} Step
         */
        addStep: function (options) {
            var S = new Step(this, options);

            this.$tourSteps.push(S);

            return S;
        },

        /**
         * Start the tour
         */
        start: function () {
            this.$current = -1;

            this.next();
            this.getShepherd().start();
        },

        /**
         * Wrapper method, appends the next step from the tour-StepsArray before continuing the Tour
         *
         * @return {Promise}
         */
        next: function () {
            this.$current = this.$current + 1;

            try {
                if (this.$current < this.$tourSteps.length) {
                    var Prom = this.$tourSteps[this.$current].run();
                }

                this.getShepherd().next();
            } catch (err) {
                new QUIAlert({
                    title  : QUILocale.get('quiqqer/tour', 'Global.Alert.Error.Title'),
                    content: QUILocale.get('quiqqer/tour', 'Global.Alert.Error')
                }).open();

                return Promise.reject(err);
            }

            return Prom || Promise.resolve();
        },

        /**
         * Bietet möglichkeit steps zu überspringen
         * @param steps
         * @returns {*}
         */
        skip: function (steps) {
            this.$current = this.$current + 1 + steps;

            if (this.$current < this.$tourSteps.length) {
                var Prom = this.$tourSteps[this.$current].run();
            }

            this.getShepherd().next();

            return Prom
        },

        /**
         * Wartet bis ein Element entstanden ist und gefunden wird
         * @param DomNode   DomNode
         * @param CSSSelector   String
         * @param Skip int How many steps should be skipped if element isnt found after Timeout
         * @param Timeout int
         */
        addWaitingStepByCSSClass: function (DomNode, CSSSelector, Skip, Timeout) {
            this.addStep({
                classes: '.no-show',
                when   : {
                    show: function () {
                        var iter = 0;
                        var step = function () {
                            iter++;
                            if (Timeout === 'undefined') {
                                Timeout = 20;
                            }
                            if (iter > Timeout) {
                                this.skip(Skip);
                                return 0
                            }
                            var gefunden = DomNode.getElement(CSSSelector);
                            if (gefunden) {
                                this.next.delay(100);
                                return
                            }
                            step.delay(100);
                        }.bind(this);
                        step();
                    }.bind(this)
                },
                buttons: false
            });
        },

        /**
         * Wartet bis ein Element entstanden ist und gefunden wird
         * @param Type   String
         * @param Skip int How many steps should be skipped if element isnt found after Timeout
         * @param Timeout int
         */
        addWaitingStepByType: function (Type, Skip, Timeout) {
            this.addStep({
                classes: '.no-show',
                when   : {
                    show: function () {
                        var iter = 0;
                        var step = function () {
                            iter++;
                            if (Timeout === 'undefined') {
                                Timeout = 20;
                            }
                            if (iter > Timeout) {
                                this.skip(Skip);
                                return 0
                            }
                            var gefunden = QUI.Controls.getByType(Type);
                            if (gefunden.length) {
                                this.next.delay(100);
                                return
                            }
                            step.delay(100);
                        }.bind(this);
                        step();
                    }.bind(this)
                },
                buttons: false
            });
        },

        /**
         * Wartet
         * @param time Zeit in zehntel Sekunden
         */
        wait: function (time) {
            this.addStep({
                classes: '.no-show',
                when   : {
                    show: function () {
                        var iter          = 0;
                        var wartefunktion = function () {
                            iter++;
                            if (iter > time) {
                                this.next();
                                return
                            }
                            wartefunktion.delay(100);
                        }.bind(this);
                        wartefunktion()
                    }.bind(this)
                },
                buttons: false
            });


        },

        /**
         * Führt übergebene Funktion aus
         * @param fkt function
         */
        execute: function (fkt) {
            this.addStep({
                classes: '.no-show',
                when   : {
                    show: function () {
                        fkt()
                    }.bind(this)
                },
                buttons: false
            });
        },

        /**
         * Resettet das Tourobjekt
         */
        reset: function () {
            this.$Tour = new Shepherd.Tour(
                this.getAttribute('shepherd')
            );
            this.step  = 0;
        }
    });
});