package meerkat.bulletinboard.workers.multiserver;

import com.google.common.util.concurrent.FutureCallback;
import meerkat.bulletinboard.MultiServerWorker;
import meerkat.bulletinboard.SingleServerBulletinBoardClient;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardApi.*;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by Arbel Deutsch Peled on 27-Dec-15.
 */
public class MultiServerGetRedundancyWorker extends MultiServerWorker<MessageID, Float> {

    private AtomicInteger serversContainingMessage;
    private AtomicInteger totalContactedServers;

    public MultiServerGetRedundancyWorker(List<SingleServerBulletinBoardClient> clients,
                                         int minServers, MessageID payload, int maxRetry,
                                         FutureCallback<Float> futureCallback) {

        super(clients, minServers, payload, maxRetry, futureCallback); // Shuffle clients on creation to balance load

        serversContainingMessage = new AtomicInteger(0);
        totalContactedServers = new AtomicInteger(0);

    }

    /**
     * This method carries out the actual communication with the servers via HTTP Post
     * It accesses the servers in a random order until one answers it
     * Successful retrieval from any server terminates the method and returns the received values; The list is not changed
     */
    public void run(){

        // Iterate through clients
        for (SingleServerBulletinBoardClient client : clients) {

            // Send request to client
            client.getRedundancy(payload,this);

        }

    }

    @Override
    public void onSuccess(Float result) {

        if (result > 0.5) {
            serversContainingMessage.incrementAndGet();
        }

        if (totalContactedServers.incrementAndGet() >= getClientNumber()){
            succeed(((float) serversContainingMessage.get()) / ((float) getClientNumber()));
        }

    }

    @Override
    public void onFailure(Throwable t) {
        onSuccess(0.0f);
    }

}
