!(function ($) {

    'use strict';

    function crossSlider($Scope, $){

        const MathUtils = {
            lineEq: (y2, y1, x2, x1, currentVal) => {
                // y = mx + b
                var m = (y2 - y1) / (x2 - x1), b = y1 - m * x1;
                return m * currentVal + b;
            },
            lerp: (a, b, n) =>  (1 - n) * a + n * b,
            distance: (x1, x2, y1, y2) => {
                var a = x1 - x2;
                var b = y1 - y2;
                return Math.hypot(a,b);
            },
            randomNumber: (min,max) => Math.floor(Math.random()*(max-min+1)+min)
        };

        let winsize;
        const calcWinsize = () => winsize = {width: window.innerWidth, height: window.innerHeight};
        calcWinsize();
        window.addEventListener('resize', calcWinsize);

        const getMousePos = (ev) => {
            let posx = 0;
            let posy = 0;
            if (!ev) ev = window.event;
            if (ev.pageX || ev.pageY) {
                posx = ev.pageX;
                posy = ev.pageY;
            }
            else if (ev.clientX || ev.clientY) 	{
                posx = ev.clientX + body.scrollLeft + docEl.scrollLeft;
                posy = ev.clientY + body.scrollTop + docEl.scrollTop;
            }
            return {x: posx, y: posy};
        }

        let mousePos = {x: winsize.width/2, y: winsize.height/2};
        window.addEventListener('mousemove', ev => mousePos = getMousePos(ev));

        class Slide {
            constructor(el, title) {
                this.DOM = {el: el};
                this.DOM.title = title;
                charming(this.DOM.title);
                this.DOM.titleLetters = [...this.DOM.title.querySelectorAll('span')];
                this.DOM.titleLetters.sort(() => Math.round(Math.random())-0.5);
                this.DOM.number = this.DOM.el.querySelector('.number');
                this.DOM.subtitle = this.DOM.el.querySelector('.caption');
                this.DOM.imgWrap = this.DOM.el.querySelector('.img-wrap');
                this.DOM.img = this.DOM.imgWrap.querySelector('.cross-img');
            }
            move(direction, val) {
                return new Promise((resolve, reject) => {
                    const tx = direction === 'left' ? '+=' + val*-1 : '+=' + val;
                    const duration = 1.2;

                    gsap.timeline({onComplete: resolve})
                    .to(this.DOM.imgWrap, {
                        duration: duration,
                        x: tx,
                        ease: Quart.easeInOut
                    }, 0)
                    .to(this.DOM.imgWrap, {
                        duration: duration*.5,
                        scaleX: 1.3,
                        ease: Quart.easeIn
                    }, 0)
                    .to(this.DOM.imgWrap, {
                        duration: duration*.5,
                        scaleX: 1,
                        ease: Quart.easeOut
                    }, duration*.5)
                    .to(this.DOM.number, {
                        duration: duration*.95,
                        x: tx,
                        ease: Quint.easeInOut
                    }, 0)
                    .to(this.DOM.subtitle, {
                        duration: duration*1.1,
                        x: tx,
                        ease: Quart.easeInOut
                    }, 0)
                    .to(this.DOM.title, {
                        duration: duration*1.05,
                        x: tx,
                        ease: Quart.easeInOut
                    }, 0);
                });
            }
            setCenter() {
                this.isCenter = true;
                this.DOM.el.classList.add('grid__item--center');
                this.DOM.title.classList.add('grid__item--center');
                gsap.set([this.DOM.el, this.DOM.title], {opacity: 1});
            }
            setRight() {
                this.isRight = this.isCenter = false;
                this.isLeft = true;
                this.DOM.el.classList.add('grid__item--right');
                this.DOM.title.classList.add('grid__item--right');
                gsap.set([this.DOM.el, this.DOM.title], {opacity: 1});
            }
            setLeft() {
                this.isLeft = this.isCenter = false;
                this.isRight = true;
                this.DOM.el.classList.add('grid__item--left');
                this.DOM.title.classList.add('grid__item--left');
                gsap.set([this.DOM.el, this.DOM.title], {opacity: 1});
            }
            reset() {
                gsap.set([this.DOM.el, this.DOM.imgWrap, this.DOM.number, this.DOM.subtitle, this.DOM.title], {transform: 'none'});
                gsap.set([this.DOM.el, this.DOM.title], {opacity: 0});
                this.DOM.title.classList = 'grid__item grid__item--title';
                this.DOM.el.classList = 'grid__item grid__item--slide';
            }
            animateElementsOut(contentItem) {
                return new Promise((resolve, reject) => {
                    const time = MathUtils.randomNumber(0,100)/500;
                    this.elemsTimeline = gsap.timeline({onComplete: resolve})
                    .to(this.DOM.titleLetters, {
                        duration: 1,
                        stagger: 0.04,
                        y: MathUtils.randomNumber(300,600),
                        opacity: 0,
                        ease: Quart.easeInOut
                    }, time)
                    .to(this.DOM.titleLetters, {
                        duration: 0.5,
                        stagger: 0.04,
                        scaleY: 2.2,
                        ease: Quart.easeIn
                    }, time)
                    .to(this.DOM.titleLetters, {
                        duration: 0.5,
                        stagger: 0.04,
                        scaleY: 1,
                        ease: Quart.easeOut
                    }, time + 0.5)
                    .to(this.DOM.number, {
                        duration: 1,
                        y: -500,
                        opacity: 0,
                        ease: Quart.easeInOut
                    }, time+0.3)
                    .to(this.DOM.imgWrap, {
                        duration: 0.8,
                        y: -500,
                        opacity: 0,
                        ease: Quart.easeInOut
                    }, time+0.4)
                    .to(this.DOM.imgWrap, {
                        duration: .4,
                        scaleX: 0.95,
                        scaleY: 1.4,
                        ease: Quart.easeIn
                    }, time+0.4)
                    .to(this.DOM.imgWrap, {
                        duration: .4,
                        scaleX: 1,
                        scaleY: 1,
                        ease: Quart.easeOut
                    }, time+0.4 + 0.4)
                    .to(this.DOM.subtitle, {
                        duration: 1,
                        y: -500,
                        opacity: 0,
                        ease: Quart.easeInOut
                    }, time+0.5);

                    if ( this.isCenter ) {
                        const contentItemTitle = contentItem.querySelector('.content__item-header-title');
                        const contentItemImg = contentItem.querySelector('.img--content');
                        this.elemsTimeline.to(contentItemTitle, {
                            duration: 0.8,
                            ease: Expo.easeOut,
                            startAt: {y: '100%', opacity: 0, rotation: -16},
                            y: '0%',
                            rotation: 0,
                            opacity: 1
                        }, time+1.3)
                        .set(contentItemImg, {scale: 1.2}, 0)
                        .to(contentItemImg, 0.8, {
                            ease: Expo.easeOut,
                            scale: 1
                        }, time+1.3)
                        .to(revealer.DOM.el, 1, {
                            ease: Quint.easeOut,
                            y: '-100%'
                        }, time+1.2);
                    }
                });
            }
            animateElementsIn(contentItem) {
                return new Promise((resolve, reject) => {
                    const time = MathUtils.randomNumber(0,50)/500;
                    this.elemsTimeline = gsap.timeline({onComplete: resolve});

                    if ( this.isCenter ) {
                        const contentItemTitle = contentItem.querySelector('.content__item-header-title');
                        const contentItemImg = contentItem.querySelector('.img--content');
                        this.elemsTimeline.to(contentItemTitle, {
                            duration: 1,
                            ease: Quint.easeOut,
                            y: '50%',
                            opacity: 0
                        }, 0)
                        .to(contentItemImg, {
                            duration:1,
                            ease: Quint.easeOut,
                            scale: 1.2
                        }, 0)
                        .to(revealer.DOM.el, {
                            duration: 1,
                            ease: Quint.easeOut,
                            y: '0%'
                        }, 0);
                    }
                    this.elemsTimeline.to(this.DOM.subtitle, {
                        duration: 0.8,
                        y: 0,
                        opacity: 1,
                        ease: Quart.easeOut
                    }, time)
                    .to(this.DOM.imgWrap, {
                        duration: 0.8,
                        y: 0,
                        opacity: 1,
                        scaleX: 1,
                        scaleY: 1,
                        ease: Quart.easeOut
                    }, time+0.1)
                    .to(this.DOM.number, {
                        duration: 0.8,
                        y: 0,
                        opacity: 1,
                        ease: Quart.easeOut
                    }, time+0.2)
                    .to(this.DOM.titleLetters, {
                        stagger: 0.03,
                        duration: 0.8,
                        y: 0,
                        opacity: 1,
                        scaleX: 1,
                        scaleY: 1,
                        ease: Quart.easeOut
                    }, time+0.1)
                });
            }
        }

        class Slideshow {
            constructor(el) {
                this.DOM = {el: el};
                // The titles
                this.DOM.titlesWrap = this.DOM.el.querySelector('.titles-wrap');
                this.DOM.titlesInner = this.DOM.titlesWrap.querySelector('.grid--titles');
                this.DOM.titles = [...this.DOM.titlesInner.querySelectorAll('.grid__item--title')];
                // The slides instances
                this.slides = [];
                [...this.DOM.el.querySelectorAll('.grid__item--slide')].forEach((slide, pos) => this.slides.push(new Slide(slide, this.DOM.titles[pos])));
                // Total number of slides
                this.slidesTotal = this.slides.length;
                if ( this.slidesTotal < 4 ) return;
                // Center slide's position
                this.center = 0;

                // Content Items
                this.DOM.contentItems = [...document.querySelectorAll('.content__item')];

                // Areas (left, center, right) where to attach the navigation events.
                this.DOM.interaction = {
                    left: document.querySelector('.grid__item--left'),
                    center: document.querySelector('.grid__item--center'),
                    right: document.querySelector('.grid__item--right')
                };

                this.setVisibleSlides();
                this.calculateGap();
                this.initEvents();

                let mouseMoveVals = {translation: 0, rotation: -8};
                const render = () => {
                    mouseMoveVals.translation = MathUtils.lerp(mouseMoveVals.translation, MathUtils.lineEq(-15, 15, winsize.width, 0, mousePos.x), 0.03);
                    for (let i = 0; i <= this.slidesTotal - 1; ++i) {
                        gsap.set(this.slides[i].DOM.img, {x: mouseMoveVals.translation});
                        gsap.set(this.DOM.titlesInner, {x: -4*mouseMoveVals.translation});
                    }
                    requestAnimationFrame(render);
                }
                requestAnimationFrame(render);
            }
            setVisibleSlides() {
                this.centerSlide = this.slides[this.center];
                this.rightSlide = this.slides[this.center+1 <= this.slidesTotal-1 ? this.center+1 : 0];
                this.leftSlide = this.slides[this.center-1 >= 0 ? this.center-1 : this.slidesTotal-1];
                this.centerSlide.setCenter();
                this.rightSlide.setRight();
                this.leftSlide.setLeft();
            }
            // Distance between 2 slides
            // The amount to translate the elements that move when we navigate the slideshow
            calculateGap() {
                const s1 = this.slides[0].DOM.el.getBoundingClientRect();
                const s2 = this.slides[1].DOM.el.getBoundingClientRect();
                this.gap = MathUtils.distance(s1.left + s1.width/2, s2.left + s2.width/2, s1.top + s1.height/2, s2.top + s2.height/2);
            }
            // Initialize events
            initEvents() {
                this.clickRightFn = () => this.navigate('right');
                this.DOM.interaction.right.addEventListener('click', this.clickRightFn);

                this.clickLeftFn = () => this.navigate('left');
                this.DOM.interaction.left.addEventListener('click', this.clickLeftFn);

                this.clickCenterFn = () => this.openSlide();
                this.DOM.interaction.center.addEventListener('click', this.clickCenterFn);

                this.mouseenterCenterFn = () => {
                    if ( this.isAnimating ) {
                        return;
                    }
                    gsap.timeline()
                    .to(this.centerSlide.DOM.imgWrap, {
                        duration: 0.7,
                        ease: Expo.easeOut,
                        scale: 1.02
                    })
                    .to(this.centerSlide.DOM.img, {
                        duration: 1.7,
                        ease: Expo.easeOut,
                        scale: 1.05
                    }, 0);
                };
                this.DOM.interaction.center.addEventListener('mouseenter', this.mouseenterCenterFn);

                this.mouseleaveCenterFn = () => {
                    if ( this.isAnimating ) {
                        return;
                    }
                    gsap.timeline().to(this.centerSlide.DOM.imgWrap, {
                        duration: 0.7,
                        ease: Expo.easeOut,
                        scale: 1
                    })
                    .to(this.centerSlide.DOM.img, {
                        duration: 0.7,
                        ease: Expo.easeOut,
                        scale: 1
                    }, 0);
                };
                this.DOM.interaction.center.addEventListener('mouseleave', this.mouseleaveCenterFn);

                this.resizeFn = () => this.calculateGap();
                window.addEventListener('resize', this.resizeFn);

                this.DOM.contentItems.forEach(item => {
                    item.querySelector('.img-wrap--content').addEventListener('click', () => this.closeSlide());
                });
            }
            navigate(direction) {
                if ( this.isAnimating ) {
                    return false;
                }
                this.isAnimating = true;

                const upcomingPos = direction === 'right' ?
                this.center < this.slidesTotal-2 ? this.center+2 : Math.abs(this.slidesTotal-2-this.center):
                this.center >= 2 ? this.center-2 : Math.abs(this.slidesTotal-2+this.center);

                // Update current.
                this.center = direction === 'right' ?
                this.center < this.slidesTotal-1 ? this.center+1 : 0 :
                this.center > 0 ? this.center-1 : this.slidesTotal-1;

                this.upcomingSlide = this.slides[upcomingPos];
                this.upcomingTitle = this.upcomingSlide.DOM.title;
                // Position upcomingSlide / upcomingTitle
                gsap.set(this.upcomingSlide.DOM.el, {x: direction === 'right' ? this.gap*2 : -1*this.gap*2, opacity: 1});
                gsap.set(this.upcomingTitle, {x: direction === 'right' ? this.gap*2 : -1*this.gap*2, opacity: 1});

                const movingSlides = [this.upcomingSlide, this.centerSlide, this.rightSlide, this.leftSlide];
                let promises = [];
                movingSlides.forEach(slide => promises.push(slide.move(direction === 'right' ? 'left' : 'right', this.gap)));
                Promise.all(promises).then(() => {
                    // After all is moved, update the classes of the 3 visible slides and reset styles
                    movingSlides.forEach(slide => slide.reset());
                    // Set it again
                    this.setVisibleSlides();
                    this.isAnimating = false;
                });
            }
            openSlide() {
                this.toggleSlide('open');
            }
            closeSlide() {
                this.toggleSlide('close');
            }
            toggleSlide(action) {
                if ( this.isAnimating ) {
                    return;
                }
                this.isAnimating = true;

                const contentItem = this.DOM.contentItems[this.center];
                // Cursor styles related class
                this.DOM.el.classList[action === 'open' ? 'add' : 'remove']('content-open');

                const movingSlides = [this.centerSlide, this.rightSlide, this.leftSlide];
                let promises = [];
                movingSlides.forEach(slide => promises.push(slide[action === 'open' ? 'animateElementsOut' : 'animateElementsIn'](contentItem)));

                if ( action === 'open' ) {
                    contentItem.classList.add('content__item--current');
                }
                Promise.all(promises).then(() => {
                    if ( action === 'close' ) {
                        contentItem.classList.remove('content__item--current');
                    }
                    this.isAnimating = false;
                });
            }
        }

        class Revealer {
            constructor(el) {
                this.DOM = {el: el};
                this.DOM.el.style.width = `calc(100vw * ${Math.cos(8 * Math.PI/180)} + 100vh * ${Math.sin(8 * Math.PI/180)})`;
                this.DOM.el.style.height = `calc(100vw * ${Math.sin(8 * Math.PI/180)} + 100vh * ${Math.cos(8 * Math.PI/180)})`;
            }
        }

        // Revealer element
        const revealer = new Revealer(document.querySelector('.revealer__inner'));
        // Initialize the slideshow
        new Slideshow(document.querySelector('.grid--slideshow'));
        document.body.classList.add('crossslider-cursor');
        // Preload all the images in the page
        imagesLoaded(document.querySelectorAll('.img'), {background: true}, () => document.body.classList.remove('loading'));
        
        $( '.cross-slider .grid__item, .cross-slider .img-wrap' ).hover(
          function() {
            $( '.wixi-cursor' ).addClass( 'hide' );
          }, function() {
            $( '.wixi-cursor' ).removeClass( 'hide' );
          }
        );

    }

    jQuery(window).on('elementor/frontend/init', function () {
        elementorFrontend.hooks.addAction('frontend/element_ready/wixi-crossroads-slideshow.default', crossSlider);
    });

})(jQuery);
