/*******************************************************************************
* This file is part of RedReader.
*
* RedReader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RedReader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RedReader. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package org.quantumbadger.redreader.reddit.api;
import android.content.Context;
import android.util.Log;
import org.quantumbadger.redreader.account.RedditAccount;
import org.quantumbadger.redreader.cache.CacheManager;
import org.quantumbadger.redreader.cache.CacheRequest;
import org.quantumbadger.redreader.cache.downloadstrategy.DownloadStrategyAlways;
import org.quantumbadger.redreader.common.Constants;
import org.quantumbadger.redreader.common.TimestampBound;
import org.quantumbadger.redreader.io.CacheDataSource;
import org.quantumbadger.redreader.io.RequestResponseHandler;
import org.quantumbadger.redreader.jsonwrap.JsonValue;
import org.quantumbadger.redreader.reddit.RedditSubredditHistory;
import org.quantumbadger.redreader.reddit.things.RedditSubreddit;
import org.quantumbadger.redreader.reddit.things.RedditThing;
import java.util.Collection;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class RedditAPIIndividualSubredditDataRequester implements CacheDataSource<String, RedditSubreddit, SubredditRequestFailure> {
private static final String TAG = "IndividualSRDataReq";
private final Context context;
private final RedditAccount user;
public RedditAPIIndividualSubredditDataRequester(Context context, RedditAccount user) {
this.context = context;
this.user = user;
}
public void performRequest(final String subredditCanonicalName,
final TimestampBound timestampBound,
final RequestResponseHandler<RedditSubreddit, SubredditRequestFailure> handler) {
final CacheRequest aboutSubredditCacheRequest = new CacheRequest(
Constants.Reddit.getUri("/r/" + subredditCanonicalName + "/about.json"),
user,
null,
Constants.Priority.API_SUBREDDIT_INVIDIVUAL,
0,
DownloadStrategyAlways.INSTANCE,
Constants.FileType.SUBREDDIT_ABOUT,
CacheRequest.DOWNLOAD_QUEUE_REDDIT_API,
true,
false,
context
) {
@Override
protected void onCallbackException(Throwable t) {
handler.onRequestFailed(new SubredditRequestFailure(CacheRequest.REQUEST_FAILURE_PARSE, t, null, "Parse error", url));
}
@Override protected void onDownloadNecessary() {}
@Override protected void onDownloadStarted() {}
@Override protected void onProgress(final boolean authorizationInProgress, long bytesRead, long totalBytes) {}
@Override
protected void onFailure(@CacheRequest.RequestFailureType int type, Throwable t, Integer status, String readableMessage) {
handler.onRequestFailed(new SubredditRequestFailure(type, t, status, readableMessage, url));
}
@Override
protected void onSuccess(CacheManager.ReadableCacheFile cacheFile, long timestamp, UUID session,
boolean fromCache, String mimetype) {}
@Override
public void onJsonParseStarted(JsonValue result, long timestamp, UUID session, boolean fromCache) {
try {
final RedditThing subredditThing = result.asObject(RedditThing.class);
final RedditSubreddit subreddit = subredditThing.asSubreddit();
subreddit.downloadTime = timestamp;
handler.onRequestSuccess(subreddit, timestamp);
RedditSubredditHistory.addSubreddit(user, subredditCanonicalName);
} catch(Exception e) {
handler.onRequestFailed(new SubredditRequestFailure(CacheRequest.REQUEST_FAILURE_PARSE, e, null, "Parse error", url));
}
}
};
CacheManager.getInstance(context).makeRequest(aboutSubredditCacheRequest);
}
public void performRequest(final Collection<String> subredditCanonicalIds,
final TimestampBound timestampBound,
final RequestResponseHandler<HashMap<String, RedditSubreddit>, SubredditRequestFailure> handler) {
// TODO if there's a bulk API to do this, that would be good... :)
final HashMap<String, RedditSubreddit> result = new HashMap<>();
final AtomicBoolean stillOkay = new AtomicBoolean(true);
final AtomicInteger requestsToGo = new AtomicInteger(subredditCanonicalIds.size());
final AtomicLong oldestResult = new AtomicLong(Long.MAX_VALUE);
final RequestResponseHandler <RedditSubreddit, SubredditRequestFailure> innerHandler
= new RequestResponseHandler<RedditSubreddit, SubredditRequestFailure>() {
@Override
public void onRequestFailed(SubredditRequestFailure failureReason) {
synchronized(result) {
if(stillOkay.get()) {
stillOkay.set(false);
handler.onRequestFailed(failureReason);
}
}
}
@Override
public void onRequestSuccess(RedditSubreddit innerResult, long timeCached) {
synchronized(result) {
if(stillOkay.get()) {
result.put(innerResult.getKey(), innerResult);
oldestResult.set(Math.min(oldestResult.get(), timeCached));
try
{
RedditSubredditHistory.addSubreddit(user, innerResult.getCanonicalName());
}
catch(RedditSubreddit.InvalidSubredditNameException e)
{
Log.e(TAG, "Invalid subreddit name " + innerResult.name, e);
}
if(requestsToGo.decrementAndGet() == 0) {
handler.onRequestSuccess(result, oldestResult.get());
}
}
}
}
};
for(String subredditCanonicalId : subredditCanonicalIds) {
performRequest(subredditCanonicalId, timestampBound, innerHandler);
}
}
public void performWrite(RedditSubreddit value) {
throw new UnsupportedOperationException();
}
public void performWrite(Collection<RedditSubreddit> values) {
throw new UnsupportedOperationException();
}
}