package org.mtransit.android.task;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.mtransit.android.commons.MTLog;
import org.mtransit.android.commons.RuntimeUtils;
import org.mtransit.android.commons.data.POIStatus;
import org.mtransit.android.commons.provider.StatusProviderContract;
import org.mtransit.android.commons.task.MTAsyncTask;
import org.mtransit.android.data.DataSourceManager;
import org.mtransit.android.data.DataSourceProvider;
import org.mtransit.android.data.POIManager;
import org.mtransit.android.data.StatusProviderProperties;
import android.content.Context;
public class StatusLoader implements MTLog.Loggable {
private static final String TAG = StatusLoader.class.getSimpleName();
@Override
public String getLogTag() {
return TAG;
}
private static StatusLoader instance;
public static StatusLoader get() {
if (instance == null) {
instance = new StatusLoader();
}
return instance;
}
private StatusLoader() {
}
private ThreadPoolExecutor fetchStatusExecutor;
private static final int CORE_POOL_SIZE = RuntimeUtils.NUMBER_OF_CORES > 1 ? RuntimeUtils.NUMBER_OF_CORES / 2 : 1;
private static final int MAX_POOL_SIZE = RuntimeUtils.NUMBER_OF_CORES > 1 ? RuntimeUtils.NUMBER_OF_CORES / 2 : 1;
public ThreadPoolExecutor getFetchStatusExecutor() {
if (this.fetchStatusExecutor == null) {
this.fetchStatusExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LIFOBlockingDeque<Runnable>());
}
return fetchStatusExecutor;
}
public boolean isBusy() {
return this.fetchStatusExecutor != null && this.fetchStatusExecutor.getActiveCount() > 0;
}
public void clearAllTasks() {
if (this.fetchStatusExecutor != null) {
this.fetchStatusExecutor.shutdown();
this.fetchStatusExecutor = null;
}
}
public boolean findStatus(Context context, POIManager poim, StatusProviderContract.Filter statusFilter, StatusLoader.StatusLoaderListener listener,
boolean skipIfBusy) {
if (skipIfBusy && isBusy()) {
return false;
}
HashSet<StatusProviderProperties> providers = DataSourceProvider.get(context).getTargetAuthorityStatusProviders(poim.poi.getAuthority());
if (providers != null && providers.size() > 0) {
Iterator<StatusProviderProperties> it = providers.iterator();
while (it.hasNext()) {
StatusProviderProperties provider = it.next();
StatusFetcherCallable task = new StatusFetcherCallable(context, listener, provider, poim, statusFilter); // , null, timestamp);
task.executeOnExecutor(getFetchStatusExecutor());
}
}
return true;
}
private static class StatusFetcherCallable extends MTAsyncTask<Void, Void, POIStatus> {
private static final String TAG = StatusLoader.class.getSimpleName() + '>' + StatusFetcherCallable.class.getSimpleName();
@Override
public String getLogTag() {
return TAG;
}
private WeakReference<Context> contextWR;
private StatusProviderProperties statusProvider;
private WeakReference<POIManager> poiWR;
private StatusLoader.StatusLoaderListener listener;
private StatusProviderContract.Filter statusFilter;
public StatusFetcherCallable(Context context, StatusLoader.StatusLoaderListener listener, StatusProviderProperties statusProvider, POIManager poim,
StatusProviderContract.Filter statusFilter) {
this.contextWR = new WeakReference<Context>(context);
this.listener = listener;
this.statusProvider = statusProvider;
this.poiWR = new WeakReference<POIManager>(poim);
this.statusFilter = statusFilter;
}
@Override
protected POIStatus doInBackgroundMT(Void... params) {
try {
return call();
} catch (Exception e) {
MTLog.w(this, e, "Error while running task!");
return null;
}
}
@Override
protected void onPostExecute(POIStatus result) {
if (result == null) {
return;
}
POIManager poim = this.poiWR == null ? null : this.poiWR.get();
if (poim == null) {
return;
}
boolean statusChanged = poim.setStatus(result);
if (statusChanged) {
if (this.listener == null) {
return;
}
this.listener.onStatusLoaded(result);
}
}
public POIStatus call() throws Exception {
Context context = this.contextWR == null ? null : this.contextWR.get();
if (context == null) {
return null;
}
POIManager poim = this.poiWR == null ? null : this.poiWR.get();
if (poim == null) {
return null;
}
if (this.statusFilter == null) {
return null;
}
return DataSourceManager.findStatus(context, this.statusProvider.getAuthority(), this.statusFilter);
}
}
public static class LIFOBlockingDeque<E> extends LinkedBlockingDeque<E> implements MTLog.Loggable {
private static final String TAG = LIFOBlockingDeque.class.getSimpleName();
@Override
public String getLogTag() {
return TAG;
}
private static final long serialVersionUID = -470545646554946137L;
@Override
public boolean offer(E e) {
return super.offerFirst(e);
}
@Override
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
return super.offerFirst(e, timeout, unit);
}
@Override
public boolean add(E e) {
return super.offerFirst(e);
}
@Override
public void put(E e) throws InterruptedException {
super.putFirst(e);
}
}
public interface StatusLoaderListener {
void onStatusLoaded(POIStatus status);
}
}