package lc.mecha.mq;

import lc.mecha.log.MechaLogger;
import lc.mecha.log.MechaLoggerFactory;

import java.io.Closeable;
import java.util.UUID;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

/**
 * Trivial implementation of a queue compatible with {@link Fanout}.
 *
 * @param <T> The type of object this queue trades in.
 * @author Alex Leigh
 */
public class Queue<T> implements Closeable {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(Queue.class);
    private final UUID id;
    private final LinkedBlockingDeque<T> queue = new LinkedBlockingDeque<>();
    private final Fanout<T> parent;

    public Queue(UUID id, Fanout<T> parent) {
        this.id = id;
        this.parent = parent;
    }

    /**
     * Write an object into the queue.
     */
    public void write(T obj) throws InterruptedException {
        if(obj==null) throw new IllegalArgumentException("Object cannot be null.");
        queue.put(obj);
    }

    /**
     * Attempt to read a message from the queue. If the queue is empty, <code>null</code> is returned.
     */
    public T read() throws InterruptedException {
        return queue.poll(5, TimeUnit.SECONDS);
    }

    public UUID getId() {
        return id;
    }

    @Override
    public void close() {
        parent.destroyQueue(this);
        // FIXME: We should find some way to stop calls into remove() which are blocked
    }

    @Override
    public String toString() {
        return "Queue{" +
                "id=" + id +
                ", queue=" + queue +
                ", parent=" + parent +
                '}';
    }
}
