package cs451.net.handler;

import cs451.net.NetManager;
import cs451.net.event.Message;
import cs451.net.event.NetEvent;
import cs451.parser.Host;
import cs451.parser.Parser;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * NetEventHandler for Failure Detection
 *
 * Beat: Sends ping to hosts
 * Deliver: Marks peer as alive (Drop HRBT packets)
 *
 * @author C. Hölzl
 */
public class NetHandlerFD extends NetEventHandlerAbstract {

    private List<Host> hosts;
    private static final ConcurrentHashMap<Integer,Integer> alive = new ConcurrentHashMap<>();

    public NetHandlerFD(Class<? extends NetEventHandlerAbstract> deliverLayer, Class<? extends NetEventHandlerAbstract> broadcastLayer) {
        super(deliverLayer, broadcastLayer);
    }

    @Override
    public void beat() {
        hosts.forEach(h-> alive.computeIfPresent(h.getId(),(k, v) -> {
            if(v == -1) return 0;
            if(v > NetManager.FD_MAX_TRIES)
                crashNextAsync(NetEvent.Message(h, Message.EMPTY()));
            else
                sendNextSync(NetEvent.MessageHRTB(h));
            return v+1;
        }));
    }

    @Override
    public void deliver(NetEvent ne) {
        alive.computeIfPresent(ne.peer.getId(),(k,v)->-1);
        switch(ne.message.tpe){
            case HRTB:
                break;
            default: deliverNextSync(ne);
        }
    }

    @Override
    public void start(Host h, Parser p) {
        super.start(h, p);
        hosts = p.hosts();
        hosts.stream().filter(ch->ch.getId()!=h.getId()).forEach(ch-> alive.put(ch.getId(),0));
    }
}
