package io.github.memfis19.cadar.internal.process;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.support.v4.util.Pair;
import java.util.List;
import java.util.Queue;
import io.github.memfis19.cadar.data.entity.Event;
import io.github.memfis19.cadar.data.process.EventCalculator;
import io.github.memfis19.cadar.internal.helper.ScrollManager;
import io.github.memfis19.cadar.internal.process.utils.CircularFifoQueue;
/**
* Created by memfis on 7/22/16.
*/
public abstract class EventsProcessor<T, E> extends HandlerThread implements ScrollManager.OnScrollChanged {
private static final String TAG = "EventsProcessor";
private static final int MESSAGE_EVENTS_PROCESS = 126;
private EventCalculator eventCalculator;
private List<Event> eventList;
private Queue<Pair<T, E>> resultQueue = new CircularFifoQueue<>(3);
private boolean shouldProcess;
private boolean processAsync = false;
private boolean hasQuit = false;
private Handler requestHandler;
private Handler responseHandler = new Handler(Looper.getMainLooper());
private EventsProcessorCallback<T, E> eventsProcessorCallback;
private ScrollManager scrollManager;
public EventsProcessor(boolean shouldProcess, EventCalculator eventProcessor, boolean processAsync) {
super(String.valueOf(System.currentTimeMillis()), Process.THREAD_PRIORITY_BACKGROUND);
this.shouldProcess = shouldProcess;
this.eventCalculator = eventProcessor;
this.processAsync = processAsync;
}
public void setScrollManager(ScrollManager scrollManager) {
this.scrollManager = scrollManager;
this.scrollManager.subscribeForScrollStateChanged(this);
}
protected EventCalculator getEventProcessor() {
return eventCalculator;
}
protected List<Event> getEventList() {
return eventList;
}
protected boolean isShouldProcess() {
return shouldProcess;
}
public void setEventProcessor(EventCalculator eventProcessor) {
this.eventCalculator = eventProcessor;
}
public void setEvents(List<Event> eventList) {
this.eventList = eventList;
this.eventCalculator.setEventsToProcess(eventList);
}
public void setEventsProcessorCallback(EventsProcessorCallback<T, E> eventsProcessorCallback) {
this.eventsProcessorCallback = eventsProcessorCallback;
}
public void queueEventsProcess(T target) {
if (target == null) return;
requestHandler.obtainMessage(MESSAGE_EVENTS_PROCESS, target).sendToTarget();
}
@Override
protected void onLooperPrepared() {
requestHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message message) {
if (message.what == MESSAGE_EVENTS_PROCESS) {
T target = (T) message.obj;
handleRequest(target);
}
}
};
}
@Override
public boolean quit() {
release();
return super.quit();
}
@Override
public boolean quitSafely() {
release();
return (Build.VERSION.SDK_INT > 17) ? super.quitSafely() : super.quit();
}
private void release() {
hasQuit = true;
resultQueue.clear();
if (scrollManager != null) scrollManager.unSubscribeForScrollStateChanged(this);
}
private void handleRequest(final T target) {
if (processAsync) processEventsAsync(target, eventsProcessorCallback);
else deliverResult(target, processEvents(target));
}
protected E processEvents(final T target) {
return null;
}
protected void processEventsAsync(final T target, EventsProcessorCallback<T, E> eventsProcessorCallback) {
}
private void deliverResult(final T target, final E result) {
if (scrollManager != null && scrollManager.getCurrentScrollState() == ScrollManager.SCROLL_STATE_IDLE) {
responseHandler.post(new Runnable() {
@Override
public void run() {
if (hasQuit) return;
if (eventsProcessorCallback != null)
eventsProcessorCallback.onEventsProcessed(target, result);
}
});
} else {
resultQueue.add(new Pair<>(target, result));
}
}
@Override
public void onScrollStateChanged(@ScrollManager.ScrollState int scrollState) {
if (scrollState == ScrollManager.SCROLL_STATE_IDLE) {
for (final Pair<T, E> pair : resultQueue) {
responseHandler.post(new Runnable() {
@Override
public void run() {
if (hasQuit) return;
if (eventsProcessorCallback != null)
eventsProcessorCallback.onEventsProcessed(pair.first, pair.second);
resultQueue.remove(pair);
}
});
}
}
}
}