package com.northpine;

import com.google.gson.*;
import com.google.gson.stream.JsonWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

public class ArcJsonWriter {

  private static final Logger log = LoggerFactory.getLogger(ArcJsonWriter.class);
  private static final String FEATURES = "features";
  private boolean firstWrite;

  private final JsonWriter writer;


  public ArcJsonWriter(Writer output) {
    writer = new JsonWriter(output);
    firstWrite = true;
  }

  /**
   * This method is used as the public interface to the json writer.
   * If this is the first call to write, we want to be able to write all the associated
   * metadata that is included with a call to an ArcGIS Server. However, we want to keep an
   * open array for future 'features' to be put into the array.
   * @param obj object containing geometric information
   * @throws IOException if failed to write to file
   */
  public void write(JsonObject obj) throws IOException {
    long before = System.currentTimeMillis();
    if(firstWrite) {
      firstWrite = false;
      var features = obj.getAsJsonArray(FEATURES);
      obj.remove(FEATURES);
      writeJsonObject(obj, false);
      if(features != null) {
        writer.name(FEATURES);
        writer.beginArray();
        log.info("Beginning features array");
        for(var i = 0; i < features.size(); i++) {
          log.info("" + i);
          var el = features.get(i);
          checkTypeAndWrite(el);
        }
      } else {
        log.warn("Features is null");
      }
    } else {
      var featuresArr = obj.getAsJsonArray(FEATURES);
      for(var i = 0; i < featuresArr.size(); i++) {
        checkTypeAndWrite(featuresArr.get(i));
      }
    }
    log.info(String.format("Appended json in '%d'ms", System.currentTimeMillis() - before));
  }

  public void close() throws IOException {
    writer.endArray();
    writer.endObject();
    writer.close();
  }

  private void writePrimitive(JsonPrimitive el) throws IOException {
    if(el.isBoolean()) {
      writer.value(el.getAsBoolean());
    } else if(el.isNumber()) {
      writer.value(el.getAsNumber());
    } else if(el.isString()) {
      writer.value(el.getAsString());
    }
  }

  private void writeJsonObject(JsonObject el) throws IOException {
    writeJsonObject(el, true);
  }
  private void writeJsonObject(JsonObject el, boolean shouldClose) throws IOException {
    writer.beginObject();
    for(var entry: el.entrySet()) {
      writer.name(entry.getKey());
      var val = entry.getValue();
      checkTypeAndWrite(val);
    }
    if(shouldClose) writer.endObject();
  }

  private void checkTypeAndWrite(JsonElement val) throws IOException {
    if(val.isJsonPrimitive()) {
      writePrimitive(val.getAsJsonPrimitive());
    } else if(val.isJsonArray()) {
      writeJsonArray(val.getAsJsonArray());
    } else if(val.isJsonObject()) {
      writeJsonObject(val.getAsJsonObject());
    }
  }

  private void writeJsonArray(JsonArray arr) throws IOException {
    writer.beginArray();
    for(var i = 0; i < arr.size(); i++) {
      var el = arr.get(i);
      checkTypeAndWrite(el);
    }
    if(true) writer.endArray();

  }








}

@@ -2034,24 +2034,83 @@
 oolean()) %7B%0A
+//      log.info(%22Writing boolean: %22 + el.getAsBoolean());%0A
       writer
@@ -2163,24 +2163,81 @@
 Number()) %7B%0A
+//      log.info(%22Writing number: %22 + el.getAsNumber());%0A
       writer
@@ -2289,24 +2289,81 @@
 String()) %7B%0A
+//      log.info(%22Writing string: %22 + el.getAsString());%0A
       writer
@@ -2893,22 +2893,148 @@
 Json
-Primitive()) %7B
+Null()) %7B%0A      writer.nullValue();%0A    %7D else if(val.isJsonPrimitive()) %7B%0A//      log.info(%22Found primitive: %22 + val.getAsJsonPrimitive());
 %0A   
@@ -3109,24 +3109,82 @@
 nArray()) %7B%0A
+//      log.info(%22Found array: %22 + val.getAsJsonArray());%0A
       writeJ
@@ -3247,24 +3247,84 @@
 Object()) %7B%0A
+//      log.info(%22Found object: %22 + val.getAsJsonObject());%0A
       writeJ
@@ -3497,24 +3497,24 @@
 e(); i++) %7B%0A
-
       var el
@@ -3524,24 +3524,73 @@
 arr.get(i);%0A
+//      log.info(%22Writing array element: %22 + i);%0A
       checkT

fix null json values