package org.wikipedia.gallery;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import org.wikipedia.dataclient.WikiSite;
import org.wikipedia.dataclient.mwapi.MwException;
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
import org.wikipedia.dataclient.retrofit.MwCachedService;
import org.wikipedia.dataclient.retrofit.WikiCachedService;
import org.wikipedia.page.PageTitle;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
import static org.wikipedia.Constants.PREFERRED_THUMB_SIZE;
public class GalleryCollectionClient {
// TODO: This limit seems pretty arbitrary. Do we need or want to adjust it?
private static final int MAX_ITEM_COUNT = 256;
@NonNull private final WikiCachedService<Service> cachedService = new MwCachedService<>(Service.class);
public Map<String, ImageInfo> request(@NonNull WikiSite wiki, @NonNull PageTitle title, boolean getThumbs) throws IOException {
return request(cachedService.service(wiki), title, getThumbs);
}
@VisibleForTesting Map<String, ImageInfo> request(@NonNull Service service, @NonNull PageTitle title, boolean getThumbs)
throws IOException, MwException {
Map<String, ImageInfo> result = new HashMap<>();
MwQueryResponse<FilePagesWithImageInfo> currentResponse;
Map<String, String> continuation = null;
do {
currentResponse = continuation == null
? fetch(service, title, getThumbs)
: continueFetch(service, title, getThumbs, continuation);
if (currentResponse.success()) {
// TODO: Technically, new results should be merged with rather than overwrite old ones.
// However, Map.merge() requires Java 8. As of this writing (May 2017), the Jack
// compiler is deprecated, but still required to bump JAVA_VERSION to 1_8.
//
// In the meantime, based on manual testing, overwriting seems not to result in any
// information loss, and should be adequate in practice.
//
// noinspection ConstantConditions
result.putAll(currentResponse.query().images());
continuation = currentResponse.getContinuation();
} else if (currentResponse.hasError()) {
// noinspection ConstantConditions
throw new MwException(currentResponse.getError());
} else {
throw new IOException("An unknown error occurred.");
}
} while (continuation != null);
return result;
}
private MwQueryResponse<FilePagesWithImageInfo> fetch(@NonNull Service service, @NonNull PageTitle title, boolean getThumbs)
throws IOException {
Call<MwQueryResponse<FilePagesWithImageInfo>> call = getThumbs
? service.fetch("dimensions|mime|url", Integer.toString(PREFERRED_THUMB_SIZE),
Integer.toString(PREFERRED_THUMB_SIZE), title.toString())
: service.fetch("dimensions|mime", null, null, title.toString());
return call.execute().body();
}
private MwQueryResponse<FilePagesWithImageInfo> continueFetch(@NonNull Service service, @NonNull PageTitle title,
boolean getThumbs, @Nullable Map<String, String> continuation)
throws IOException {
Call<MwQueryResponse<FilePagesWithImageInfo>> call = getThumbs
? service.continueFetch("dimensions|mime|url", Integer.toString(PREFERRED_THUMB_SIZE),
Integer.toString(PREFERRED_THUMB_SIZE), title.toString(), continuation)
: service.continueFetch("dimensions|mime", null, null, title.toString(), continuation);
return call.execute().body();
}
@VisibleForTesting interface Service {
@GET("w/api.php?action=query&format=json&formatversion=2&prop=imageinfo&generator=images&redirects=&gimlimit=" + MAX_ITEM_COUNT)
Call<MwQueryResponse<FilePagesWithImageInfo>> fetch(@NonNull @Query("iiprop") String properties,
@Nullable @Query("iiurlwidth") String thumbWidth,
@Nullable @Query("iiurlheight") String thumbHeight,
@NonNull @Query("titles") String title);
// N.B. @QueryMap will throw if it receives a null parameter, separate handling is required.
@GET("w/api.php?action=query&format=json&formatversion=2&prop=imageinfo&generator=images&redirects=&gimlimit=" + MAX_ITEM_COUNT)
Call<MwQueryResponse<FilePagesWithImageInfo>> continueFetch(@NonNull @Query("iiprop") String properties,
@Nullable @Query("iiurlwidth") String thumbWidth,
@Nullable @Query("iiurlheight") String thumbHeight,
@NonNull @Query("titles") String title,
@NonNull @QueryMap Map<String, String> continuation);
}
}