/**
 * Navigation tabs control
 *
 * Every nav tab content has an url conform ID (title, it comes from brick entries).
 * You can use it to target and auto open this element. Simply place `#open_` before your title in the url.
 * The page will be scrolled to the element if it is not in viewport.
 *
 * Example: <a href="www.example.com/subpage#open_myTarget">Open "myTarget" element</a>
 *
 * @module package/quiqqer/menu/bin/Controls/NavTabs
 * @author www.pcsg.de (Michael Danielczok)
 */
define('package/quiqqer/menu/bin/Controls/NavTabs', [

    'qui/QUI',
    'qui/controls/Control',
    URL_OPT_DIR + 'bin/quiqqer-asset/animejs/animejs/lib/anime.min.js',

], function (QUI, QUIControl, animejs) {
    "use strict";

    return new Class({

        Extends: QUIControl,
        Type   : 'package/quiqqer/menu/bin/Controls/NavTabs',

        Binds: [
            '$onImport',
            '$resize',
            'toggle',
            '$mouseMoveHandler',
            '$mouseDownHandler',
            '$mouseUpHandler'
        ],

        options: {
            animation         : 'slide',
            enabledragtoscroll: false // if enabled allows users to drag to scroll nav elements
        },

        initialize: function (options) {
            this.parent(options);

            this.navTab              = false;
            this.navTabsItems        = false;
            this.navContents         = false;
            this.NavContentContainer = null;
            this.ActiveNavTab        = null;
            this.ActiveContent       = null;
            this.clicked             = false;
            this.animation           = 'slide';

            // drag to scroll
            this.enableDragToScroll = false;
            this.navPos             = {left: 0, x: 0};

            this.addEvents({
                onImport: this.$onImport
            });

            QUI.addEvent('resize', this.$resize);
        },

        $onImport: function () {
            var Elm  = this.getElm(),
                self = this;

            this.navTab              = Elm.getElement('.quiqqer-tab-nav');
            this.navTabsItems        = Elm.getElements('.quiqqer-tab-nav-item');
            this.navContents         = Elm.getElements('.quiqqer-tab-content-item');
            this.NavContentContainer = Elm.getElement('.quiqqer-tab-content');

            if (!this.navTabsItems || !this.navContents) {
                return;
            }

            this.enableDragToScroll = parseInt(this.getAttribute('enabledragtoscroll'));

            if (this.enableDragToScroll === 1) {
                this.$initDragToScroll();
            }

            // animation effect
            if (this.getAttribute('animation')) {
                switch (this.getAttribute('animation')) {
                    case 'slide':
                    default:
                        this.animation = 'slide';
                }
            }

            this.ActiveNavTab  = Elm.getElement('.quiqqer-tab-nav-item.active');
            this.ActiveContent = Elm.getElement('.quiqqer-tab-content-item.active');

            let queryString = window.location.hash;

            if (queryString && queryString.substr(0, 6) === '#open_') {
                const target     = decodeURI(queryString.substr(6));
                const NavTabItem = this.navTab.querySelector('[href="#' + target + '"]');

                if (NavTabItem) {
                    if (!this.$isInViewport(Elm)) {
                        new Fx.Scroll(window, {
                            duration: 500
                        }).toElement(Elm);
                    }

                    self.$setNavItemPos(NavTabItem.parentElement);
                    self.toggle(NavTabItem.parentElement, target);
                }
            }

            let clickEvent = function (event) {
                event.stop();

                if (self.clicked) {
                    return;
                }

                self.clicked = true;

                let NavTabItem = event.target;

                if (NavTabItem.nodeName !== 'LI') {
                    NavTabItem = NavTabItem.getParent('li');
                }

                let target = NavTabItem.getElement('a').getAttribute("href");

                if (target.indexOf('#') === 0) {
                    target = target.substring(1);
                }

                if (!target) {
                    self.clicked = false;
                    return;
                }

                self.$setNavItemPos(NavTabItem);
                self.toggle(NavTabItem, target);

                const url    = window.location.href;
                const newUrl = url.split('#')[0] + '#open_' + target;

                history.pushState(null, null, newUrl);
            };

            this.navTabsItems.addEvent('click', clickEvent);
            this.$resize();
        },

        $resize: function () {
            if (this.enableDragToScroll !== 1) {
                return;
            }

            if (this.navTab.scrollWidth > this.navTab.clientWidth) {
                this.navTab.addEventListener('mousedown', this.$mouseDownHandler);
            } else {
                this.navTab.removeEventListener('mousedown', this.$mouseDownHandler);
            }
        },

        /**
         * Toggle nav tabs
         *
         * @param NavItem HTMLNode
         * @param target string
         */
        toggle: function (NavItem, target) {
            if (NavItem.hasClass('active')) {
                this.clicked = false;
                return;
            }

            var TabContent = this.getElm().getElement('[id="' + target + '"]');

            if (!TabContent) {
                this.clicked = false;
                return;
            }

            var self = this;

            this.NavContentContainer.setStyle('height', this.NavContentContainer.offsetHeight);

            Promise.all([
                this.disableNavItem(this.ActiveNavTab),
                this.hideContent(this.ActiveContent)
            ]).then(function () {
                TabContent.setStyle('display', null);

                return Promise.all([
                    self.enableNavItem(NavItem),
                    self.showContent(TabContent),
                    self.$setHeight(TabContent.offsetHeight)
                ]);
            }).then(function () {
                self.clicked = false;
                self.NavContentContainer.setStyle('height', null);
            });
        },

        /**
         * Set nav item to inactive
         *
         * @param Item HTMLNode
         * @return Promise
         */
        disableNavItem: function (Item) {
            return new Promise(function (resolve) {
                Item.removeClass('active');

                resolve();
            });
        },

        /**
         * Set nav item to active
         *
         * @param Item HTMLNode
         * @return Promise
         */
        enableNavItem: function (Item) {
            var self = this;

            return new Promise(function (resolve) {
                Item.addClass('active');
                self.ActiveNavTab = Item;

                resolve();
            });
        },

        /**
         * Hide tab content
         *
         * @param Item HTMLNode
         * @return Promise
         */
        hideContent: function (Item) {
            var self = this;

            return new Promise(function (resolve) {
                self.$slideFadeOut(Item).then(function () {
                    Item.removeClass('active');
                    Item.setStyle('display', 'none');

                    resolve();
                });
            });
        },

        /**
         * Show tab content
         *
         * @param Item HTMLNode
         * @return Promise
         */
        showContent: function (Item) {
            var self = this;

            return new Promise(function (resolve) {
                self.$slideFadeIn(Item).then(function () {
                    Item.style.display = null;
                    Item.style.opacity = null;
                    Item.addClass('active');
                    self.ActiveContent = Item;

                    resolve();
                });
            });
        },

        /**
         * Set height of tab content container
         *
         * @param height integer
         * @return Promise
         */
        $setHeight: function (height) {
            return this.$animate(this.NavContentContainer, {
                height: height
            });
        },

        /**
         * Fade out animation (hide)
         *
         * @param Item HTMLNode
         * @return Promise
         */
        $slideFadeOut: function (Item) {
            return this.$animate(Item, {
                opacity   : 0,
                translateX: -5,

            });
        },

        /**
         * Fade in animation (show)
         *
         * @param Item HTMLNode
         * @return Promise
         */
        $slideFadeIn: function (Item) {
            Item.setStyles({
                transform: 'translateX(-5px)',
                opacity  : 0
            });

            return this.$animate(Item, {
                translateX: 0,
                opacity   : 1
            });
        },

        /**
         * Scroll active nav item to the left edge (on mobile)
         *
         * @param Item
         */
        $setNavItemPos: function (Item) {
            if (!Item) {
                return;
            }

            if (QUI.getWindowSize().x > 767) {
                return;
            }

            let paddingLeft = window.getComputedStyle(this.navTab, null).getPropertyValue('padding-left'),
                marginLeft  = window.getComputedStyle(Item, null).getPropertyValue('padding-left');

            new Fx.Scroll(this.navTab).start(Item.offsetLeft - parseInt(paddingLeft) - parseInt(marginLeft), 0);
        },

        /**
         * Check if element is in viewport
         * @param element
         * @return {boolean}
         */
        $isInViewport: function (element) {
            const rect = element.getBoundingClientRect();
            return (
                rect.top >= 0 &&
                rect.left >= 0 &&
                rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
                rect.right <= (window.innerWidth || document.documentElement.clientWidth)
            );
        },

        $animate: function (Target, options) {
            return new Promise(function (resolve) {
                options          = options || {};
                options.targets  = Target;
                options.complete = resolve;
                options.duration = options.duration || 250;
                options.easing   = options.easing || 'easeInQuad';

                animejs(options);
            });
        },

        // region drag to scroll

        /**
         * Init drag to scroll
         */
        $initDragToScroll: function () {
            if (this.navTab.scrollWidth <= this.navTab.clientWidth) {
                return;
            }

            this.navTab.addEventListener('mousedown', this.$mouseDownHandler);
        },

        /**
         * Move handler
         *
         * @param e
         */
        $mouseMoveHandler: function (e) {
            // How far the mouse has been moved
            const dx = e.clientX - this.navPos.x;

            if (this.navPos.x !== dx) {
                this.clicked = true;
            }

            // Scroll the element
            this.navTab.scrollLeft = this.navPos.left - dx;
        },

        /**
         * Mouse down handler
         *
         * @param e
         */
        $mouseDownHandler: function (e) {
            this.navTab.style.userSelect = 'none';

            this.navPos = {
                left: this.navTab.scrollLeft, // The current scroll
                x   : e.clientX, // Get the current mouse position
            };

            document.addEventListener('mousemove', this.$mouseMoveHandler);
            document.addEventListener('mouseup', this.$mouseUpHandler);
        },

        /**
         * Mouse up handler
         */
        $mouseUpHandler: function () {
            document.removeEventListener('mousemove', this.$mouseMoveHandler);
            document.removeEventListener('mouseup', this.$mouseUpHandler);

            this.navTab.style.removeProperty('user-select');

            setTimeout(() => {
                this.clicked = false;
            }, 50);
        }

        // end region
    });
});