package peergos.server.mutable;

import com.sun.net.httpserver.*;
import peergos.shared.cbor.*;
import peergos.shared.corenode.*;
import peergos.shared.crypto.asymmetric.*;
import peergos.shared.merklebtree.*;
import peergos.shared.mutable.*;
import peergos.shared.util.*;

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

public class HttpMutablePointerServer
{
    public static final int PORT = 9998;

    private static final boolean LOGGING = true;
    private static final int CONNECTION_BACKLOG = 100;
    private static final int HANDLER_THREAD_COUNT = 100;

    public static final String MUTABLE_POINTERS_URL = "mutable/";

    public static class MutationHandler implements HttpHandler
    {
        private final MutablePointers mutable;

        public MutationHandler(MutablePointers mutable) {
            this.mutable = mutable;
        }

        public void handle(HttpExchange exchange) throws IOException
        {
            long t1 = System.currentTimeMillis();
            DataInputStream din = new DataInputStream(exchange.getRequestBody());

            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            DataOutputStream dout = new DataOutputStream(bout);

            String path = exchange.getRequestURI().getPath();
            if (path.startsWith("/"))
                path = path.substring(1);
            String[] subComponents = path.substring(MUTABLE_POINTERS_URL.length()).split("/");
            String method = subComponents[0];
//            System.out.println("core method "+ method +" from path "+ path);

            try {
                switch (method)
                {
                    case "setPointer":
                        setPointer(din, dout);
                        break;
                    case "getPointer":
                        getPointer(din, dout);
                        break;
                    default:
                        throw new IOException("Unknown method "+ method);
                }

                dout.flush();
                dout.close();
                byte[] b = bout.toByteArray();
                exchange.sendResponseHeaders(200, b.length);
                exchange.getResponseBody().write(b);
            } catch (Exception e) {
                e.printStackTrace();
                exchange.sendResponseHeaders(400, 0);
            } finally {
                exchange.close();
                long t2 = System.currentTimeMillis();
                if (LOGGING)
                    System.out.println("Mutable pointers server handled " + method + " request in: " + (t2 - t1) + " mS");
            }

        }

        void setPointer(DataInputStream din, DataOutputStream dout) throws Exception
        {
            byte[] ownerPublicKey = CoreNodeUtils.deserializeByteArray(din);
            byte[] encodedSharingPublicKey = CoreNodeUtils.deserializeByteArray(din);
            byte[] signedPayload = CoreNodeUtils.deserializeByteArray(din);
            boolean isAdded = mutable.setPointer(
                    PublicSigningKey.fromByteArray(ownerPublicKey),
                    PublicSigningKey.fromByteArray(encodedSharingPublicKey),
                    signedPayload).get();
            dout.writeBoolean(isAdded);
        }

        void getPointer(DataInputStream din, DataOutputStream dout) throws Exception
        {
            PublicSigningKey encodedSharingKey = PublicSigningKey.fromCbor(CborObject.deserialize(new CborDecoder(din)));
            MaybeMultihash metadataBlob = mutable.getPointer(encodedSharingKey).get();

            dout.write(metadataBlob.serialize());
        }
    }

    private final HttpServer server;
    private final InetSocketAddress address;
    private final MutationHandler ch;

    public HttpMutablePointerServer(MutablePointers mutable, InetSocketAddress address) throws IOException
    {

        this.address = address;
        if (address.getHostName().contains("local"))
            server = HttpServer.create(address, CONNECTION_BACKLOG);
        else
            server = HttpServer.create(new InetSocketAddress(InetAddress.getLocalHost(), address.getPort()), CONNECTION_BACKLOG);
        ch = new MutationHandler(mutable);
        server.createContext("/" + MUTABLE_POINTERS_URL, ch);
        server.setExecutor(Executors.newFixedThreadPool(HANDLER_THREAD_COUNT));
    }

    public void start() throws IOException
    {
        server.start();
    }

    public void close() throws IOException
    {   
        server.stop(5);
    }
}

@@ -2351,16 +2351,135 @@
 00, 0);%0A
+                OutputStream body = exchange.getResponseBody();%0A                body.write(e.getMessage().getBytes());%0A
         

return error messages in http