package com.sunlightlabs.congress.services;
import com.sunlightlabs.congress.models.CongressException;
import com.sunlightlabs.congress.models.Roll;
import com.sunlightlabs.congress.models.Roll.Vote;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class RollService {
public static String[] basicFields = {
"roll_id", "chamber", "number", "year", "congress", "bill_id",
"bill.official_title", "bill.short_title",
"voted_at", "vote_type", "roll_type", "question", "required", "result",
"breakdown",
"nomination.nominees", "nomination.nomination_id", "nomination.number", "nomination.organization",
"amendment.amendment_id", "amendment.purpose", "amendment.description", "amendment.amends_bill_id"
};
public static Roll find(String id, String[] fields) throws CongressException {
Map<String,String> params = new HashMap<String,String>();
params.put("roll_id", id);
return rollFor(Congress.url("votes", fields, params));
}
public static List<Roll> latestVotes(String bioguideId, String chamber, int page, int per_page) throws CongressException {
Map<String,String> params = new HashMap<String,String>();
params.put("order", "voted_at");
params.put("chamber", chamber);
params.put("voter_ids." + bioguideId + "__exists", "true");
String[] fields = new String[basicFields.length + 1];
System.arraycopy(basicFields, 0, fields, 0, basicFields.length);
fields[basicFields.length + 0] = "voter_ids." + bioguideId;
return rollsFor(Congress.url("votes", fields, params, page, per_page));
}
public static List<Roll> latestVotes(int page, int per_page) throws CongressException {
Map<String,String> params = new HashMap<String,String>();
params.put("order", "voted_at");
return rollsFor(Congress.url("votes", basicFields, params, page, per_page));
}
/* JSON parsers, also useful for other service endpoints within this package */
protected static Roll fromAPI(JSONObject json) throws JSONException, ParseException, CongressException {
if (json == null)
throw new CongressException("Error loading votes.");
Roll roll = new Roll();
if (!json.isNull("chamber"))
roll.chamber = json.getString("chamber");
if (!json.isNull("vote_type"))
roll.vote_type = json.getString("vote_type");
if (!json.isNull("question"))
roll.question = json.getString("question");
if (!json.isNull("result"))
roll.result = json.getString("result");
if (!json.isNull("congress"))
roll.congress = json.getInt("congress");
if (!json.isNull("year"))
roll.year = json.getInt("year");
if (!json.isNull("voted_at"))
roll.voted_at = Congress.parseDate(json.getString("voted_at"));
// guaranteed fields for roll call votes
if (!json.isNull("required"))
roll.required = json.getString("required");
if (!json.isNull("number"))
roll.number = json.getInt("number");
if (!json.isNull("roll_id"))
roll.id = json.getString("roll_id");
if (!json.isNull("roll_type"))
roll.roll_type = json.getString("roll_type");
if (!json.isNull("bill_id"))
roll.bill_id = json.getString("bill_id");
if (!json.isNull("bill"))
roll.bill = BillService.fromAPI(json.getJSONObject("bill"));
roll.voteBreakdown.put(Roll.YEA, 0);
roll.voteBreakdown.put(Roll.NAY, 0);
roll.voteBreakdown.put(Roll.PRESENT, 0);
roll.voteBreakdown.put(Roll.NOT_VOTING, 0);
if (!json.isNull("breakdown")) {
JSONObject vote_breakdown = json.getJSONObject("breakdown");
JSONObject total = vote_breakdown.getJSONObject("total");
Iterator<?> iter = total.keys();
while (iter.hasNext()) {
String key = (String) iter.next();
roll.voteBreakdown.put(key, total.getInt(key));
if (!key.equals(Roll.YEA) && !key.equals(Roll.NAY) && !key.equals(Roll.PRESENT) && !key.equals(Roll.NOT_VOTING))
roll.otherVotes = true;
}
//todo: what does this mean
// until this is fixed on the server
if (roll.otherVotes) {
roll.voteBreakdown.remove(Roll.YEA);
roll.voteBreakdown.remove(Roll.NAY);
}
}
if (!json.isNull("nomination")) {
JSONObject nominationObject = json.getJSONObject("nomination");
roll.nomination = NominationService.fromAPI(nominationObject);
}
if (!json.isNull("amendment")) {
JSONObject amendmentObject = json.getJSONObject("amendment");
roll.amendment = AmendmentService.fromAPI(amendmentObject);
}
if (!json.isNull("voters")) {
roll.voters = new HashMap<String, Vote>();
JSONObject votersObject = json.getJSONObject("voters");
Iterator<?> iter = votersObject.keys();
while (iter.hasNext()) {
String voter_id = (String) iter.next();
JSONObject voterObject = votersObject.getJSONObject(voter_id);
Roll.Vote vote = voteFromAPI(voter_id, voterObject);
// if there was no voter info for some reason, don't add the vote
if (vote != null)
roll.voters.put(voter_id, vote);
}
}
if (!json.isNull("voter_ids")) {
roll.voter_ids = new HashMap<String, Vote>();
JSONObject voterIdsObject = json.getJSONObject("voter_ids");
Iterator<?> iter = voterIdsObject.keys();
while (iter.hasNext()) {
String voter_id = (String) iter.next();
String vote_name = voterIdsObject.getString(voter_id);
roll.voter_ids.put(voter_id, voteFromAPI(voter_id, vote_name));
}
}
return roll;
}
protected static Vote voteFromAPI(String voter_id, JSONObject json) throws JSONException, CongressException {
Vote vote = new Vote();
vote.vote = json.getString("vote");
vote.voter_id = voter_id;
vote.voter = LegislatorService.fromAPI(json.getJSONObject("voter"));
if (vote.voter == null)
return null;
else
return vote;
}
protected static Vote voteFromAPI(String voter_id, String vote_name) throws JSONException, CongressException {
Vote vote = new Vote();
vote.vote = vote_name;
vote.voter_id = voter_id;
return vote;
}
private static Roll rollFor(String url) throws CongressException {
try {
return fromAPI(Congress.firstResult(url));
} catch (JSONException e) {
throw new CongressException(e, "Problem parsing the JSON from " + url);
} catch (ParseException e) {
throw new CongressException(e, "Problem parsing a date in the JSON from " + url);
}
}
private static List<Roll> rollsFor(String url) throws CongressException {
List<Roll> rolls = new ArrayList<Roll>();
try {
JSONArray results = Congress.resultsFor(url);
int length = results.length();
for (int i = 0; i < length; i++)
rolls.add(fromAPI(results.getJSONObject(i)));
} catch (JSONException e) {
throw new CongressException(e, "Problem parsing the JSON from " + url);
} catch (ParseException e) {
throw new CongressException(e, "Problem parsing a date in the JSON from " + url);
}
return rolls;
}
}