/*
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.gnd.repository.local;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.room.ColumnInfo;
import androidx.room.TypeConverter;
import com.google.auto.value.AutoValue;
import com.google.auto.value.AutoValue.CopyAnnotations;
import org.json.JSONObject;

/** Fields describing operation type, old, and new values, common to Feature and Record edits. */
@AutoValue
public abstract class Edit {
  public enum Type implements IntEnum {
    UNKNOWN(0),
    CREATE(1),
    UPDATE(2),
    DELETE(3);

    private final int intValue;

    Type(int intValue) {
      this.intValue = intValue;
    }

    public int intValue() {
      return intValue;
    }

    @TypeConverter
    public static int toInt(@Nullable Edit.Type value) {
      return IntEnum.toInt(value, UNKNOWN);
    }

    @NonNull
    @TypeConverter
    public static Edit.Type fromInt(int intValue) {
      return IntEnum.fromInt(values(), intValue, UNKNOWN);
    }
  }

  @CopyAnnotations
  @ColumnInfo(name = "type")
  @NonNull
  public abstract Type getType();

  /**
   * For edits of type UPDATE, returns a JSON object with the original value of modified attributes
   * before this edit. For all other edit types this will return null.
   */
  @CopyAnnotations
  @ColumnInfo(name = "old_values")
  @Nullable
  public abstract JSONObject getOldValues();

  /**
   * For edits of type UPDATE, returns a JSON object with the new value of modified attributes after
   * this edit. For all other edit types this will return null.
   */
  @CopyAnnotations
  @ColumnInfo(name = "new_values")
  @Nullable
  public abstract JSONObject getNewValues();

  @NonNull
  public static Edit create(
      @NonNull Type type, @Nullable JSONObject oldValues, @Nullable JSONObject newValues) {
    return builder().setType(type).setOldValues(oldValues).setNewValues(newValues).build();
  }

  public static Builder builder() {
    return new AutoValue_Edit.Builder();
  }

  @AutoValue.Builder
  public abstract static class Builder {

    public abstract Builder setType(Type type);

    public abstract Builder setOldValues(JSONObject oldValues);

    public abstract Builder setNewValues(JSONObject newValues);

    public abstract Edit build();
  }
}

@@ -909,16 +909,19 @@
 ct;%0A%0A/**
+%0A *
  Fields 
@@ -949,14 +949,16 @@
 type
-,
+ and
  old
-,
  and
@@ -966,51 +966,216 @@
 new 
-values, common to Feature and Record edits.
+attribute values. Edits are maintained in%0A * addition to latest local snapshot of entities to allow two-way data sync (merging local changes%0A * with remote edits and vice versa) and rollback on sync failure.%0A
  */%0A
@@ -1867,38 +1867,56 @@
 r edits of type 
+%7B@link Edit.Type.
 UPDATE
+%7D
 , returns a JSON
@@ -1942,27 +1942,33 @@
 iginal value
+s
  of
+%0A   *
  modified at
@@ -1975,21 +1975,16 @@
 tributes
-%0A   *
  before 
@@ -2033,32 +2033,112 @@
 ill return null.
+ The old%0A   * values are maintained to allow rollback in case remote sync fails.
 %0A   */%0A  @CopyAn
@@ -2269,22 +2269,69 @@
 of type 
+%7B@link Edit.Type.CREATE%7D and %7B@link Edit.Type.
 UPDATE
+%7D
 , return
@@ -2337,32 +2337,37 @@
 ns a JSON object
+%0A   *
  with the new va
@@ -2398,21 +2398,16 @@
 es after
-%0A   *
  this ed
@@ -2436,32 +2436,37 @@
  types this will
+%0A   *
  return null.%0A  
@@ -2463,16 +2463,560 @@
 n null.%0A
+   *%0A   * %3Cp%3ETaken together, the old and new values represent changes as follows:%0A   *%0A   * %3Cul%3E%0A   *   %3Cli%3EIf a key is present in new values, but not the old, the entry represents an unset%0A   *       attribute that is now being set.%0A   *   %3Cli%3EIf a key is present in both old and new values, the entry represents an attribute that%0A   *       was already set but has now been modified.%0A   *   %3Cli%3EIf a key is present in old values but not the new, the entry represents an attribute that%0A   *       was present, but has been removed.%0A   * %3C/ul%3E%0A
    */%0A  

Update Edit Javadoc to be more descriptive and correct