(function() {

    window.CanvasSlideshow = function( options ) {



      //  SCOPE
      /// ---------------------------
      var that  =   this;



      //  OPTIONS
      /// ---------------------------
      options                     = options || {};
      options.stageWidth          = options.hasOwnProperty('stageWidth') ? options.stageWidth : 1920;
      options.stageHeight         = options.hasOwnProperty('stageHeight') ? options.stageHeight : 1080;
      options.pixiSprites         = options.hasOwnProperty('sprites') ? options.sprites : [];
      options.centerSprites       = options.hasOwnProperty('centerSprites') ? options.centerSprites : false;
      options.texts               = options.hasOwnProperty('texts') ? options.texts : [];
      options.autoPlay            = options.hasOwnProperty('autoPlay') ? options.autoPlay : true;
      options.autoPlaySpeed       = options.hasOwnProperty('autoPlaySpeed') ? options.autoPlaySpeed : [10, 3];
      options.fullScreen          = options.hasOwnProperty('fullScreen') ? options.fullScreen : true;
      options.displaceScale       = options.hasOwnProperty('displaceScale') ? options.displaceScale : [200, 70];
      options.displacementImage   = options.hasOwnProperty('displacementImage') ? options.displacementImage : '';
      options.navElement          = options.hasOwnProperty('navElement')  ?  options.navElement : document.querySelectorAll( '.scene-nav' );
      options.displaceAutoFit     = options.hasOwnProperty('displaceAutoFit')  ?  options.displaceAutoFit : false;
      options.wacky               = options.hasOwnProperty('wacky') ? options.wacky : false;
      options.interactive         = options.hasOwnProperty('interactive') ? options.interactive : false;
      options.interactionEvent    = options.hasOwnProperty('interactionEvent') ? options.interactionEvent : '';
      options.displaceScaleTo     = ( options.autoPlay === false ) ? [ 0, 0 ] : [ 20, 20 ];
      options.textColor           = options.hasOwnProperty('textColor') ? options.textColor : '#fff';
      options.displacementCenter  = options.hasOwnProperty('displacementCenter') ? options.displacementCenter : false;
      options.dispatchPointerOver = options.hasOwnProperty('dispatchPointerOver') ? options.dispatchPointerOver : false;



      //  PIXI VARIABLES
      /// ---------------------------
      var renderer            = new PIXI.autoDetectRenderer( options.stageWidth, options.stageHeight, { transparent: true });
      var stage               = new PIXI.Container();
      var slidesContainer     = new PIXI.Container();
      var displacementSprite  = new PIXI.Sprite.fromImage( options.displacementImage );
      var displacementFilter  = new PIXI.filters.DisplacementFilter( displacementSprite );



      //  TEXTS
      /// ---------------------------
      var style = new PIXI.TextStyle({
        fill: options.textColor,
        wordWrap: true,
        wordWrapWidth: 400,
        fontSize: 36
      });



      //  SLIDES ARRAY INDEX
      /// ---------------------------
      this.currentIndex = 0;



      /// ---------------------------
      //  INITIALISE PIXI
      /// ---------------------------
      this.initPixi = function() {

        // Add canvas to the HTML
        document.body.appendChild( renderer.view );


        // Add child container to the main container
        stage.addChild( slidesContainer );


        // Enable Interactions
        stage.interactive = true;


        // Fit renderer to the screen
        if ( options.fullScreen === true ) {
          renderer.view.style.objectFit = 'cover';
          renderer.view.style.width     = '100%';
          renderer.view.style.height    = '100%';
          renderer.view.style.top       = '50%';
          renderer.view.style.left      = '50%';
          renderer.view.style.webkitTransform = 'translate( -50%, -50% ) scale(1.2)';
          renderer.view.style.transform = 'translate( -50%, -50% ) scale(1.2)';
        } else {
          renderer.view.style.maxWidth  = '100%';
          renderer.view.style.top       = '50%';
          renderer.view.style.left      = '50%';
          renderer.view.style.webkitTransform = 'translate( -50%, -50% )';
          renderer.view.style.transform = 'translate( -50%, -50% )';
        }


        displacementSprite.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT;


        // Set the filter to stage and set some default values for the animation
        stage.filters = [displacementFilter];

        if ( options.autoPlay === false ) {
          displacementFilter.scale.x = 0;
          displacementFilter.scale.y = 0;
        }

        if ( options.wacky === true ) {

          displacementSprite.anchor.set(0.5);
          displacementSprite.x = renderer.width / 2;
          displacementSprite.y = renderer.height / 2;
        }

        displacementSprite.scale.x = 2;
        displacementSprite.scale.y = 2;

        // PIXI tries to fit the filter bounding box to the renderer so we optionally bypass
        displacementFilter.autoFit = options.displaceAutoFit;

        stage.addChild( displacementSprite );

      };



      /// ---------------------------
      //  LOAD SLIDES TO CANVAS
      /// ---------------------------
      this.loadPixiSprites = function( sprites ) {


        var rSprites = options.sprites;
        var rTexts   = options.texts;

        for ( var i = 0; i < rSprites.length; i++ ) {

          var texture   = new PIXI.Texture.fromImage( sprites[i] );
          var image     = new PIXI.Sprite( texture );

          if ( rTexts ) {
            var richText = new PIXI.Text( rTexts[i], style);
            image.addChild(richText);

            richText.anchor.set(0.5);
            richText.x = image.width / 2;
            richText.y = image.height / 2;
          }

          if ( options.centerSprites === true ) {
            image.anchor.set(0.5);
            image.x = renderer.width / 2;
            image.y = renderer.height / 2;
          }
          // image.transform.scale.x = 1.3;
          // image.transform.scale.y = 1.3;



          if ( i !== 0  ) {
            TweenMax.set( image, { alpha: 0 } );
          }

          slidesContainer.addChild( image );

        }

      };



      /// ---------------------------
      //  DEFAULT RENDER/ANIMATION
      /// ---------------------------
      if ( options.autoPlay === true ) {

        var ticker = new PIXI.ticker.Ticker();

        ticker.autoStart = options.autoPlay;

        ticker.add(function( delta ) {

          displacementSprite.x += options.autoPlaySpeed[0] * delta;
          displacementSprite.y += options.autoPlaySpeed[1];

          renderer.render( stage );

        });

      }  else {

          var render = new PIXI.ticker.Ticker();

          render.autoStart = true;

          render.add(function( delta ) {
            renderer.render( stage );
          });

      }


      /// ---------------------------
      //  TRANSITION BETWEEN SLIDES
      /// ---------------------------
      var isPlaying   = false;
      var slideImages = slidesContainer.children;
      this.moveSlider = function( newIndex ) {

        isPlaying = true;


        var baseTimeline = new TimelineMax( { onComplete: function () {
          that.currentIndex = newIndex;
          isPlaying = false;
          if ( options.wacky === true ) {
            displacementSprite.scale.set( 1 );
          }
         },onUpdate: function() {

            if ( options.wacky === true ) {
              displacementSprite.rotation += baseTimeline.progress() * 0.02;
              displacementSprite.scale.set( baseTimeline.progress() * 3 );
            }

        } });

        baseTimeline.clear();

        if ( baseTimeline.isActive() ) {
          return;
        }

        // DEMO 4
        baseTimeline
        .to(displacementFilter.scale, 1, { x: options.displaceScale[0], y: options.displaceScale[1], ease: Power1.easeOut  })
        .to(slideImages[that.currentIndex], 0.5, { alpha: 0, ease: Power2.easeOut }, 0.2)
        .to(slideImages[newIndex], 0.5, { alpha: 1, ease: Power2.easeOut }, 0.3)
        .to(displacementFilter.scale, 1, { x: options.displaceScaleTo[0], y: options.displaceScaleTo[1], ease: Power2.easeOut }, 0.3 );

      };



      /// ---------------------------
      //  CLICK HANDLERS
      /// ---------------------------
      var nav = options.navElement;

      for ( var i = 0; i < nav.length; i++ ) {

        var navItem = nav[i];

        navItem.onclick = function( event ) {

          // Make sure the previous transition has ended
          if ( isPlaying ) {
            return false;
          }

          if ( this.getAttribute('data-nav') === 'next' ) {

            if ( that.currentIndex >= 0 && that.currentIndex < slideImages.length - 1 ) {
              that.moveSlider( that.currentIndex + 1 );
            } else {
              that.moveSlider( 0 );
            }

          } else {

            if ( that.currentIndex > 0 && that.currentIndex < slideImages.length ) {
              that.moveSlider( that.currentIndex - 1 );
            } else {
              that.moveSlider( spriteImages.length - 1 );
            }

          }

          return false;

        }

      }



      /// ---------------------------
      //  INIT FUNCTIONS
      /// ---------------------------

      this.init = function() {


        that.initPixi();
        that.loadPixiSprites( options.pixiSprites );

        /*
        if ( options.fullScreen === true ) {
          window.addEventListener("resize", function( event ){
            scaleToWindow( renderer.view );
          });
          scaleToWindow( renderer.view );
        }
        */


      };




      /// ---------------------------
      //  INTERACTIONS
      /// ---------------------------
      function rotateSpite() {
        displacementSprite.rotation += 0.001;
        rafID = requestAnimationFrame( rotateSpite );
      }

      if ( options.interactive === true ) {

        var rafID, mouseX, mouseY;

        // Enable interactions on our slider
        slidesContainer.interactive = true;
        slidesContainer.buttonMode  = true;

        // HOVER
        if ( options.interactionEvent === 'hover' || options.interactionEvent === 'both'  )  {

          slidesContainer.pointerover = function( mouseData ){
            mouseX = mouseData.data.global.x;
            mouseY = mouseData.data.global.y;
            TweenMax.to( displacementFilter.scale, 1, { x: "+=" + Math.sin( mouseX ) * 100 + "", y: "+=" + Math.cos( mouseY ) * 100 + ""  });
            rotateSpite();
          };

          slidesContainer.pointerout = function( mouseData ){
            TweenMax.to( displacementFilter.scale, 1, { x: 0, y: 0 });
            cancelAnimationFrame( rafID );
          };

        }

        // CLICK
        if ( options.interactionEvent === 'click' || options.interactionEvent === 'both'  ) {

          slidesContainer.pointerup = function( mouseData ){
            if ( options.dispatchPointerOver === true ) {
              TweenMax.to( displacementFilter.scale, 1, { x: 0, y: 0, onComplete: function() {
                TweenMax.to( displacementFilter.scale, 1, { x: 20, y: 20  });
              } });
            } else {
              TweenMax.to( displacementFilter.scale, 1, { x: 0, y: 0 });
              cancelAnimationFrame( rafID );
            }

          };

          slidesContainer.pointerdown = function( mouseData ){
            mouseX = mouseData.data.global.x;
            mouseY = mouseData.data.global.y;
            TweenMax.to( displacementFilter.scale, 1, { x: "+=" + Math.sin( mouseX ) * 1200 + "", y: "+=" + Math.cos( mouseY ) * 200 + ""  });
          };

          slidesContainer.pointerout = function( mouseData ){
            if ( options.dispatchPointerOver === true ) {
              TweenMax.to( displacementFilter.scale, 1, { x: 0, y: 0, onComplete: function() {
                TweenMax.to( displacementFilter.scale, 1, { x: 20, y: 20  });
              } });
            } else {
              TweenMax.to( displacementFilter.scale, 1, { x: 0, y: 0 });
              cancelAnimationFrame( rafID );
            }

          };

        }

      }



      /// ---------------------------
      //  CENTER DISPLACEMENT
      /// ---------------------------
      if ( options.displacementCenter === true ) {
        displacementSprite.anchor.set(0.5);
        displacementSprite.x = renderer.view.width / 2;
        displacementSprite.y = renderer.view.height / 2;
      }


      /// ---------------------------
      //  START
      /// ---------------------------
      this.init();


      /// ---------------------------
      //  HELPER FUNCTIONS
      /// ---------------------------
      function scaleToWindow( canvas, backgroundColor ) {
        var scaleX, scaleY, scale, center;

        //1. Scale the canvas to the correct size
        //Figure out the scale amount on each axis
        scaleX = window.innerWidth / canvas.offsetWidth;
        scaleY = window.innerHeight / canvas.offsetHeight;

        //Scale the canvas based on whichever value is less: `scaleX` or `scaleY`
        scale = Math.min(scaleX, scaleY);
        canvas.style.transformOrigin = "0 0";
        canvas.style.transform = "scale(" + scale + ")";

        //2. Center the canvas.
        //Decide whether to center the canvas vertically or horizontally.
        //Wide canvases should be centered vertically, and
        //square or tall canvases should be centered horizontally
        if (canvas.offsetWidth > canvas.offsetHeight) {
          if (canvas.offsetWidth * scale < window.innerWidth) {
            center = "horizontally";
          } else {
            center = "vertically";
          }
        } else {
          if (canvas.offsetHeight * scale < window.innerHeight) {
            center = "vertically";
          } else {
            center = "horizontally";
          }
        }

        //Center horizontally (for square or tall canvases)
        var margin;
        if (center === "horizontally") {
          margin = (window.innerWidth - canvas.offsetWidth * scale) / 2;
          canvas.style.marginTop = 0 + "px";
          canvas.style.marginBottom = 0 + "px";
          canvas.style.marginLeft = margin + "px";
          canvas.style.marginRight = margin + "px";
        }

        //Center vertically (for wide canvases)
        if (center === "vertically") {
          margin = (window.innerHeight - canvas.offsetHeight * scale) / 2;
          canvas.style.marginTop = margin + "px";
          canvas.style.marginBottom = margin + "px";
          canvas.style.marginLeft = 0 + "px";
          canvas.style.marginRight = 0 + "px";
        }

        //3. Remove any padding from the canvas  and body and set the canvas
        //display style to "block"
        canvas.style.paddingLeft = 0 + "px";
        canvas.style.paddingRight = 0 + "px";
        canvas.style.paddingTop = 0 + "px";
        canvas.style.paddingBottom = 0 + "px";
        canvas.style.display = "block";

        //4. Set the color of the HTML body background
        document.body.style.backgroundColor = backgroundColor;

        //Fix some quirkiness in scaling for Safari
        var ua = navigator.userAgent.toLowerCase();
        if (ua.indexOf("safari") != -1) {
          if (ua.indexOf("chrome") > -1) {
            // Chrome
          } else {
            // Safari
            //canvas.style.maxHeight = "100%";
            //canvas.style.minHeight = "100%";
          }
        }

        //5. Return the `scale` value. This is important, because you'll nee this value
        //for correct hit testing between the pointer and sprites
        return scale;
      } // http://bit.ly/2y1Yk2k


    };

  })();