/**
   * Build a list of {@link ContentProviderOperation} that will transform the current "before"
   * {@link Entity} state into the modified state which this {@link RawContactDelta} represents.
   */
  public void buildDiff(ArrayList<ContentProviderOperation> buildInto) {
    final int firstIndex = buildInto.size();

    final boolean isContactInsert = mValues.isInsert();
    final boolean isContactDelete = mValues.isDelete();
    final boolean isContactUpdate = !isContactInsert && !isContactDelete;

    final Long beforeId = mValues.getId();

    Builder builder;

    if (isContactInsert) {
      // TODO: for now simply disabling aggregation when a new contact is
      // created on the phone.  In the future, will show aggregation suggestions
      // after saving the contact.
      mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
    }

    // Build possible operation at Contact level
    builder = mValues.buildDiff(mContactsQueryUri);
    possibleAdd(buildInto, builder);

    // Build operations for all children
    for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
      for (ValuesDelta child : mimeEntries) {
        // Ignore children if parent was deleted
        if (isContactDelete) continue;

        // Use the profile data URI if the contact is the profile.
        if (mContactsQueryUri.equals(Profile.CONTENT_RAW_CONTACTS_URI)) {
          builder =
              child.buildDiff(
                  Uri.withAppendedPath(Profile.CONTENT_URI, RawContacts.Data.CONTENT_DIRECTORY));
        } else {
          builder = child.buildDiff(Data.CONTENT_URI);
        }

        if (child.isInsert()) {
          if (isContactInsert) {
            // Parent is brand new insert, so back-reference _id
            builder.withValueBackReference(Data.RAW_CONTACT_ID, firstIndex);
          } else {
            // Inserting under existing, so fill with known _id
            builder.withValue(Data.RAW_CONTACT_ID, beforeId);
          }
        } else if (isContactInsert && builder != null) {
          // Child must be insert when Contact insert
          throw new IllegalArgumentException("When parent insert, child must be also");
        }
        possibleAdd(buildInto, builder);
      }
    }

    final boolean addedOperations = buildInto.size() > firstIndex;
    if (addedOperations && isContactUpdate) {
      // Suspend aggregation while persisting updates
      builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_SUSPENDED);
      buildInto.add(firstIndex, builder.build());

      // Restore aggregation mode as last operation
      builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_DEFAULT);
      buildInto.add(builder.build());
    } else if (isContactInsert) {
      // Restore aggregation mode as last operation
      builder = ContentProviderOperation.newUpdate(mContactsQueryUri);
      builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT);
      builder.withSelection(RawContacts._ID + "=?", new String[1]);
      builder.withSelectionBackReference(0, firstIndex);
      buildInto.add(builder.build());
    }
  }