(function ($, document, window, viewport) {
    'use strict';

    // PLUGIN CLASS
    // ============
    const PointerEventsPluginClass = {

        EVENT_SWIPE_LEFT: 'swipeleft',
        EVENT_SWIPE_RIGHT: 'swiperight',

        SWIPE_MIN_DISTANCE: 30, // minimum distance in pixels to swipe
        SWIPE_MAX_LATERAL_RATIO: 0.25, // maximum lateral ratio for a swipe to count (i.e. for a horizontal swipe, the vertical movement must be max 1/4th of the horizontal movement)

        registerSwipeLeft: function ($element, callback) {
            $element.css({'touch-action': 'pan-y'}); // disable left/right scrolling actions
            $element.on('pointerdown', (event) => {
                if(this.shouldIgnore(event)) {
                    return;
                }
                event.preventDefault();
                $element.data('last-pointer-down', {x: event.pageX, y: event.pageY});
            });
            $element.on('pointerup', (event) => {
                if(this.shouldIgnore(event)) {
                    return;
                }
                event.preventDefault();
                let lastDown = $element.data('last-pointer-down');
                if (typeof lastDown === 'object') {
                    const direction = (lastDown.x < event.pageX) ? 'right' : 'left';
                    if(direction === 'left') {
                        const movedX = Math.abs(lastDown.x - event.pageX);
                        const movedY = Math.abs(lastDown.y - event.pageY);
                        if (movedX > this.SWIPE_MIN_DISTANCE && (movedY / movedX) < this.SWIPE_MAX_LATERAL_RATIO) {
                            callback($element);
                        }
                    }
                }
            });
            $element.on('pointercancel pointerout pointerleave', (event) => {
                if(this.shouldIgnore(event)) {
                    return;
                }
                $element.data('last-pointer-down', '');
            });
        },

        registerSwipeRight: function ($element, callback) {
            $element.css({'touch-action': 'pan-y'}); // disable left/right scrolling actions
            $element.on('pointerdown', (event) => {
                if(this.shouldIgnore(event)) {
                    return;
                }
                event.preventDefault();
                $element.data('last-pointer-down', {x: event.pageX, y: event.pageY});
            });
            $element.on('pointerup', (event) => {
                if(this.shouldIgnore(event)) {
                    return;
                }
                event.preventDefault();
                let lastDown = $element.data('last-pointer-down');
                if (typeof lastDown === 'object') {
                    const direction = (lastDown.x < event.pageX) ? 'right' : 'left';
                    if(direction === 'right') {
                        const movedX = Math.abs(lastDown.x - event.pageX);
                        const movedY = Math.abs(lastDown.y - event.pageY);
                        if (movedX > this.SWIPE_MIN_DISTANCE && (movedY / movedX) < this.SWIPE_MAX_LATERAL_RATIO) {
                            callback($element);
                        }
                    }
                }
            });
            $element.on('pointercancel pointerout pointerleave', (event) => {
                if(this.shouldIgnore(event)) {
                    return;
                }
                $element.data('last-pointer-down', '');
            });
        },

        on: function (event, $element, callback) {
            if (!event || !$element || !$element.length || !callback) {
                return;
            }
            switch (event) {
                case this.EVENT_SWIPE_LEFT:
                    this.registerSwipeLeft($element, callback);
                    break;
                case this.EVENT_SWIPE_RIGHT:
                    this.registerSwipeRight($element, callback);
                    break;
                default:
                    console.log('PointerEvents: Event ' + event + ' is unknown.');
                    break;
            }
        },

        shouldIgnore: function(event) {
            return event && event.target && event.target.tagName && ['A', 'BUTTON', 'INPUT', 'TEXTAREA'].includes(event.target.tagName.toUpperCase());
        },

        /**
         * @this {PluginBase & PointerEventsPluginClass}
         * @param {HTMLElement} element
         * @param {Object} options
         */
        init: function (element, options) {
            // Nothing to initialize here.
            window.easytemplate.PointerEvents = {
                on: this.on.bind(this)
            };
        },
    };

    // REGISTER AND ADD THE PLUGIN
    // ===========================
    if (!window.easytemplate && !window.easytemplate.PluginManager) {
        throw Error('Cannot initialize Easytemplate Plugin. plugin-manager.js has to be loaded first!');
    }

    /** @type {PluginManager} manager */
    const manager = window.easytemplate.PluginManager;
    manager.addPlugin('body', PointerEventsPluginClass, 'etPointerEventsPlugin');
})(jQuery, document, window, ResponsiveBootstrapToolkit);