/**
 * IAS History Extension
 * An IAS extension to enable browser history
 * https://infiniteajaxscroll.com
 *
 * This file is part of the Infinite AJAX Scroll package
 *
 * Copyright 2014-2018 Webcreate (Jeroen Fiege)
 */

var IASHistoryExtension = function (options) {
  options = jQuery.extend({}, this.defaults, options);

  this.ias = null;
  this.prevSelector = options.prev;
  this.prevUrl = null;
  this.listeners = {
    prev: new IASCallbacks(jQuery)
  };

  /**
   * @private
   * @param pageNum
   * @param scrollOffset
   * @param url
   */
  this.onPageChange = function (pageNum, scrollOffset, url) {
    if (!window.history || !window.history.replaceState) {
      return;
    }
    
    var state = history.state;

    history.replaceState(state, document.title, url);
  };

  /**
   * @private
   * @param currentScrollOffset
   * @param scrollThreshold
   */
  this.onScroll = function (currentScrollOffset, scrollThreshold) {
    var firstItemScrollThreshold = this.getScrollThresholdFirstItem();

    if (!this.prevUrl) {
      return;
    }

    currentScrollOffset -= this.ias.$scrollContainer.height();

    if (currentScrollOffset <= firstItemScrollThreshold) {
      this.prev();
    }
  };

  this.onReady = function () {
    var currentScrollOffset = this.ias.getCurrentScrollOffset(this.ias.$scrollContainer),
        firstItemScrollThreshold = this.getScrollThresholdFirstItem();

    currentScrollOffset -= this.ias.$scrollContainer.height();

    if (currentScrollOffset <= firstItemScrollThreshold) {
      this.prev();
    }
  };

  /**
   * Returns the url for the next page
   *
   * @private
   */
  this.getPrevUrl = function (container) {
    if (!container) {
      container = this.ias.$container;
    }

    // always take the last matching item
    return jQuery(this.prevSelector, container).last().attr('href');
  };

  /**
   * Returns scroll threshold. This threshold marks the line from where
   * IAS should start loading the next page.
   *
   * @private
   * @return {number}
   */
  this.getScrollThresholdFirstItem = function () {
    var $firstElement;

    $firstElement = this.ias.getFirstItem();

    // if the don't have a first element, the DOM might not have been loaded,
    // or the selector is invalid
    if (0 === $firstElement.length) {
      return -1;
    }

    return ($firstElement.offset().top);
  };

  /**
   * Renders items
   *
   * @private
   * @param items
   * @param callback
   */
  this.renderBefore = function (items, callback) {
    var ias = this.ias,
        $firstItem = ias.getFirstItem(),
        count = 0;

    ias.fire('render', [items]);

    jQuery(items).hide(); // at first, hide it so we can fade it in later

    $firstItem.before(items);

    jQuery(items).fadeIn(400, function () {
      if (++count < items.length) {
        return;
      }

      ias.fire('rendered', [items]);

      if (callback) {
        callback();
      }
    });
  };

  return this;
};

/**
 * @public
 */
IASHistoryExtension.prototype.initialize = function (ias) {
  var self = this;

  this.ias = ias;

  // expose the extensions listeners
  jQuery.extend(ias.listeners, this.listeners);

  // expose prev method
  ias.prev = function() {
    return self.prev();
  };

  this.prevUrl = this.getPrevUrl();
};

/**
 * Bind to events
 *
 * @public
 * @param ias
 */
IASHistoryExtension.prototype.bind = function (ias) {
  ias.on('pageChange', jQuery.proxy(this.onPageChange, this));
  ias.on('scroll', jQuery.proxy(this.onScroll, this));
  ias.on('ready', jQuery.proxy(this.onReady, this));
};

/**
 * @public
 * @param {object} ias
 */
IASHistoryExtension.prototype.unbind = function(ias) {
  ias.off('pageChange', this.onPageChange);
  ias.off('scroll', this.onScroll);
  ias.off('ready', this.onReady);
};

/**
 * Load the prev page
 *
 * @public
 */
IASHistoryExtension.prototype.prev = function () {
  var url = this.prevUrl,
      self = this,
      ias = this.ias;

  if (!url) {
    return false;
  }

  ias.pause();

  var promise = ias.fire('prev', [url]);

  promise.done(function () {
    ias.load(url, function (data, items) {
      self.renderBefore(items, function () {
        self.prevUrl = self.getPrevUrl(data);

        ias.resume();

        if (self.prevUrl) {
          self.prev();
        }
      });
    });
  });

  promise.fail(function () {
    ias.resume();
  });

  return true;
};

/**
 * @public
 */
IASHistoryExtension.prototype.defaults = {
  prev: ".prev"
};
