package de.factoryfx.remoteserver;

import de.factoryfx.data.merge.MergeDiff;
import de.factoryfx.factory.FactoryBase;
import de.factoryfx.factory.datastorage.FactoryAndStorageMetadata;
import de.factoryfx.factory.datastorage.StoredFactoryMetadata;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.core.MediaType;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;

public class AdminUiJavafxServerClient<V,T extends FactoryBase<?,V>> {

    private final Client client;
    private final URI baseURI;
    private final Class<? extends T> configurationRootClass;

    public AdminUiJavafxServerClient(Client client, String host, int port, boolean ssl, Class<? extends T> configurationRootClass) {
        this(client,buildURI(host, port, ssl),configurationRootClass);
    }

    public AdminUiJavafxServerClient(Client client, URI baseURI, Class<? extends T> configurationRootClass) {
        this.client = client;
        this.baseURI = baseURI;
        this.configurationRootClass = configurationRootClass;
    }

    public MergeDiff updateCurrentFactory(FactoryAndStorageMetadata<T> update) {
        return post("updateCurrentFactory", update, MergeDiff.class);
    }

    public FactoryAndStorageMetadata<T> getCurrentFactory() {
        return get("currentFactory", FactoryAndStorageMetadata.class);
    }


    public T getHistoryFactory(String id) {
        return get("historyFactory", configurationRootClass);
    }

    static final Class<? extends ArrayList<StoredFactoryMetadata>> collectionOfStoredFactoryMetadataClass = new ArrayList<StoredFactoryMetadata>() {}.getClass();
    public Collection<StoredFactoryMetadata> getHistoryFactoryList() {
        return get("historyFactoryList", collectionOfStoredFactoryMetadataClass);
    }

    public void start() {
        get("start");
    }

    public void stop() {
        get("stop");
    }


    public V query(V visitor) {
        return post("query",visitor,(Class<? extends V>)visitor.getClass());
    }

    private <R> R post(String subPath, Object entity, Class<R> returnType) {
        return createRequest(subPath).post(Entity.json(entity)).readEntity(returnType);
    }

    private <R> R get(String subPath, Class<R> returnType) {
        return createRequest(subPath).get().readEntity(returnType);
    }

    private Invocation.Builder createRequest(String subPath) {
        return client.target(baseURI.resolve(subPath)).request().accept(MediaType.APPLICATION_JSON_TYPE);
    }

    private Object get(String subPath) {
        return createRequest(subPath).get().getEntity();
    }


    private static URI buildURI(String host, int port, boolean ssl)  {
        try {
            return new URI((ssl?"http":"https")+"://"+host+":"+port+"/applicationServer/");
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException("bad host name",e);
        }
    }


}

@@ -391,24 +391,59 @@
 MediaType;%0D%0A
+import javax.ws.rs.core.Response;%0D%0A
 import java.
@@ -2284,38 +2284,51 @@
 ype) %7B%0D%0A        
-return
+Response response =
  createRequest(s
@@ -2360,16 +2360,82 @@
 entity))
+;%0D%0A        checkResponseStatus(response);%0D%0A        return response
 .readEnt
@@ -2523,38 +2523,51 @@
 ype) %7B%0D%0A        
-return
+Response response =
  createRequest(s
@@ -2579,38 +2579,345 @@
 h).get()
-.readEntity(returnType
+;%0D%0A        checkResponseStatus(response);%0D%0A        return response.readEntity(returnType);%0D%0A    %7D%0D%0A%0D%0A    private void checkResponseStatus(Response response) %7B%0D%0A        if (response.getStatus() != 200)%0D%0A            throw new RuntimeException(%22Received http status code %22+response.getStatus()+%22%5Cn%22+response.readEntity(String.class)
 );%0D%0A    

handle status code != 200