package com.vaguehope.onosendai.model;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import android.view.View;
import com.vaguehope.onosendai.R;
import com.vaguehope.onosendai.config.Account;
import com.vaguehope.onosendai.config.Column;
import com.vaguehope.onosendai.config.Config;
import com.vaguehope.onosendai.images.ImageLoadRequest;
import com.vaguehope.onosendai.images.ImageLoader;
import com.vaguehope.onosendai.model.TweetRowView.QuotingTweetRowView;
import com.vaguehope.onosendai.provider.ProviderMgr;
import com.vaguehope.onosendai.provider.ProviderMgr.ProviderMgrProvider;
import com.vaguehope.onosendai.storage.DbProvider;
import com.vaguehope.onosendai.util.ExcpetionHelper;
import com.vaguehope.onosendai.util.LogWrapper;
import com.vaguehope.onosendai.util.Result;
import com.vaguehope.onosendai.util.exec.ExecutorEventListener;
import com.vaguehope.onosendai.util.exec.TrackingAsyncTask;
public class LinkedTweetLoader {
protected static final LogWrapper LOG = new LogWrapper("LTL");
private final DbProvider dbProvider;
private final Executor localEs;
private final Executor netEs;
private final ExecutorEventListener eventListener;
private final Config config;
private final ProviderMgrProvider provMgr;
private final boolean hdMedia;
public LinkedTweetLoader (final DbProvider dbProvider, final Executor localEs, final Executor netEs, final ExecutorEventListener eventListener,
final Config config, final ProviderMgrProvider provMgr, final boolean hdMedia) {
if (dbProvider == null) throw new IllegalArgumentException("Must specificy a db provider.");
if (localEs == null) throw new IllegalArgumentException("Must specificy a local executor.");
if (netEs == null) throw new IllegalArgumentException("Must specificy a network executor.");
if (config == null) throw new IllegalArgumentException("Must specificy config.");
if (provMgr == null) throw new IllegalArgumentException("Must specificy a provMgr.");
this.dbProvider = dbProvider;
this.localEs = localEs;
this.netEs = netEs;
this.eventListener = eventListener;
this.config = config;
this.provMgr = provMgr;
this.hdMedia = hdMedia;
}
protected ExecutorEventListener getEventListener () {
return this.eventListener;
}
protected DbProvider getDbProvider () {
return this.dbProvider;
}
protected Executor getNetEs () {
return this.netEs;
}
protected Config getConf () {
return this.config;
}
protected ProviderMgr getProvMgr () {
return this.provMgr.getProviderMgr();
}
protected boolean getHdMedia () {
return this.hdMedia;
}
protected void loadTweet (final TweetLoadRequest req) {
if (!req.shouldStartLoading()) return;
req.displayPending();
new TweetLoaderTask(this, req).executeOnExecutor(this.localEs);
}
public static class TweetLoadRequest {
private final String parentSid;
private final String quotedSid;
private final QuotingTweetRowView rowView;
private final ImageLoader imageLoader;
private final int reqWidth;
public TweetLoadRequest (final String parentSid, final String quotedSid, final QuotingTweetRowView rowView, final ImageLoader imageLoader, final int reqWidth) {
this.parentSid = parentSid;
this.quotedSid = quotedSid;
this.rowView = rowView;
this.imageLoader = imageLoader;
this.reqWidth = reqWidth;
}
public String getParentSid () {
return this.parentSid;
}
public String getQuotedSid () {
return this.quotedSid;
}
private View getTrackerWidget () {
return this.rowView.getQTweet();
}
public void displayIfRequired (final Tweet tweet) {
if (!shouldFinishLoading()) return;
display(tweet);
}
public void displayIfRequired (final Exception e) {
if (!shouldFinishLoading()) return;
display(e);
}
public void displayPending () {
this.rowView.getQcte().setExpanded(false);
this.rowView.getQTweet().setText(String.format("[ %s ]", this.quotedSid));
this.rowView.getQName().setText("");
this.rowView.getQAvatar().setImageResource(R.drawable.question_blue);
this.rowView.showQInlineMedia(false);
getTrackerWidget().setTag(R.id.imageLoading, this.quotedSid);
getTrackerWidget().setTag(R.id.imageLoaded, null);
}
private void display (final Tweet quotedTweet) {
this.rowView.getQTweet().setText(quotedTweet.getBody());
final String usernameWithSubtitle = quotedTweet.getUsernameWithSubtitle();
this.rowView.getQName().setText(usernameWithSubtitle != null ? usernameWithSubtitle : quotedTweet.getFullnameWithSubtitle());
final String avatarUrl = quotedTweet.getAvatarUrl();
if (avatarUrl != null) {
this.imageLoader.loadImage(new ImageLoadRequest(avatarUrl, this.rowView.getQAvatar()));
}
else {
this.rowView.getQAvatar().setImageResource(R.drawable.question_blue);
}
final String quotedInlineMediaUrl = quotedTweet.getInlineMediaUrl();
if (quotedInlineMediaUrl != null) {
this.rowView.showQInlineMedia(true);
this.imageLoader.loadImage(new ImageLoadRequest(quotedInlineMediaUrl, this.rowView.getQInlineMedia(), this.reqWidth, this.rowView.getQInlineMediaLoadListener()));
}
else {
this.rowView.showQInlineMedia(false);
}
getTrackerWidget().setTag(R.id.imageLoading, null);
getTrackerWidget().setTag(R.id.imageLoaded, this.quotedSid);
}
private void display (final Exception e) {
this.rowView.getQTweet().setText(ExcpetionHelper.veryShortMessage(e));
this.rowView.getQName().setText(String.format("[ %s ]", this.quotedSid));
this.rowView.getQAvatar().setImageResource(R.drawable.exclamation_red);
this.rowView.showQInlineMedia(false);
getTrackerWidget().setTag(R.id.imageLoading, null);
getTrackerWidget().setTag(R.id.imageLoaded, null);
}
/**
* On UI thread.
*/
public boolean shouldStartLoading () {
return !this.quotedSid.equals(getTrackerWidget().getTag(R.id.imageLoaded));
}
/**
* On BG thread.
*/
public boolean shouldFinishLoading () {
return this.quotedSid.equals(getTrackerWidget().getTag(R.id.imageLoading));
}
}
private static class TweetLoaderTask extends TrackingAsyncTask<Void, Void, Result<Tweet>> {
private final LinkedTweetLoader loader;
private final TweetLoadRequest req;
public TweetLoaderTask (final LinkedTweetLoader loader, final TweetLoadRequest req) {
super(loader.getEventListener());
this.loader = loader;
this.req = req;
}
@Override
public String toString () {
return "load:" + this.req.getQuotedSid();
}
@Override
protected Result<Tweet> doInBackgroundWithTracking (final Void... params) {
if (!this.req.shouldFinishLoading()) return null;
try {
final Tweet tweet = this.loader.getDbProvider().getDb().getTweetDetails(this.req.getQuotedSid());
return tweet != null ? new Result<Tweet>(tweet) : null;
}
catch (final Exception e) { // NOSONAR To report errors.
return new Result<Tweet>(e);
}
catch (final Throwable e) { // NOSONAR To report errors.
return new Result<Tweet>(new ExecutionException("Failed to load tweet.", e));
}
}
@Override
protected void onPostExecute (final Result<Tweet> result) {
if (result == null) {
if (this.req.shouldFinishLoading()) {
new TweetFetcherTask(this.loader, this.req).executeOnExecutor(this.loader.getNetEs());
}
}
else if (result.isSuccess()) {
this.req.displayIfRequired(result.getData());
}
else {
LOG.e("Error loading tweet.", result.getE());
this.req.displayIfRequired(result.getE());
}
}
}
private static class TweetFetcherTask extends TrackingAsyncTask<Void, Void, Result<Tweet>> {
private final LinkedTweetLoader loader;
private final TweetLoadRequest req;
public TweetFetcherTask (final LinkedTweetLoader loader, final TweetLoadRequest req) {
super(loader.getEventListener());
this.loader = loader;
this.req = req;
}
@Override
public String toString () {
return "fetch:" + this.req.getQuotedSid();
}
@Override
protected Result<Tweet> doInBackgroundWithTracking (final Void... params) {
if (!this.req.shouldFinishLoading()) return null;
try {
final Tweet parent = this.loader.getDbProvider().getDb().getTweetDetails(this.req.getParentSid());
if (parent != null) {
final Account account = MetaUtils.accountFromMeta(parent, this.loader.getConf());
if (account != null) {
final Tweet tweet = this.loader.getProvMgr().getTwitterProvider().getTweet(account, Long.parseLong(this.req.getQuotedSid()), this.loader.getHdMedia());
LOG.i("Fetched: %s=%s", this.req.getQuotedSid(), tweet);
this.loader.getDbProvider().getDb().storeTweets(Column.ID_CACHED, Collections.singletonList(tweet));
return new Result<Tweet>(tweet);
}
return new Result<Tweet>(new IllegalStateException("Tweet missing account meta: " + parent));
}
return new Result<Tweet>(new IllegalStateException("Tweet not in DB: " + this.req.getParentSid()));
}
catch (final Exception e) { // NOSONAR To report errors.
return new Result<Tweet>(e);
}
catch (final Throwable e) { // NOSONAR To report errors.
return new Result<Tweet>(new ExecutionException("Failed to fetch tweet.", e));
}
}
@Override
protected void onPostExecute (final Result<Tweet> result) {
if (result == null) return; // Request was no longer required.
if (result.isSuccess()) {
this.req.displayIfRequired(result.getData());
}
else {
LOG.e("Error fetching tweet.", result.getE());
this.req.displayIfRequired(result.getE());
}
}
}
}