package im.actor.runtime.actors.dispatch.queue;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import im.actor.runtime.threading.AtomicIntegerCompat;
public class QueueCollection<T> {
private AtomicIntegerCompat NEXT_ID = im.actor.runtime.Runtime.createAtomicInt(0);
private HashMap<Integer, Queue<T>> queues = new HashMap<>();
private LinkedList<Queue<T>> pending = new LinkedList<>();
private ArrayList<QueueCollectionListener> listeners = new ArrayList<>();
public synchronized void addListener(QueueCollectionListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public synchronized void removeListener(QueueCollectionListener listener) {
listeners.remove(listener);
}
public synchronized int spawnQueue() {
int id = NEXT_ID.getAndIncrement();
queues.put(id, new Queue<T>(id));
return id;
}
public synchronized void disposeQueue(int id) {
Queue<T> q = queues.remove(id);
if (q != null) {
pending.remove(q);
}
}
public synchronized void post(int id, T value) {
post(id, value, false);
}
public synchronized void post(int id, T value, boolean isFirst) {
Queue<T> queue = queues.get(id);
if (queue == null) {
return;
}
boolean wasEmptyPending = pending.isEmpty();
boolean wasEmpty = queue.getQueue().isEmpty();
if (isFirst) {
queue.getQueue().add(0, value);
} else {
queue.getQueue().add(value);
}
if (wasEmpty && !queue.isLocked()) {
pending.add(queue);
}
if (wasEmptyPending) {
for (QueueCollectionListener l : listeners) {
l.onChanged();
}
}
}
public synchronized QueueFetchResult<T> fetch() {
if (pending.isEmpty()) {
return null;
}
Queue<T> queue = pending.remove(0);
queue.setIsLocked(true);
T val = queue.getQueue().remove(0);
return new QueueFetchResult<>(queue.getId(), val);
}
public synchronized void returnQueue(QueueFetchResult<T> res) {
Queue<T> queue = queues.get(res.getId());
if (queue == null) {
return;
}
queue.setIsLocked(false);
if (!queue.getQueue().isEmpty()) {
boolean wasEmptyPending = pending.isEmpty();
pending.add(queue);
if (wasEmptyPending) {
for (QueueCollectionListener l : listeners) {
l.onChanged();
}
}
}
}
public synchronized List<T> getAllPending(int id) {
Queue<T> queue = queues.get(id);
if (queue == null) {
return new ArrayList<>();
}
return new ArrayList<>(queue.getQueue());
}
}