package org.mtransit.android.task;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
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.ServiceUpdate;
import org.mtransit.android.commons.provider.ServiceUpdateProviderContract;
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.ServiceUpdateProviderProperties;
import android.content.Context;
public class ServiceUpdateLoader implements MTLog.Loggable {
private static final String TAG = ServiceUpdateLoader.class.getSimpleName();
@Override
public String getLogTag() {
return TAG;
}
private static ServiceUpdateLoader instance;
public static ServiceUpdateLoader get() {
if (instance == null) {
instance = new ServiceUpdateLoader();
}
return instance;
}
private ServiceUpdateLoader() {
}
private ThreadPoolExecutor fetchServiceUpdateExecutor;
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 getFetchServiceUpdateExecutor() {
if (this.fetchServiceUpdateExecutor == null) {
this.fetchServiceUpdateExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, 0L, TimeUnit.MILLISECONDS,
new LIFOBlockingDeque<Runnable>());
}
return fetchServiceUpdateExecutor;
}
public boolean isBusy() {
return this.fetchServiceUpdateExecutor != null && this.fetchServiceUpdateExecutor.getActiveCount() > 0;
}
public void clearAllTasks() {
if (this.fetchServiceUpdateExecutor != null) {
this.fetchServiceUpdateExecutor.shutdown();
this.fetchServiceUpdateExecutor = null;
}
}
public boolean findServiceUpdate(Context context, POIManager poim, ServiceUpdateProviderContract.Filter serviceUpdateFilter,
ServiceUpdateLoader.ServiceUpdateLoaderListener listener, boolean skipIfBusy) {
if (skipIfBusy && isBusy()) {
return false;
}
HashSet<ServiceUpdateProviderProperties> providers = DataSourceProvider.get(context).getTargetAuthorityServiceUpdateProviders(poim.poi.getAuthority());
if (providers != null) {
if (providers.size() > 0) {
ServiceUpdateProviderProperties provider = providers.iterator().next();
ServiceUpdateFetcherCallable task = new ServiceUpdateFetcherCallable(context, listener, provider, poim, serviceUpdateFilter);
task.executeOnExecutor(getFetchServiceUpdateExecutor());
}
}
return true;
}
private static class ServiceUpdateFetcherCallable extends MTAsyncTask<Void, Void, ArrayList<ServiceUpdate>> {
private static final String TAG = ServiceUpdateLoader.TAG + '>' + ServiceUpdateFetcherCallable.class.getSimpleName();
@Override
public String getLogTag() {
return TAG;
}
private WeakReference<Context> contextWR;
private ServiceUpdateProviderProperties serviceUpdateProvider;
private WeakReference<POIManager> poiWR;
private ServiceUpdateLoader.ServiceUpdateLoaderListener listener;
private ServiceUpdateProviderContract.Filter serviceUpdateFilter;
public ServiceUpdateFetcherCallable(Context context, ServiceUpdateLoader.ServiceUpdateLoaderListener listener,
ServiceUpdateProviderProperties serviceUpdateProvider, POIManager poim, ServiceUpdateProviderContract.Filter serviceUpdateFilter) {
this.contextWR = new WeakReference<Context>(context);
this.listener = listener;
this.serviceUpdateProvider = serviceUpdateProvider;
this.poiWR = new WeakReference<POIManager>(poim);
this.serviceUpdateFilter = serviceUpdateFilter;
}
@Override
protected ArrayList<ServiceUpdate> doInBackgroundMT(Void... params) {
try {
return call();
} catch (Exception e) {
MTLog.w(this, e, "Error while running task!");
return null;
}
}
@Override
protected void onPostExecute(ArrayList<ServiceUpdate> result) {
if (result == null) {
return;
}
POIManager poim = this.poiWR == null ? null : this.poiWR.get();
if (poim == null) {
return;
}
poim.setServiceUpdates(result);
if (listener == null) {
return;
}
listener.onServiceUpdatesLoaded(poim.poi.getUUID(), poim.getServiceUpdatesOrNull());
}
public ArrayList<ServiceUpdate> 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.serviceUpdateFilter == null) {
return null;
}
return DataSourceManager.findServiceUpdates(context, this.serviceUpdateProvider.getAuthority(), this.serviceUpdateFilter);
}
}
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 ServiceUpdateLoaderListener {
void onServiceUpdatesLoaded(String targetUUID, ArrayList<ServiceUpdate> serviceUpdates);
}
}