/*
 * 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.persistence.local.room.converter;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.room.TypeConverter;
import com.google.android.gnd.model.observation.ResponseDelta;
import com.google.common.collect.ImmutableList;
import java.util.Iterator;
import org.json.JSONException;
import org.json.JSONObject;
import timber.log.Timber;

/**
 * {@link TypeConverter} for converting between {@link ResponseDelta}s and JSON strings used to
 * represent them in the local db.
 */
public class ResponseDeltasTypeConverter {

  @TypeConverter
  @Nullable
  public static String toString(@NonNull ImmutableList<ResponseDelta> responseDeltas) {
    JSONObject json = new JSONObject();
    for (ResponseDelta delta : responseDeltas) {
      try {
        json.put(
            delta.getFieldId(),
            delta
                .getNewResponse()
                .map(ResponseJsonConverter::toJsonObject)
                .orElse(JSONObject.NULL));
      } catch (JSONException e) {
        Timber.e(e, "Error building JSON");
      }
    }
    return json.toString();
  }

  @TypeConverter
  @NonNull
  public static ImmutableList<ResponseDelta> fromString(@Nullable String jsonString) {
    ImmutableList.Builder<ResponseDelta> deltas = ImmutableList.builder();
    if (jsonString == null) {
      return deltas.build();
    }
    try {
      JSONObject jsonObject = new JSONObject(jsonString);
      Iterator<String> keys = jsonObject.keys();
      while (keys.hasNext()) {
        String fieldId = keys.next();
        deltas.add(
            ResponseDelta.builder()
                .setFieldId(fieldId)
                .setNewResponse(ResponseJsonConverter.toResponse(jsonObject.get(fieldId)))
                .build());
      }
    } catch (JSONException e) {
      Timber.e(e, "Error parsing JSON string");
    }
    return deltas.build();
  }
}

@@ -655,16 +655,73 @@
 erter;%0A%0A
+import static com.google.android.gnd.util.Enums.toEnum;%0A%0A
 import a
@@ -748,16 +748,16 @@
 onNull;%0A
-
 import a
@@ -821,16 +821,64 @@
 verter;%0A
+import com.google.android.gnd.model.form.Field;%0A
 import c
@@ -1276,16 +1276,209 @@
 rter %7B%0A%0A
+  private static final String KEY_FIELD_TYPE = %22field type%22;%0A  private static final String KEY_RESPONSE = %22original response%22;%0A  private static final String KEY_NEW_RESPONSE = %22new response%22;%0A%0A
   @TypeC
@@ -1490,23 +1490,22 @@
 ter%0A  @N
+onN
 ull
-able
 %0A  publi
@@ -1698,50 +1698,402 @@
     
-json.put(%0A            delta.getFieldId(),%0A
+JSONObject newJson = new JSONObject();%0A        newJson%0A            .put(KEY_FIELD_TYPE, delta.getFieldType().name())%0A            .put(%0A                KEY_RESPONSE,%0A                delta%0A                    .getOriginalResponse()%0A                    .map(ResponseJsonConverter::toJsonObject)%0A                    .orElse(JSONObject.NULL))%0A            .put(%0A                KEY_NEW_RESPONSE,%0A    
     
@@ -2098,32 +2098,36 @@
           delta%0A
+    
                 
@@ -2152,32 +2152,36 @@
                 
+   
+ 
 .map(ResponseJso
@@ -2214,32 +2214,36 @@
                 
+    
 .orElse(JSONObje
@@ -2249,24 +2249,71 @@
 ect.NULL));%0A
+        json.put(delta.getFieldId(), newJson);%0A
       %7D catc
@@ -2862,24 +2862,90 @@
 eys.next();%0A
+        JSONObject jsonDelta = jsonObject.getJSONObject(fieldId);%0A
         delt
@@ -3025,16 +3025,209 @@
 ieldId)%0A
+                .setFieldType(toEnum(Field.Type.class, jsonDelta.getString(KEY_FIELD_TYPE)))%0A                .setOriginalResponse(ResponseJsonConverter.toResponse(jsonDelta.get(KEY_RESPONSE)))%0A
         
@@ -3291,26 +3291,34 @@
 json
-Object.get(fieldId
+Delta.get(KEY_NEW_RESPONSE
 )))%0A

Configure ResponseDeltasTypeConverter to save the new info to db