package com.marverenic.music.utils;
import android.support.annotation.NonNull;
import java.util.ArrayDeque;
import java.util.Queue;
import rx.Observable;
import rx.subjects.ReplaySubject;
/**
* A data structure that combines a queue with an observable stream. Objects can be enqueued to the
* queue, and will be sent in order to the observable returned by {@link #toObservable()}. Objects
* are removed from the queue immediately before they are delivered to the subscriber.
* @param <T>
*/
public class ObservableQueue<T> {
private final Object mLock = new Object();
private Queue<T> mQueue;
private ReplaySubject<T> mSubject;
public ObservableQueue() {
mQueue = new ArrayDeque<>();
}
/**
* If this queue is subscribed to, {@code value} will immediately be sent to the observer.
* Otherwise, this will be added to the end of the queue.
* @param value The value to be enqueued. Must not be null.
*/
public void enqueue(@NonNull T value) {
synchronized (mLock) {
mQueue.add(value);
if (mSubject != null) {
mSubject.onNext(value);
}
}
}
/**
* Creates an Observable stream from this queue. There should only ever be one subscriber to
* this method. Calling this method twice will complete any previously opened observable
* (leaving unprocessed elements in the queue).
* @return An observable containing the contents of the queue in order
*/
public Observable<T> toObservable() {
synchronized (mLock) {
if (mSubject != null) {
mSubject.onCompleted();
}
if (mQueue.isEmpty()) {
mSubject = ReplaySubject.create();
} else {
mSubject = ReplaySubject.create(mQueue.size());
for (T data : mQueue) {
mSubject.onNext(data);
}
}
}
return mSubject.map(item -> {
mQueue.remove();
return item;
}).asObservable();
}
}