package anastore.server;

import anastore.net.Message;
import anastore.net.ReceiveChannel;
import anastore.net.SendChannel;
import anastore.proto.*;
import anastore.store.Storable;
import anastore.util.NotImplementedError;
import anastore.util.Pair;
import anastore.util.ProtocolViolationException;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * Receive thread for a server. This thread is started by the server
 * when a new client connects. It receives messages on the root
 * channel, and dispatches them to the associated Client for
 * processing.
 */
class ClientHandlerThread<D extends Storable> extends Thread {

    private final Client client;
    private final SendChannel send;
    private final ReceiveChannel recv;

    public ClientHandlerThread(Client client,
                               SendChannel send,
                               ReceiveChannel recv) {
        super("Client handler " +
              client.getHostname() + ":" + client.getPort());
        this.client = client;
        this.send = send;
        this.recv = recv;
    }
        
    public void run() {
        boolean done = false;

        while (!done) {
            Pair<Message, SendChannel> received;
            Message msg;
            SendChannel replyChannel;
            try {
                received = recv.receive();
                msg = received.first;
                replyChannel = received.second;
            } catch (InterruptedException e) {
                // Ignore and retry
                continue;
            } catch (IOException e) {
                throw new
                    ProtocolViolationException("Network error", e);
            }

            try {
                // Dispatch the messsage.
                // A lost opportunity for dynamic polymorphism!
                if (msg instanceof HandshakeReq) {
                    client.handleHandshakeReq((HandshakeReq) msg,
                                              replyChannel);
                } else if (msg instanceof GetBlockReq) {
                    client.handleGetBlockReq((GetBlockReq) msg,
                                             replyChannel);
                } else if (msg instanceof GetLatestReq) {
                    client.handleGetLatestReq((GetLatestReq) msg,
                                              replyChannel);
                } else if (msg instanceof CommitReq) {
                    client.handleCommitReq((CommitReq) msg,
                                           replyChannel);
                } else if (msg instanceof HiReq) {
                    client.handleHiReq((HiReq) msg,
                                       replyChannel);
                } else {
                    throw new
                        ProtocolViolationException(msg,
                                                   "Unexpected type");
                }
            } catch (IOException e) {
                throw new ProtocolViolationException("Network error",
                                                     e);
            }
        }

    }
    
}
