package ch.ethz.globis.distindex.client.io;

import ch.ethz.globis.disindex.codec.api.RequestEncoder;
import ch.ethz.globis.disindex.codec.api.ResponseDecoder;
import ch.ethz.globis.distindex.operation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ClientRequestDispatcher<K, V> implements RequestDispatcher<K, V> {

    private Transport transport;
    protected RequestEncoder<K, V> encoder;
    protected ResponseDecoder<K, V> decoder;

    public ClientRequestDispatcher(Transport transport, RequestEncoder<K, V> encoder, ResponseDecoder<K, V> decoder) {
        this.transport = transport;
        this.encoder = encoder;
        this.decoder = decoder;
    }

    @Override
    public Response<K, V> send(String hostId, Request request) {
        byte[] requestBytes = encode(request);
        byte[] responseBytes = transport.sendAndReceive(hostId, requestBytes);
        return decoder.decode(responseBytes);
    }

    @Override
    public List<Response<K, V>> send(List<String> hostIds, Request request) {
        byte[] requestBytes = encode(request);
        List<byte[]> responseList = transport.sendAndReceive(hostIds, requestBytes);
        List<Response<K, V>> responses = new ArrayList<>();
        for (byte[] responseBytes : responseList) {
            responses.add(decoder.decode(responseBytes));
        }
        return responses;
    }

    private byte[] encode(Request request) {
        byte[] encodedRequest;
        switch (request.getOpCode()) {
            case OpCode.GET:
                GetRequest<K> gr = (GetRequest<K>) request;
                encodedRequest = encoder.encodeGet(gr);
                break;
            case OpCode.GET_RANGE:
                GetRangeRequest<K> grr = (GetRangeRequest<K>) request;
                encodedRequest = encoder.encodeGetRange(grr);
                break;
            case OpCode.GET_KNN:
                GetKNNRequest<K> gknn = (GetKNNRequest<K>) request;
                encodedRequest = encoder.encodeGetKNN(gknn);
                break;
            case OpCode.GET_BATCH:
                GetIteratorBatch gb = (GetIteratorBatch) request;
                encodedRequest = encoder.encodeGetBatch(gb);
                break;
            case OpCode.PUT:
                PutRequest<K, V> p = (PutRequest<K, V>) request;
                encodedRequest = encoder.encodePut(p);
                break;
            case OpCode.CREATE_INDEX:
                CreateRequest cr = (CreateRequest) request;
                encodedRequest = encoder.encodeCreate(cr);
                break;
            default:
                throw new RuntimeException("Unknown command type");
        }
        return encodedRequest;
    }

    @Override
    public void close() throws IOException {
        if (transport == null) {
            throw new IllegalStateException("Transport was not properly initialized.");
        }
        transport.close();
    }
}
@@ -283,695 +283,2152 @@
 t;%0A%0A
-public class ClientRequestDispatcher%3CK, V%3E implements RequestDispatcher%3CK, V%3E %7B%0A%0A    private Transport transport;%0A    protected RequestEncoder%3CK, V%3E encoder;%0A    protected ResponseDecoder%3CK, V%3E decoder;%0A%0A    public ClientRequestDispatcher(Transport transport, RequestEncoder%3CK, V%3E encoder, ResponseDecoder%3CK, V%3E decoder) %7B%0A        this.transport = transport;%0A        this.encoder = encoder;%0A        this.decoder = decoder;%0A    %7D%0A%0A    @Override%0A    public Response%3CK, V%3E send(String hostId, Request request) %7B%0A        byte%5B%5D requestBytes = encode(request);%0A        byte%5B%5D responseBytes = transport.sendAndReceive(hostId, requestBytes);%0A        return decoder.decode(responseBytes);%0A    %7D%0A
+/**%0A * Dispatches client side requests to the server and returns the results.%0A *%0A * Additional, it also performs request encoding and response decoding.%0A * @param %3CK%3E%0A * @param %3CV%3E%0A */%0Apublic class ClientRequestDispatcher%3CK, V%3E implements RequestDispatcher%3CK, V%3E %7B%0A%0A    /** The transport used to send encoded messages to the server. */%0A    private Transport transport;%0A%0A    /** Encodes requests into a form that can be sent over the transport to the server. */%0A    protected RequestEncoder%3CK, V%3E encoder;%0A%0A    /** Decodes the messages received from the server to Response objects. */%0A    protected ResponseDecoder%3CK, V%3E decoder;%0A%0A    public ClientRequestDispatcher(Transport transport, RequestEncoder%3CK, V%3E encoder, ResponseDecoder%3CK, V%3E decoder) %7B%0A        this.transport = transport;%0A        this.encoder = encoder;%0A        this.decoder = decoder;%0A    %7D%0A%0A    /**%0A     * Send a request to the host identified by hostId and return the response.%0A     *%0A     * The request is first encoded to a byte array which is then sent to the client via the available transport.%0A     * The byte array received as a response is the decoded to a Response object and returned to the caller.%0A     *%0A     * @param hostId                                The destination host identifier.%0A     * @param request                               The request to be sent.%0A     * @return                                      The decoded response.%0A     */%0A    @Override%0A    public Response%3CK, V%3E send(String hostId, Request request) %7B%0A        byte%5B%5D requestBytes = encode(request);%0A        byte%5B%5D responseBytes = transport.sendAndReceive(hostId, requestBytes);%0A        return decoder.decode(responseBytes);%0A    %7D%0A%0A    /**%0A     * Send a request to a number of remote hosts. This method works as the previous one, with the exception%0A     * that multiple responses are received, decoded and then returned to the caller.%0A     *%0A     * @param hostIds                               The identifiers of the destination hosts.%0A     * @param request                               The request to be sent.%0A     * @return                                      The decoded responses.%0A     */
 %0A   

Index distribution Added documentation to the client dispatcher.