/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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
 *
 * http://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 org.apache.geode.pdx.internal.json;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonGenerator.Feature;

import org.apache.geode.annotations.internal.MutableForTesting;
import org.apache.geode.internal.HeapDataOutputStream;
import org.apache.geode.pdx.JSONFormatter;
import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.pdx.internal.EnumInfo;
import org.apache.geode.pdx.internal.EnumInfo.PdxInstanceEnumInfo;

/*
 * This class converts a PdxInstance into a JSON document.
 */
public class PdxToJSON {

  @MutableForTesting
  public static boolean PDXTOJJSON_UNQUOTEFIELDNAMES =
      Boolean.getBoolean("pdxToJson.unQuoteFieldNames");
  private PdxInstance m_pdxInstance;

  public PdxToJSON(PdxInstance pdx) {
    m_pdxInstance = pdx;
  }

  public String getJSON() {
    JsonFactory jf = new JsonFactory();
    HeapDataOutputStream hdos = new HeapDataOutputStream(org.apache.geode.internal.Version.CURRENT);
    try {
      JsonGenerator jg = jf.createJsonGenerator(hdos, JsonEncoding.UTF8);
      enableDisableJSONGeneratorFeature(jg);
      getJSONString(jg, m_pdxInstance);
      jg.close();
      return new String(hdos.toByteArray());
    } catch (IOException e) {
      throw new RuntimeException(e.getMessage());
    } finally {
      hdos.close();
    }
  }

  public byte[] getJSONByteArray() {
    JsonFactory jf = new JsonFactory();
    HeapDataOutputStream hdos = new HeapDataOutputStream(org.apache.geode.internal.Version.CURRENT);
    try {
      JsonGenerator jg = jf.createJsonGenerator(hdos, JsonEncoding.UTF8);
      enableDisableJSONGeneratorFeature(jg);
      getJSONString(jg, m_pdxInstance);
      jg.close();
      return hdos.toByteArray();
    } catch (IOException e) {
      throw new RuntimeException(e.getMessage());
    } finally {
      hdos.close();
    }
  }

  private void enableDisableJSONGeneratorFeature(JsonGenerator jg) {
    jg.enable(Feature.ESCAPE_NON_ASCII);
    jg.disable(Feature.AUTO_CLOSE_TARGET);
    if (PDXTOJJSON_UNQUOTEFIELDNAMES)
      jg.disable(Feature.QUOTE_FIELD_NAMES);
  }

  protected String convertPdxToJson(final PdxInstance pdxObj) {
    return (pdxObj != null ? JSONFormatter.toJSON(pdxObj) : null);
  }

  private void writeValue(JsonGenerator jg, Object value, String pf)
      throws JsonGenerationException, IOException {

    if (value == null) {
      jg.writeNull();
    } else if (value.getClass().equals(Boolean.class)) {
      boolean b = (Boolean) value;
      jg.writeBoolean(b);
    } else if (value.getClass().equals(Byte.class)) {
      Byte b = (Byte) value;
      jg.writeNumber(b);
    } else if (value.getClass().equals(Short.class)) {
      Short b = (Short) value;
      jg.writeNumber(b);
    } else if (value.getClass().equals(Integer.class)) {
      int i = (Integer) value;
      jg.writeNumber(i);
    } else if (value.getClass().equals(Long.class)) {
      long i = (Long) value;
      jg.writeNumber(i);
    } else if (value.getClass().equals(BigInteger.class)) {
      BigInteger i = (BigInteger) value;
      jg.writeNumber(i);
    } else if (value.getClass().equals(Float.class)) {
      float i = (Float) value;
      jg.writeNumber(i);
    } else if (value.getClass().equals(BigDecimal.class)) {
      BigDecimal i = (BigDecimal) value;
      jg.writeNumber(i);
    } else if (value.getClass().equals(Double.class)) {
      double d = (Double) value;
      jg.writeNumber(d);
    } else if (value.getClass().equals(String.class)) {
      String s = (String) value;
      jg.writeString(s);
    } else if (value.getClass().isArray()) {
      getJSONStringFromArray(jg, value, pf);
    } else if (value.getClass().equals(EnumInfo.class)) {
      jg.writeString(value.toString());
    } else if (value.getClass().equals(PdxInstanceEnumInfo.class)) {
      jg.writeString(value.toString());
    } else {
      if (value instanceof PdxInstance) {
        getJSONString(jg, (PdxInstance) value);
      } else if (value instanceof Collection) {
        getJSONStringFromCollection(jg, (Collection<?>) value, pf);
      } else if (value instanceof Map) {
        getJSONStringFromMap(jg, (Map) value, pf);
      } else {
        throw new IllegalStateException(
            "PdxInstance returns unknwon pdxfield " + pf + " for type " + value);
      }
    }
  }

  private void getJSONStringFromMap(JsonGenerator jg, Map map, String pf)
      throws JsonGenerationException, IOException {

    jg.writeStartObject();

    Iterator iter = map.entrySet().iterator();
    while (iter.hasNext()) {
      Map.Entry entry = (Map.Entry) iter.next();

      // Iterate over Map and write key-value
      jg.writeFieldName(entry.getKey().toString()); // write Key in a Map
      writeValue(jg, entry.getValue(), pf); // write value in a Map
    }
    jg.writeEndObject();
  }

  private String getJSONString(JsonGenerator jg, PdxInstance pdxInstance)
      throws JsonGenerationException, IOException {
    jg.writeStartObject();

    List<String> pdxFields = pdxInstance.getFieldNames();

    for (String pf : pdxFields) {
      Object value = pdxInstance.getField(pf);
      jg.writeFieldName(pf);
      writeValue(jg, value, pf);
    }
    jg.writeEndObject();
    return null;
  }

  private void getJSONStringFromArray(JsonGenerator jg, Object value, String pf)
      throws JsonGenerationException, IOException {

    if (value.getClass().getName().equals("[Z")) {
      JsonHelper.getJsonFromPrimitiveBoolArray(jg, (boolean[]) value, pf);
    } else if (value.getClass().getName().equals("[B")) {
      JsonHelper.getJsonFromPrimitiveByteArray(jg, (byte[]) value, pf);
    } else if (value.getClass().getName().equals("[S")) {
      JsonHelper.getJsonFromPrimitiveShortArray(jg, (short[]) value, pf);
    } else if (value.getClass().getName().equals("[I")) {
      JsonHelper.getJsonFromPrimitiveIntArray(jg, (int[]) value, pf);
    } else if (value.getClass().getName().equals("[J")) {
      JsonHelper.getJsonFromPrimitiveLongArray(jg, (long[]) value, pf);
    } else if (value.getClass().getName().equals("[F")) {
      JsonHelper.getJsonFromPrimitiveFloatArray(jg, (float[]) value, pf);
    } else if (value.getClass().getName().equals("[D")) {
      JsonHelper.getJsonFromPrimitiveDoubleArray(jg, (double[]) value, pf);
    } else if (value.getClass().equals(Boolean[].class)) {
      JsonHelper.getJsonFromWrapperBoolArray(jg, (Boolean[]) value, pf);
    } else if (value.getClass().equals(Byte[].class)) {
      JsonHelper.getJsonFromWrapperByteArray(jg, (Byte[]) value, pf);
    } else if (value.getClass().equals(Short[].class)) {
      JsonHelper.getJsonFromWrapperShortArray(jg, (Short[]) value, pf);
    } else if (value.getClass().equals(Integer[].class)) {
      JsonHelper.getJsonFromWrapperIntArray(jg, (Integer[]) value, pf);
    } else if (value.getClass().equals(Long[].class)) {
      JsonHelper.getJsonFromWrapperLongArray(jg, (Long[]) value, pf);
    } else if (value.getClass().equals(Float[].class)) {
      JsonHelper.getJsonFromWrapperFloatArray(jg, (Float[]) value, pf);
    } else if (value.getClass().equals(Double[].class)) {
      JsonHelper.getJsonFromWrapperDoubleArray(jg, (Double[]) value, pf);
    } else if (value.getClass().equals(BigInteger[].class)) {
      JsonHelper.getJsonFromBigIntArray(jg, (BigInteger[]) value, pf);
    } else if (value.getClass().equals(BigDecimal[].class)) {
      JsonHelper.getJsonFromBigDecimalArray(jg, (BigDecimal[]) value, pf);
    } else if (value.getClass().equals(String[].class)) {
      JsonHelper.getJsonFromStringArray(jg, (String[]) value, pf);
    } else if (value.getClass().equals(Object[].class)) {
      jg.writeStartArray();
      Object[] array = (Object[]) value;
      for (Object obj : array) {
        writeValue(jg, obj, pf);
      }
      jg.writeEndArray();
    } else {
      throw new IllegalStateException(
          "PdxInstance returns unknown pdxfield " + pf + " for type " + value);
    }
  }

  private void getJSONStringFromCollection(JsonGenerator jg, Collection<?> coll, String pf)
      throws JsonGenerationException, IOException {
    jg.writeStartArray();

    for (Object obj : coll) {
      writeValue(jg, obj, pf);
    }
    jg.writeEndArray();
  }
}
