/**

* Wrapper for creating animation when an element appear in the screen.
*
* @author Htmlstream
* @version 1.0
* @requires appear.js 
*
*/

; (function($) {

'use strict';

$.HSCore.components.HSOnScrollAnimation = {

  /**
   * Base configuration.
   *
   * @var Object _baseConfig
   */
  _baseConfig: {
    bounds: -100,
    debounce: 50,
    inViewportClass: 'u-in-viewport',
    animation: 'fadeInUp',
    animationOut: false,
    animationDelay: 0,
    animationDuration: 1000,
    afterShow: function(){},
    onShown: function(){},
    onHidded: function(){}
  },

  /**
   * Collection of all instances of the page.
   *
   * @var jQuery _pageCollection
   */
  _pageCollection: $(),

  /**
   * Initialization of animation.
   *
   * @param jQuery selector (optional)
   * @param Object config (optional)
   *
   * @return jQuery _pageCollection - collection of initialized items.
   */
  init: function(selector, config) {

    if( !selector || !$(selector).length ) return;

    var self = this;

    this.config = config && $.isPlainObject(config) ? $.extend(true, {}, this._baseConfig, config) : this._baseConfig;

    appear({
      bounds: self.config['bounds'],
      reappear: false,
      debounce: self.config['debounce'],
      elements: function(){
        return document.querySelectorAll(selector);
      },
      init: function() {
        $(selector).each(function(i, el){

          var $this = $(el);

          if(!$this.data('HSAnimationElement')) {
            $this.data('HSAnimationElement', new HSAnimationElement( $this, self.config ));

            self._pageCollection = self._pageCollection.add($this);
          }

        });
      },
      appear: function(el) {

        var $el = $(el);

        if(!$el.hasClass( self.config.inViewportClass )) {
          $el.data('HSAnimationElement').show();
        }
      }

    })

    return this._pageCollection;

  }

}

/**
 * HSAnimationElement constructor function.
 * 
 * @param jQuery element
 * @param Object config
 *
 * @return undefined
 */
function HSAnimationElement(element, config) {

  if( !element || !element.length ) return;

  var self = this;

  this.element = element;
  this.config = config && $.isPlainObject(config) ? $.extend(true, {}, config, element.data()) : element.data();

  if( !isFinite( this.config.animationDelay ) ) this.config.animationDelay = 0;
  if( !isFinite( this.config.animationDuration ) ) this.config.animationDuration = 1000;

  element.css({
    'animation-duration': self.config.animationDuration + 'ms'
  });

}

/**
 * Shows element.
 * 
 * @return undefined
 */
HSAnimationElement.prototype.show = function() {

  var self = this;

  if(this.config.animationDelay) {
    this.timeOutId = setTimeout( function(){

      self.element
          .removeClass(self.config.animationOut)
          .addClass(self.config.animation + ' ' + self.config.inViewportClass);
      self.config.afterShow.call( self.element );

      self.callbackTimeoutId = setTimeout( function(){
        self.config.onShown.call( self.element );
      }, self.config.animationDuration );

    }, this.config.animationDelay );
  }
  else {
    this.element
        .removeClass(this.config.animationOut)
        .addClass(this.config.animation + ' ' + this.config.inViewportClass);
    this.config.afterShow.call( this.element );

    this.callbackTimeoutId = setTimeout( function(){
      self.config.onShown.call( self.element );
    }, this.config.animationDuration );
  }

}

/**
 * Hides element.
 * 
 * @return undefined
 */
HSAnimationElement.prototype.hide = function() {

  var self = this;

  if( !this.element.hasClass(this.config.inViewportClass) ) return;

  if( this.config.animationOut ) {

    this.element
      .removeClass( this.config.animation )
      .addClass( this.config.animationOut );

    this.callbackTimeoutId = setTimeout(function(){

      self.element.removeClass(self.config.inViewportClass);
      self.config.onHidded.call( self.element );

    }, this.config.animationDuration);

  }
  else {

    this.element.removeClass(this.config.inViewportClass + ' ' + this.config.animation);
    this.config.onHidded.call( this.element );
  }

}

})(jQuery);