/**
  @module ember-data
*/

import Ember from 'ember';
import { PromiseArray } from "ember-data/-private/system/promise-proxies";
import SnapshotRecordArray from "ember-data/-private/system/snapshot-record-array";

const { get, set, RSVP: { Promise } } = Ember;

/**
  A record array is an array that contains records of a certain type. The record
  array materializes records as needed when they are retrieved for the first
  time. You should not create record arrays yourself. Instead, an instance of
  `DS.RecordArray` or its subclasses will be returned by your application's store
  in response to queries.

  @class RecordArray
  @namespace DS
  @extends Ember.ArrayProxy
  @uses Ember.Evented
*/

export default Ember.ArrayProxy.extend(Ember.Evented, {
  init() {
    this._super(...arguments);

    /**
      The model type contained by this record array.

      @property type
      @type DS.Model
      */
    this.type = this.type || null;

    /**
      The array of client ids backing the record array. When a
      record is requested from the record array, the record
      for the client id at the same index is materialized, if
      necessary, by the store.

      @property content
      @private
      @type Ember.Array
      */
    this.content = this.content || null;

    /**
    The flag to signal a `RecordArray` is finished loading data.

    Example

    ```javascript
    var people = store.peekAll('person');
    people.get('isLoaded'); // true
    ```

    @property isLoaded
    @type Boolean
    */
    this.isLoaded = this.isLoaded || false;
      /**
    The flag to signal a `RecordArray` is currently loading data.

    Example

    ```javascript
    var people = store.peekAll('person');
    people.get('isUpdating'); // false
    people.update();
    people.get('isUpdating'); // true
    ```

    @property isUpdating
    @type Boolean
    */
    this.isUpdating = false;

      /**
    The store that created this record array.

    @property store
    @private
    @type DS.Store
    */
    this.store = this.store || null;
    this._updatingPromise = null;
  },
  replace() {
    let type = get(this, 'type').toString();
    throw new Error(`The result of a server query (for all ${type} types) is immutable. To modify contents, use toArray()`);
  },

  /**
    Retrieves an object from the content by index.

    @method objectAtContent
    @private
    @param {Number} index
    @return {DS.Model} record
  */
  objectAtContent(index) {
    let internalModel = get(this, 'content').objectAt(index);
    return internalModel && internalModel.getRecord();
  },

  /**
    Used to get the latest version of all of the records in this array
    from the adapter.

    Example

    ```javascript
    var people = store.peekAll('person');
    people.get('isUpdating'); // false

    people.update().then(function() {
      people.get('isUpdating'); // false
    });

    people.get('isUpdating'); // true
    ```

    @method update
  */
  update() {
    if (get(this, 'isUpdating')) { return this._updatingPromise; }

    this.set('isUpdating', true);

    let updatingPromise = this._update().finally(() => {
      this._updatingPromise = null;
      if (this.get('isDestroying') || this.get('isDestroyed')) { return }
      this.set('isUpdating', false);
    });

    this._updatingPromise = updatingPromise;

    return updatingPromise;
  },

  /*
    Update this RecordArray and return a promise which resolves once the update
    is finished.
   */
  _update() {
    let store = get(this, 'store');
    let modelName = get(this, 'type.modelName');

    return store.findAll(modelName, { reload: true });
  },

  /**
    Adds an internal model to the `RecordArray` without duplicates

    @method addInternalModel
    @private
    @param {InternalModel} internalModel
  */
  addInternalModel(internalModel) {
    get(this, 'content').addObject(internalModel);
  },

  /**
    Removes an internalModel to the `RecordArray`.

    @method removeInternalModel
    @private
    @param {InternalModel} internalModel
  */
  removeInternalModel(internalModel) {
    get(this, 'content').removeObject(internalModel);
  },

  /**
    Saves all of the records in the `RecordArray`.

    Example

    ```javascript
    var messages = store.peekAll('message');
    messages.forEach(function(message) {
      message.set('hasBeenSeen', true);
    });
    messages.save();
    ```

    @method save
    @return {DS.PromiseArray} promise
  */
  save() {
    let promiseLabel = 'DS: RecordArray#save ' + get(this, 'type');
    let promise = Promise.all(this.invoke('save'), promiseLabel).
      then(() => this, null, 'DS: RecordArray#save return RecordArray');

    return PromiseArray.create({ promise });
  },

  _dissociateFromOwnRecords() {
    this.get('content').forEach(record => {
      let recordArrays = record._recordArrays;

      if (recordArrays) {
        recordArrays.delete(this);
      }
    });
  },

  /**
    @method _unregisterFromManager
    @private
  */
  _unregisterFromManager() {
    get(this, 'manager').unregisterRecordArray(this);
  },

  willDestroy() {
    this._unregisterFromManager();
    this._dissociateFromOwnRecords();
    set(this, 'content', undefined);
    set(this, 'length', 0);
    this._super(...arguments);
  },

  createSnapshot(options) {
    return new SnapshotRecordArray(this, this.get('meta'), options);
  }
});

@@ -2097,16 +2097,17 @@
 l;%0A  %7D,%0A
+%0A
   replac

add whitespace