package com.uservoice;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
public class Collection implements Iterable<JSONObject> {
public static final int PER_PAGE = 100;
private Client client;
private int limit = Integer.MAX_VALUE;
private int perPage;
private JSONObject responseData = null;
private String path;
private Map<Integer, JSONArray> pages = new HashMap<Integer, JSONArray>();
public Collection(Client client, String path, Integer limit) {
this.client = client;
this.path = path;
if (limit != null) {
this.limit = limit;
}
this.perPage = Math.min(this.limit, PER_PAGE);
}
public Collection(Client client, String path) {
this(client, path, Integer.MAX_VALUE);
}
public int size() {
if (responseData == null) {
try {
get(0);
} catch (IndexOutOfBoundsException e) {
/* Empty array */
}
}
return Math.min(responseData.getInt("total_records"), limit);
}
public JSONObject get(int i) {
if (i == 0 || (i > 0 && i < size())) {
return loadPage((int) (i / (float) (PER_PAGE)) + 1).getJSONObject(i % PER_PAGE);
} else {
throw new IndexOutOfBoundsException();
}
}
/**
* Requests i'th page from UserVoice. Thread-safe and makes one HTTP
* connection.
*
* @param i
* and index between 1..(1/PER_PAGE) + 1
* @return The page in a JSONArray
* @throws APIError
* if something unexpected happened
* @throws Unauthorized
* if the user didn't have permissions to request the page
*/
public synchronized JSONArray loadPage(int i) {
if (pages == null || pages.get(i) == null) {
String url;
if (path.contains("?")) {
url = path + "&";
} else {
url = path + "?";
}
//System.out.println(url);
JSONObject result = client.get(url + "per_page=" + perPage + "&page=" + i);
//System.out.println(result);
if (result != null && result.names().size() == 2 && !result.getJSONObject("response_data").isNullObject()) {
responseData = result.getJSONObject("response_data");
for (Object name : result.names()) {
if (!"response_data".equals(name)) {
pages.put(i, result.getJSONArray(name.toString()));
}
}
pages.put(i, pages.get(i));
} else {
throw new NotFound("The resource you requested is not a collection.");
}
}
return pages.get(i);
}
public boolean isEmpty() throws APIError {
return size() == 0;
}
public Iterator<JSONObject> iterator() {
return new Iterator<JSONObject>() {
int current = 0;
public boolean hasNext() {
return current < size();
}
public JSONObject next() {
return get(current++);
}
public void remove() {
throw new UnsupportedOperationException("Read-Only Collection");
}
};
}
public JSONObject[] toArray() {
int arraySize = size();
JSONObject[] array = new JSONObject[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = get(i);
}
return array;
}
}