require("ember-data/system/record_arrays/record_array");

var get = Ember.get, set = Ember.set;

/**
  A ManyArray is a RecordArray that represents the contents of a has-many
  association.

  The ManyArray is instantiated lazily the first time the association is
  requested.

  ### Inverses

  Often, the associations in Ember Data applications will have
  an inverse. For example, imagine the following models are
  defined:

      App.Post = DS.Model.extend({
        comments: DS.hasMany('App.Comment')
      });

      App.Comment = DS.Model.extend({
        post: DS.belongsTo('App.Post')
      });

  If you created a new instance of `App.Post` and added
  a `App.Comment` record to its `comments` has-many
  association, you would expect the comment's `post`
  property to be set to the post that contained
  the has-many.

  We call the record to which an association belongs the
  association's _owner_.
*/
DS.ManyArray = DS.RecordArray.extend({
  init: function() {
    this._super.apply(this, arguments);
    this._changesToSync = Ember.OrderedSet.create();
  },

  /**
    @private

    The record to which this association belongs.

    @property {DS.Model}
  */
  owner: null,

  // LOADING STATE

  isLoaded: false,

  loadingRecordsCount: function(count) {
    this.loadingRecordsCount = count;
  },

  loadedRecord: function() {
    this.loadingRecordsCount--;
    if (this.loadingRecordsCount === 0) {
      set(this, 'isLoaded', true);
      this.trigger('didLoad');
    }
  },

  fetch: function() {
    var references = get(this, 'content'),
        store = get(this, 'store'),
        type = get(this, 'type');

    store.fetchUnloadedReferences(type, references);
  },

  // Overrides Ember.Array's replace method to implement
  replaceContent: function(index, removed, added) {
    // Map the array of record objects into an array of  client ids.
    added = added.map(function(record) {
      Ember.assert("You can only add records of " + (get(this, 'type') && get(this, 'type').toString()) + " to this association.", !get(this, 'type') || (get(this, 'type') === record.constructor));
      return get(record, 'reference');
    }, this);

    this._super(index, removed, added);
  },

  arrangedContentDidChange: function() {
    this.fetch();
  },

  arrayContentWillChange: function(index, removed, added) {
    var owner = get(this, 'owner'),
        name = get(this, 'name');

    if (!owner._suspendedAssociations) {
      // This code is the first half of code that continues inside
      // of arrayContentDidChange. It gets or creates a change from
      // the child object, adds the current owner as the old
      // parent if this is the first time the object was removed
      // from a ManyArray, and sets `newParent` to null.
      //
      // Later, if the object is added to another ManyArray,
      // the `arrayContentDidChange` will set `newParent` on
      // the change.
      for (var i=index; i<index+removed; i++) {
        var reference = get(this, 'content').objectAt(i);
        //var record = this.objectAt(i);
        //if (!record) { continue; }

        var change = DS.OneToManyChange.createChange(reference.clientId, get(this, 'store'), {
          parentType: owner.constructor,
          hasManyName: name,
          parentClientId: owner.get('clientId'),
          changeType: "remove"
        });
        change.hasManyName = name;

        if (change.oldParent === undefined) { change.oldParent = get(owner, 'clientId'); }
        change.newParent = null;
        this._changesToSync.add(change);
      }
    }

    return this._super.apply(this, arguments);
  },

  arrayContentDidChange: function(index, removed, added) {
    this._super.apply(this, arguments);

    var owner = get(this, 'owner'),
        name = get(this, 'name'),
        store = get(this, 'store');

    if (!owner._suspendedAssociations) {
      // This code is the second half of code that started in
      // `arrayContentWillChange`. It gets or creates a change
      // from the child object, and adds the current owner as
      // the new parent.
      for (var i=index; i<index+added; i++) {
        var reference = get(this, 'content').objectAt(i);

        var change = DS.OneToManyChange.createChange(reference.clientId, store, {
          parentType: owner.constructor,
          hasManyName: name,
          parentClientId: owner.get('clientId'),
          changeType: "add"
        });
        change.hasManyName = name;

        // The oldParent will be looked up in `sync` if it
        // was not set by `belongsToWillChange`.
        change.newParent = get(owner, 'clientId');
        this._changesToSync.add(change);
      }

      // We wait until the array has finished being
      // mutated before syncing the OneToManyChanges created
      // in arrayContentWillChange, so that the array
      // membership test in the sync() logic operates
      // on the final results.
      this._changesToSync.forEach(function(change) {
        change.sync();
      });
      DS.OneToManyChange.ensureSameTransaction(this._changesToSync, store);
      this._changesToSync.clear();
    }
  },

  // Create a child record within the owner
  createRecord: function(hash, transaction) {
    var owner = get(this, 'owner'),
        store = get(owner, 'store'),
        type = get(this, 'type'),
        record;

    transaction = transaction || get(owner, 'transaction');

    record = store.createRecord.call(store, type, hash, transaction);
    this.pushObject(record);

    return record;
  },

  /**
    METHODS FOR USE BY INVERSE RELATIONSHIPS
    ========================================

    These methods exists so that belongsTo relationships can
    set their inverses without causing an infinite loop.

    This creates two APIs:

    * the normal enumerable API, which is used by clients
      of the `ManyArray` and triggers a change to inverse
      `belongsTo` relationships.
    * `removeFromContent` and `addToContent`, which are
      used by inverse relationships and do not trigger a
      change to `belongsTo` relationships.

    Unlike the normal `addObject` and `removeObject` APIs,
    these APIs manipulate the `content` array without
    triggering side-effects.
  */

  /** @private */
  removeFromContent: function(record) {
    get(this, 'content').removeObject(get(record, 'reference'));
  },

  /** @private */
  addToContent: function(record) {
    get(this, 'content').addObject(get(record, 'reference'));
  }
});

@@ -5536,956 +5536,9 @@
 %0A  %7D
-,%0A%0A  /**%0A    METHODS FOR USE BY INVERSE RELATIONSHIPS%0A    ========================================%0A%0A    These methods exists so that belongsTo relationships can%0A    set their inverses without causing an infinite loop.%0A%0A    This creates two APIs:%0A%0A    * the normal enumerable API, which is used by clients%0A      of the %60ManyArray%60 and triggers a change to inverse%0A      %60belongsTo%60 relationships.%0A    * %60removeFromContent%60 and %60addToContent%60, which are%0A      used by inverse relationships and do not trigger a%0A      change to %60belongsTo%60 relationships.%0A%0A    Unlike the normal %60addObject%60 and %60removeObject%60 APIs,%0A    these APIs manipulate the %60content%60 array without%0A    triggering side-effects.%0A  */%0A%0A  /** @private */%0A  removeFromContent: function(record) %7B%0A    get(this, 'content').removeObject(get(record, 'reference'));%0A  %7D,%0A%0A  /** @private */%0A  addToContent: function(record) %7B%0A    get(this, 'content').addObject(get(record, 'reference'));%0A  %7D
+%0A
 %0A%7D);

remove unused functions: removeFromContent, addToContent