package org.bdware.sc.engine.hook;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import org.bdware.mockjava.JsonVisitor;
import org.paillier.PaillierCipher;

import java.math.BigInteger;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

public class HomoVisitor extends JsonVisitor {
    public static RSAPublicKey publicKey;
    JsonElement root;
    public static RSAPrivateKey privateKey;

    public HomoVisitor(JsonElement ret) {
        root = ret;
    }

    @Override
    public JsonVisitor visitObject(JsonObject homoConfig) {
        if (root.isJsonObject()) {
            JsonObject jo = root.getAsJsonObject();
            for (String key : homoConfig.keySet()) {
                if (jo.has(key)) {
                    HomoVisitor visitor = new HomoVisitor(jo.get(key));
                    visitor.visit(homoConfig.get(key));
                    jo.add(key, visitor.get());
                }
            }
        }
        return this;
    }

    @Override
    public JsonVisitor visitJsonArray(JsonArray ele) {
        if (root.isJsonArray()) {
            JsonArray array = root.getAsJsonArray();
            for (int i = 0; i < array.size(); i++) {
                HomoVisitor visitor = new HomoVisitor((array.get(i)));
                visitor.visit(ele.get(0));
                array.set(i, visitor.get());
            }
        }
        return this;
    }

    public JsonElement get() {
        return root;
    }

    @Override
    public JsonVisitor visitPrimitive(JsonPrimitive primitive) {
        if (primitive.isString()) {
            String method = primitive.getAsString();
            try {
                String result = "";
                if (method.equals("@encrypt")) {
                    BigInteger i = handleRoot(root.getAsString());
                    result = PaillierCipher.encrypt(i, publicKey);
                } else if (method.equals("@decrypt")) {
                    BigInteger i = PaillierCipher.decrypt(root.getAsString(), privateKey);
                    result = String.valueOf(i);
                } else {
                    result = root.getAsString();
                }
                System.out.println(result);
                root = new JsonPrimitive(result);

            } catch (Exception e) {
                System.out.println(e);
            }
        }
        
        return this;
    }

    private BigInteger handleRoot(String data) {
        double d = Double.parseDouble(data);
        long l = (long) d;
        return BigInteger.valueOf(l);
    }
}
