package org.develnext.jphp.zend.ext.json;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException;
import org.develnext.jphp.json.gson.MemoryDeserializer;
import org.develnext.jphp.json.gson.MemorySerializer;
import php.runtime.Memory;
import php.runtime.env.Environment;
import php.runtime.ext.support.compile.FunctionsContainer;
import php.runtime.memory.StringMemory;

import static php.runtime.annotation.Runtime.Immutable;

public class JsonFunctions extends FunctionsContainer {

    public static Memory json_decode(Environment env, String json, boolean assoc, int depth) {
        GsonBuilder gsonBuilder = JsonExtension.DEFAULT_GSON_BUILDER_FOR_DECODE;
        if (assoc || depth != 512) {
            MemoryDeserializer memoryDeserializer = new MemoryDeserializer();
            gsonBuilder = JsonExtension.createGsonBuilderForDecode(memoryDeserializer);
            memoryDeserializer.setAssoc(assoc);
            memoryDeserializer.setMaxDepth(depth);
        }

        Gson gson = gsonBuilder.create();
        try {
            env.setUserValue(JsonFunctions.class.getName() + "#error", null);
            Memory r = gson.fromJson(json, Memory.class);
            if (r == null)
                return Memory.NULL;
            else
                return r;
        } catch (MemoryDeserializer.MaxDepthException e) {
            env.setUserValue(JsonFunctions.class.getName() + "#error", JsonConstants.JSON_ERROR_DEPTH);
        } catch (JsonSyntaxException e) {
            env.setUserValue(JsonFunctions.class.getName() + "#error", JsonConstants.JSON_ERROR_SYNTAX);
        } catch (JsonParseException e) {
            env.setUserValue(JsonFunctions.class.getName() + "#error", JsonConstants.JSON_ERROR_STATE_MISMATCH);
        }

        return Memory.NULL;
    }

    public static Memory json_decode(Environment env, String json, boolean assoc) {
        return json_decode(env, json, assoc, 512);
    }

    public static int json_last_error(Environment env) {
        Integer error = env.getUserValue(JsonFunctions.class.getName() + "#error", Integer.class);
        if (error == null)
            return JsonConstants.JSON_ERROR_NONE;

        return error;
    }

    public static Memory json_last_error_msg(Environment env) {
        switch (json_last_error(env)) {
            case JsonConstants.JSON_ERROR_NONE: return Memory.NULL;
            case JsonConstants.JSON_ERROR_DEPTH: return new StringMemory("Maximum stack depth exceeded");
            case JsonConstants.JSON_ERROR_STATE_MISMATCH: return new StringMemory("Underflow or the modes mismatch");
            case JsonConstants.JSON_ERROR_SYNTAX: return new StringMemory("Syntax error, malformed JSON");
            case JsonConstants.JSON_ERROR_UTF8: return new StringMemory("Malformed UTF-8 characters, possibly incorrectly encoded");
            case JsonConstants.JSON_ERROR_CTRL_CHAR: return new StringMemory("Unexpected control character found");
            default:
                return Memory.NULL;
        }
    }

    public static Memory json_decode(Environment env, String json) {
        return json_decode(env, json, false);
    }

    @Immutable
    public static String json_encode(Memory memory, int options) {
        GsonBuilder builder;
        if (options != 0){
            MemorySerializer serializer = new MemorySerializer();
            builder = JsonExtension.createGsonBuilder(serializer);

            if ((options & JsonConstants.JSON_PRETTY_PRINT) == JsonConstants.JSON_PRETTY_PRINT){
                builder.setPrettyPrinting();
            }

            if ((options & JsonConstants.JSON_HEX_TAG) != JsonConstants.JSON_HEX_TAG){
                builder.disableHtmlEscaping();
            }

            if ((options & JsonConstants.JSON_FORCE_OBJECT) == JsonConstants.JSON_FORCE_OBJECT){
                serializer.setForceObject(true);
            }

            if ((options & JsonConstants.JSON_NUMERIC_CHECK) == JsonConstants.JSON_NUMERIC_CHECK){
                serializer.setNumericCheck(true);
            }
        } else {
            builder = JsonExtension.DEFAULT_GSON_BUILDER;
        }

        Gson gson = builder.create();
        return gson.toJson(memory);
    }

    @Immutable
    public static String json_encode(Memory memory) {
        return json_encode(memory, 0);
    }
}

@@ -674,130 +674,8 @@
 ) %7B%0A
-        GsonBuilder gsonBuilder = JsonExtension.DEFAULT_GSON_BUILDER_FOR_DECODE;%0A        if (assoc %7C%7C depth != 512) %7B%0A    
     
@@ -752,19 +752,67 @@
         
-   
+memoryDeserializer.setEnv(env);%0A        GsonBuilder
  gsonBui
@@ -880,20 +880,17 @@
 lizer);%0A
-    
+%0A
         
@@ -929,28 +929,24 @@
 c);%0A        
-   
- 
 memoryDeseri
@@ -971,26 +971,16 @@
 (depth);
-%0A        %7D
 %0A%0A      

Fix tests: error in zend-json-ext