/* globals _ */

/**
 * Adds loading state to the class.
 * @class
 */
import Ember from 'ember';
import Serializer from 'web-client/models/core/serializers/serializer';

const { Evented, Mixin, RSVP } = Ember;

export default Mixin.create(Evented, {
  /** Publicly exposed properties and methods */

  /**
   * @overridden
   */
  serializer: Serializer.create(),
  isLoaded: false,
  isLoading: false,

  load(options) {
    if (!this.get('isLoading') && this._shouldLoad()) {
      this.set('error', null);
      this.set('isLoading', true);

      this.set('_loadingPromise', this.apiLoad(options).then((response) => {
        if (this.isDestroyed) { return; }
        this._loadSuccess(response);
        return this;
      }, (jqXHR, textStatus, errorThrown) => {
        if (this.isDestroyed) { return; }
        this._onLoadFailure(jqXHR, textStatus, errorThrown);
        throw this;
      }));
    }

    if (!this.get('_loadingPromise')) {
      this.set('_loadingPromise', RSVP.resolve(this));
    }
    return this.get('_loadingPromise');
  },

  /** Private helpers */

  /**
   * @overridden
   * @returns {boolean}
   * @private
   */
  _shouldLoad: function () {
    return !this.get('isLoaded');
  },
  _loadSuccess(response) {
    // note that as of ember 1.6.0, Ember event callbacks are synchronous
    //   whereas observers are asynchronous.
    let content = this._setContent(response);
    this.set('isLoaded', true);
    this.set('isLoading', false);
    this.trigger('loadSuccess');
    this.trigger('contentSet', content);
  },
  _onLoadFailure: function (jqXHR, textStatus, errorThrown) {
    this.set('error', jqXHR);
    this.set('isLoading', false);
    this.trigger('loadFail', jqXHR, textStatus, errorThrown);
  },

  /**
   * @overridden
   */
  _setContent(rawContent) {
    let keys = [];
    let content = this.get('serializer').deserialize(rawContent);
    if (content && _.isObject(content) && !_.isArray(content)) {
      keys = _.keys(content);
    }
    this.set('__keys', keys);
    this.setProperties(content);
    return content;
  }
});
