package meerkat.comm;

import com.google.protobuf.Message;
import com.google.protobuf.TextFormat;
import meerkat.protobuf.Comm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.TreeMap;
import java.util.concurrent.*;

/**
 * Created by Tzlil on 2/14/2016.
 */
// TODO: Change nane to network

public class ChannelImpl  {
    final Logger logger = LoggerFactory.getLogger(getClass());

    //private ExecutorService executorService = Executors.newCachedThreadPool();
    public static int BROADCAST = 0;
    Map<Integer,SingleChannel> channels = new TreeMap<>();


    public ChannelImpl() {
    }

    public Channel getChannel(int id) {
        return new SingleChannel(id);
    }

    public class SingleChannel implements Channel {
        protected final int id;

        ReceiverCallback callback;

        SingleChannel(int id) {
            this.id = id;
            channels.put(id, this);
        }

        @Override
        public int getSourceId() {
            return id;
        }


        @Override
        public void sendMessage(int destUser, Message msg) {
            if (destUser < 1)
                return;
            SingleChannel channel = channels.get(destUser);
            if (channel == null) {
                logger.warn("Party {} attempting to send message to non-existing party {}", getSourceId(), destUser);
                return;
            }
            Comm.BroadcastMessage broadcastMessage = Comm.BroadcastMessage.newBuilder()
                    .setSender(id)
                    .setDestination(destUser)
                    .setIsPrivate(true)
                    .setPayload(msg.toByteString())
                    .build();

            logger.debug("sending Message: Dst={},Src={} [{}]", broadcastMessage.getDestination(),
                    broadcastMessage.getSender(), TextFormat.printToString(msg));

            channel.callback.receiveMessage(broadcastMessage);
        }

        @Override
        public void broadcastMessage(Message msg) {
            Comm.BroadcastMessage broadcastMessage = Comm.BroadcastMessage.newBuilder()
                    .setSender(id)
                    .setDestination(BROADCAST)
                    .setIsPrivate(false)
                    .setPayload(msg.toByteString())
                    .build();

            logger.debug("broadcasting Message: Src={} [{}]",
                    broadcastMessage.getSender(), TextFormat.printToString(msg));

            for (SingleChannel channel : channels.values()) {
                channel.callback.receiveMessage(broadcastMessage);
            }
        }

        @Override
        public void registerReceiverCallback(final ReceiverCallback callback) {
            this.callback = callback;
        }
    }

}
