package hk.reality.stock.service.fetcher;
import hk.reality.stock.PortfolioActivity;
import hk.reality.stock.R;
import hk.reality.stock.StockApplication;
import hk.reality.stock.model.Stock;
import hk.reality.stock.model.StockDetail;
import hk.reality.stock.service.exception.DownloadException;
import hk.reality.stock.service.exception.ParseException;
import hk.reality.utils.NetworkDetector;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
public class QuoteUpdateTask extends AsyncTask<Stock, Integer, Boolean> {
private static final String TAG = "QuoteUpdateTask";
private PortfolioActivity activity;
private int total = 0;
private int current = 0;
private Error error;
enum Error {
ERROR_NO_NET, ERROR_DOWNLOAD, ERROR_PARSE, ERROR_UNKNOWN
}
public QuoteUpdateTask(PortfolioActivity activity) {
this.activity = activity;
}
@Override
protected Boolean doInBackground(Stock... stocks) {
if (!NetworkDetector.hasValidNetwork(activity)) {
error = Error.ERROR_NO_NET;
return Boolean.FALSE;
}
total = stocks.length;
QuoteFetcher fetcher = QuoteFetcherFactory.getQuoteFetcher();
fetcher.getClient().getConnectionManager().closeExpiredConnections(); // close previously opened conn
fetcher.getClient().getConnectionManager().closeIdleConnections(30, TimeUnit.SECONDS);
ExecutorService executor = StockApplication.getExecutor();
try {
ArrayList<Future<StockDetail>> results = new ArrayList<Future<StockDetail>>();
for(Stock s : stocks) {
UpdateSubTask task = new UpdateSubTask(fetcher, s);
results.add(executor.submit(task));
}
for(Future<StockDetail> r : results) {
try {
r.get();
} catch (ExecutionException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
Log.e(TAG, "unexpected error while update stock quote", t);
error = Error.ERROR_UNKNOWN;
return Boolean.FALSE;
}
}
}
StockApplication.getPortfolioService().update(StockApplication.getCurrentPortfolio());
return Boolean.TRUE;
} catch (DownloadException de) {
Log.e(TAG, "error downloading stock", de);
error = Error.ERROR_DOWNLOAD;
return Boolean.FALSE;
} catch (ParseException pe) {
Log.e(TAG, "error parsing code", pe);
error = Error.ERROR_PARSE;
return Boolean.FALSE;
} catch (InterruptedException e) {
Log.e(TAG, "download timeout", e);
error = Error.ERROR_DOWNLOAD;
return Boolean.FALSE;
} catch (RuntimeException re) {
Log.e(TAG, "unexpected error while update stock quote", re);
error = Error.ERROR_UNKNOWN;
return Boolean.FALSE;
}
}
class UpdateSubTask implements Callable<StockDetail> {
Stock stock;
QuoteFetcher fetcher;
public UpdateSubTask(QuoteFetcher fetcher, Stock s) {
this.fetcher = fetcher;
this.stock = s;
}
@Override
public StockDetail call() throws Exception {
StockDetail detail = fetcher.fetch(stock.getQuote());
stock.setDetail(detail);
publishProgress(++current);
return detail;
}
}
@Override
protected void onCancelled() {
activity.getParent().setProgressBarVisibility(false);
Toast.makeText(activity, R.string.msg_download_cancelled, Toast.LENGTH_SHORT);
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
activity.getAdapter().notifyDataSetChanged();
} else {
switch (error) {
case ERROR_NO_NET:
Toast.makeText(activity, R.string.msg_no_network, Toast.LENGTH_LONG).show();
break;
case ERROR_DOWNLOAD:
activity.showDialog(PortfolioActivity.DIALOG_ERR_DOWNLOAD_UPDATE);
break;
case ERROR_PARSE:
activity.showDialog(PortfolioActivity.DIALOG_ERR_QUOTE_UPDATE);
break;
case ERROR_UNKNOWN:
activity.showDialog(PortfolioActivity.DIALOG_ERR_UNEXPECTED);
break;
default:
break;
}
}
activity.getParent().setProgressBarVisibility(false);
}
@Override
protected void onPreExecute() {
activity.getParent().setProgressBarVisibility(true);
activity.getParent().setProgress(0);
}
@Override
protected void onProgressUpdate(Integer... values) {
float progress = ((float) values[0] / (float) total) * 10000;
Log.i(TAG, "downloaded " + values[0] + "/" + total + ", " + progress);
activity.getParent().setProgress((int) progress);
activity.getAdapter().notifyDataSetChanged();
}
}