/**
   * Build a list of {@link ContentProviderOperation} that will transform all the "before" {@link
   * Entity} states into the modified state which all {@link EntityDelta} objects represent. This
   * method specifically creates any {@link AggregationExceptions} rules needed to groups edits
   * together.
   */
  public ArrayList<ContentProviderOperation> buildDiff() {
    final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();

    final long rawContactId = this.findRawContactId();
    int firstInsertRow = -1;

    // First pass enforces versions remain consistent
    for (EntityDelta delta : this) {
      delta.buildAssert(diff);
    }

    final int assertMark = diff.size();
    int backRefs[] = new int[size()];

    int rawContactIndex = 0;

    // Second pass builds actual operations
    for (EntityDelta delta : this) {
      final int firstBatch = diff.size();
      backRefs[rawContactIndex++] = firstBatch;
      delta.buildDiff(diff);

      // Only create rules for inserts
      if (!delta.isContactInsert()) continue;

      // If we are going to split all contacts, there is no point in first combining them
      if (mSplitRawContacts) continue;

      if (rawContactId != -1) {
        // Has existing contact, so bind to it strongly
        final Builder builder = beginKeepTogether();
        builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId);
        builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
        diff.add(builder.build());

      } else if (firstInsertRow == -1) {
        // First insert case, so record row
        firstInsertRow = firstBatch;

      } else {
        // Additional insert case, so point at first insert
        final Builder builder = beginKeepTogether();
        builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, firstInsertRow);
        builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
        diff.add(builder.build());
      }
    }

    if (mSplitRawContacts) {
      buildSplitContactDiff(diff, backRefs);
    }

    // No real changes if only left with asserts
    if (diff.size() == assertMark) {
      diff.clear();
    }

    return diff;
  }