// Alex Franzelin Slider, a very simple slider library
class Afslider {
    constructor(target, options) {
        this.targetSelector = target;
        this.target = document.querySelector(target);
        options = typeof options != 'undefined' ? options : {};

        this.options = Object.assign({
            slides: 3,  // Slides per view
            scroll: 3,  // Scroll x slides per view, TODO: Implement
            gap: 20,    // Gap between items in px
            padding: 0,   // How much horizontal padding is shown (for instance if you don't want the current slide to occupy the whole screen or want to show the neighbouring slides a bit)
            draggable: true,
            arrows: false,
            pagination: false,  // TODO: Implement pagination
            responsive: [], // Responsive breakpoints, ALWAYS from biggest width to smallest
        }, options);

        // Set intial values and override them afterwards if responsive options are set
        this.slides = this.options.slides;
        this.gap = this.options.gap;
        this.setupHtml();
        this.updateResponsive();
        this.updateCss();
        window.addEventListener('resize', this.boundUpdate);
        this.checkArrows();
    }

    stopDrag(event) {
        this.drag_currentPosition = parseInt(this.list.style.left ? this.list.style.left : 0);
        this.drag_mousedown = false;

        if(this.drag_currentPosition > 0) {
            this.drag_currentPosition = 0;
        }

        let slide = Math.abs(parseInt(this.drag_currentPosition / this.itemWidth));
        let next = Math.abs(this.drag_currentPosition % this.itemWidth);
        
        if(slide >= (this.items.length - this.slides)) {
            slide = this.items.length - this.slides;
        }
        else if(slide < 0) {
            slide = 0;
        }
        
        if(next > 150 && slide < (this.items.length - 1)) {
            slide++;
        }
        
        this.activeItem = slide;
        this.list.style.transition = 'all 0.2s';
        this.list.style.left = (slide * (this.itemWidth + this.gap) * -1) + 'px';
        this.checkArrows();
    }

    // Perform operations on the html (create the slides container, the arrows and pagination div if set in the config)
    setupHtml() {
        this.list = document.createElement('div');
        this.list.classList.add('afslider_list');
        this.list.innerHTML = this.target.innerHTML;
        this.activeItem = 0;
        this.drag_mousedown = false;
        this.drag_x = 0;
        this.drag_currentPosition = 0;
        this.drag_originalTransition = '';

        if(this.options.draggable === true) {
            // Desktop events
            this.list.addEventListener('mousedown', (event) => {
                this.drag_x = event.clientX;
                this.drag_originalTransition = this.list.style.transition ? this.list.style.transition : 'none';
                this.list.style.transition = 'none';
                this.drag_currentPosition = parseInt(this.list.style.left ? this.list.style.left : 0);
                this.drag_mousedown = true;
            });

            this.list.addEventListener('mousemove', (event) => {
                if(this.drag_mousedown === true) {
                    let newX = this.drag_currentPosition + event.clientX - this.drag_x;
                    this.list.style.left = newX + 'px';
                }
            });

            this.list.addEventListener('mouseup', (event) => {
                this.stopDrag(event);
            });

            this.list.addEventListener('mouseleave', (event) => {
                this.stopDrag(event);
            });
            
            // Mobile events
            this.list.addEventListener('touchstart', (event) => {
                this.drag_x = event.touches[0].clientX;
                this.drag_originalTransition = this.list.style.transition ? this.list.style.transition : 'none';
                this.list.style.transition = 'none';
                this.drag_currentPosition = parseInt(this.list.style.left ? this.list.style.left : 0);
                this.drag_mousedown = true;
            });

            this.list.addEventListener('touchmove', (event) => {
                if(this.drag_mousedown === true) {
                    let newX = this.drag_currentPosition + event.touches[0].clientX - this.drag_x;
                    this.list.style.left = newX + 'px';
                }
            });

            this.list.addEventListener('touchend', (event) => {
                this.stopDrag(event);
            });
        }

        this.target.classList.add('afslider');
        this.target.innerHTML = '';
        this.target.appendChild(this.list);
        this.items = this.target.querySelectorAll('.afslider_list > div');

        if(this.options.arrows === true) {
            let arrows = document.createElement('div');
            let prev = document.createElement('div');
            let next = document.createElement('div');
            let prevLink = document.createElement('a');
            let nextLink = document.createElement('a');

            arrows.classList.add('arrows');
            prev.classList.add('prev');
            next.classList.add('next');
            prevLink.addEventListener('click', () => {
                this.goto('prev');
            });
            nextLink.addEventListener('click', () => {
                this.goto('next');
            });
            prevLink.innerHTML = '&lt;';
            nextLink.innerHTML = '&gt;';

            prev.appendChild(prevLink);
            next.appendChild(nextLink);
            arrows.appendChild(prev);
            arrows.appendChild(next);
            this.target.appendChild(arrows);
        }

        if(this.options.pagination === true) {
            let pagination = document.createElement('div');
            pagination.classList.add('pagination');
            this.target.appendChild(pagination);
        }
    }

    // Check if the arrows have to be active or inactive
    checkArrows() {
        if(this.target.querySelector('.arrows') === null || this.target.querySelector('.arrows').length <= 0) {
            return;
        }

        if(this.activeItem == 0) {
            this.target.querySelector('.arrows .prev').classList.add('inactive');
        }
        else {
            this.target.querySelector('.arrows .prev').classList.remove('inactive');
        }

        if(this.activeItem >= this.items.length - this.slides) {
            this.target.querySelector('.arrows .next').classList.add('inactive');
        }
        else {
            this.target.querySelector('.arrows .next').classList.remove('inactive');
        }
    }

    // Goto a certain slide or to the prev/next one
    goto(where) {
        let distance = this.itemWidth + this.gap;
        
        if(where == 'next') {
            // TODO: Move variable definition out of if-block, do checks if last item, add option to move multiple slides at a time, add possibility to move specific amount of slides, add drag and drop
            if(this.activeItem >= (this.items.length - this.slides)) {
                return;
            }

            let currentLeft = parseInt(this.target.querySelector('.afslider_list').style.left ? this.target.querySelector('.afslider_list').style.left : 0);
            this.target.querySelector('.afslider_list').style.left = (currentLeft - distance) + 'px';
            this.activeItem++;
        }
        else if(where == 'prev') {
            if(this.activeItem <= 0) {
                return;
            }

            let currentLeft = parseInt(this.target.querySelector('.afslider_list').style.left ? this.target.querySelector('.afslider_list').style.left : 0);
            this.target.querySelector('.afslider_list').style.left = (currentLeft + distance) + 'px';
            this.activeItem--;
        }
        else if(!isNaN(where) && where >= 0 && where <= this.items.length - 1) {    // Goto specific item
            let left = (where * distance) * -1;
            this.target.querySelector('.afslider_list').style.left = left + 'px';
            this.activeItem = where;
        }

        this.checkArrows();
    }

    // Setup the responsive values (gap, item-width)
    boundUpdate = () => {
        this.updateResponsive();
        this.goto(this.activeItem);
        this.updateCss();
    }
    
    updateResponsive() {
        this.targetWidth = this.target.clientWidth;
        
        if(!this.options.responsive || this.options.responsive.length == 0) {
            return;
        }

        // Reset the options
        this.slides = this.options.slides;
        this.gap = this.options.gap;

        for(let i = 0; i < this.options.responsive.length; i++) {
            let item = this.options.responsive[i];

            if(this.targetWidth <= item.width) {
                this.slides = typeof item.slides != 'undefined' ? item.slides : this.slides;
                this.gap = typeof item.gap != 'undefined' ? item.gap : this.gap;
            }
        }

        let totalGap = this.gap * (this.slides - 1); // The gaps visible in the current page (screw it if a page contains less than the max slides per page, does not matter)
        
        this.itemWidth = (this.targetWidth / this.slides) - (totalGap / this.slides);
        this.totalWidth = (this.itemWidth * this.items.length) + (this.gap * (this.items.length - 1));
        
        if(this.options.padding > 0) {
            this.itemWidth = (this.targetWidth - this.options.padding * 2) / this.slides - (totalGap / this.slides);
            this.totalWidth = (this.itemWidth * this.items.length) + (this.gap * (this.items.length - 1));
        }
    }

    // Update each item, assigning the current width to it
    updateCss() {
        this.target.querySelector('.afslider_list').style.gap = this.gap + 'px';
        this.target.querySelector('.afslider_list').style.width = this.totalWidth + 'px';
        this.target.querySelector('.afslider_list > div:first-child').style["padding-left"] = this.options.padding + 'px';

        for(let i = 0; i < this.items.length; i++) {
            this.items[i].style.flex = '0 0 ' + this.itemWidth + 'px';
        }
    }
}