package com.sunlightlabs.android.congress.fragments;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import com.sunlightlabs.android.congress.R;
import com.sunlightlabs.android.congress.notifications.Footer;
import com.sunlightlabs.android.congress.notifications.Subscriber;
import com.sunlightlabs.android.congress.notifications.Subscription;
import com.sunlightlabs.android.congress.utils.FragmentUtils;
import com.sunlightlabs.android.congress.utils.PaginationListener;
import com.sunlightlabs.android.congress.utils.Utils;
import com.sunlightlabs.congress.models.Amendment;
import com.sunlightlabs.congress.models.Bill;
import com.sunlightlabs.congress.models.CongressException;
import com.sunlightlabs.congress.models.Legislator;
import com.sunlightlabs.congress.models.Nomination;
import com.sunlightlabs.congress.models.Roll;
import com.sunlightlabs.congress.services.RollService;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class RollListFragment extends ListFragment implements PaginationListener.Paginates {
public static final int PER_PAGE = 20;
public static final int ROLLS_VOTER = 0;
public static final int ROLLS_RECENT = 1;
private List<Roll> rolls;
private Legislator voter;
private int type;
String query;
PaginationListener pager;
View loadingView;
public static RollListFragment forRecent() {
RollListFragment frag = new RollListFragment();
Bundle args = new Bundle();
args.putInt("type", ROLLS_RECENT);
frag.setArguments(args);
frag.setRetainInstance(true);
return frag;
}
public static RollListFragment forLegislator(Legislator legislator) {
RollListFragment frag = new RollListFragment();
Bundle args = new Bundle();
args.putInt("type", ROLLS_VOTER);
args.putSerializable("legislator", legislator);
frag.setArguments(args);
frag.setRetainInstance(true);
return frag;
}
public RollListFragment() {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
type = args.getInt("type", ROLLS_VOTER);
voter = (Legislator) args.getSerializable("legislator");
query = args.getString("query");
loadRolls();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.list_footer, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setupControls();
if (rolls != null)
displayRolls();
}
@Override
public void onResume() {
super.onResume();
if (rolls != null)
setupSubscription();
}
public void setupControls() {
((Button) getView().findViewById(R.id.refresh)).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
refresh();
}
});
loadingView = LayoutInflater.from(getActivity()).inflate(R.layout.loading_page, null);
loadingView.setVisibility(View.GONE);
getListView().addFooterView(loadingView);
pager = new PaginationListener(this);
getListView().setOnScrollListener(pager);
FragmentUtils.setLoading(this, R.string.votes_loading);
}
private void setupSubscription() {
Subscription subscription = null;
if (type == ROLLS_VOTER)
subscription = new Subscription(voter.bioguide_id, Subscriber.notificationName(voter), "RollsLegislatorSubscriber", voter.chamber);
else if (type == ROLLS_RECENT)
subscription = new Subscription("RecentVotes", "Recent Votes", "RollsRecentSubscriber", null);
if (subscription != null)
Footer.setup(this, subscription, rolls);
}
@Override
public void onListItemClick(ListView parent, View v, int position, long id) {
Roll roll = (Roll) parent.getItemAtPosition(position);
if (roll != null) // happened once somehow
startActivity(Utils.rollIntent(getActivity(), roll));
}
private void refresh() {
rolls = null;
FragmentUtils.setLoading(this, R.string.votes_loading);
FragmentUtils.showLoading(this);
loadRolls();
}
@Override
public void loadNextPage(int page) {
getListView().setOnScrollListener(null);
loadingView.setVisibility(View.VISIBLE);
new LoadRollsTask(this, page).execute();
}
public void loadRolls() {
new LoadRollsTask(this, 1).execute();
}
public void onLoadRolls(List<Roll> rolls, int page) {
if (!isAdded())
return;
if (page == 1) {
this.rolls= rolls;
displayRolls();
} else {
this.rolls.addAll(rolls);
loadingView.setVisibility(View.GONE);
((RollAdapter) getListAdapter()).notifyDataSetChanged();
}
// only re-enable the pagination if we got a full page back
if (rolls.size() == PER_PAGE)
getListView().setOnScrollListener(pager);
}
public void onLoadRolls(CongressException exception) {
if (isAdded())
FragmentUtils.showRefresh(this, R.string.votes_error);
}
public void displayRolls() {
if (rolls.size() > 0) {
setListAdapter(new RollAdapter(this, rolls));
setupSubscription();
} else {
if (type == ROLLS_VOTER) {
FragmentUtils.showEmpty(this, R.string.votes_empty_voter);
setupSubscription();
} else // ROLLS_RECENT
FragmentUtils.showRefresh(this, R.string.votes_error); // should not happen
}
}
private class LoadRollsTask extends AsyncTask<Void,Void,List<Roll>> {
private RollListFragment context;
private CongressException exception;
int page;
public LoadRollsTask(RollListFragment context, int page) {
this.context = context;
this.page = page;
FragmentUtils.setupAPI(context);
}
@Override
public List<Roll> doInBackground(Void... nothing) {
try {
Map<String,String> params = new HashMap<String,String>();
switch (context.type) {
case ROLLS_VOTER:
return RollService.latestVotes(context.voter.bioguide_id, context.voter.chamber, page, PER_PAGE);
case ROLLS_RECENT:
return RollService.latestVotes(page, PER_PAGE);
default:
throw new CongressException("Not sure what type of votes to find.");
}
} catch(CongressException exception) {
this.exception = exception;
return null;
}
}
@Override
public void onPostExecute(List<Roll> rolls) {
if (exception != null)
context.onLoadRolls(exception);
else
context.onLoadRolls(rolls, page);
}
}
private static class RollAdapter extends ArrayAdapter<Roll> {
private LayoutInflater inflater;
private RollListFragment context;
public RollAdapter(RollListFragment context, List<Roll> rolls) {
super(context.getActivity(), 0, rolls);
this.inflater = LayoutInflater.from(context.getActivity());
this.context = context;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
Roll roll = getItem(position);
ViewHolder holder;
if (view == null) {
view = inflater.inflate(R.layout.roll_item, null);
holder = new ViewHolder();
holder.roll = (TextView) view.findViewById(R.id.chamber_number);
holder.date = (TextView) view.findViewById(R.id.date);
holder.question = (TextView) view.findViewById(R.id.question);
holder.result = (TextView) view.findViewById(R.id.result);
holder.details = (ViewGroup) view.findViewById(R.id.details);
holder.detailsText = (TextView) view.findViewById(R.id.details_text);
view.setTag(holder);
} else
holder = (ViewHolder) view.getTag();
TextView msgView = holder.roll;
if (context.voter != null && (context.type == ROLLS_VOTER || context.type == ROLLS_RECENT)) {
Roll.Vote vote = roll.voter_ids.get(context.voter.bioguide_id);
if (vote == null || vote.vote.equals(Roll.NOT_VOTING))
msgView.setText("Did Not Vote");
else
msgView.setText(vote.vote);
} else
msgView.setText(Utils.capitalize(roll.chamber));
holder.roll = msgView;
shortDate(holder.date, roll.voted_at);
holder.question.setText(Utils.truncate(roll.question, 200));
holder.result.setText(resultFor(roll));
// vote views can use an optional 'details' pane for more info
if (roll.nomination != null && roll.nomination.nominees != null) {
holder.details.setVisibility(View.VISIBLE);
holder.detailsText.setText(Nomination.nomineesFor(roll.nomination));
} else if (roll.amendment != null && roll.amendment.amends_bill_id != null) {
holder.details.setVisibility(View.VISIBLE);
String text = "Amendment to " + Bill.formatCode(roll.amendment.amends_bill_id) + ": " + Amendment.description(roll.amendment);
holder.detailsText.setText(Utils.truncate(text, 300));
} else if (roll.bill != null) {
holder.details.setVisibility(View.VISIBLE);
holder.detailsText.setText(Bill.formatCode(roll.bill_id) + ": " + Bill.displayTitle(roll.bill));
}
return view;
}
static class ViewHolder {
TextView roll, date, question, result, detailsText;
ViewGroup details;
}
private String resultFor(Roll roll) {
String breakdown;
if (roll.otherVotes) {
breakdown = "";
Iterator<Integer> iter = roll.voteBreakdown.values().iterator();
while (iter.hasNext()) {
breakdown += iter.next();
if (iter.hasNext())
breakdown += "-";
}
} else {
breakdown = roll.voteBreakdown.get(Roll.YEA)+ "-" + roll.voteBreakdown.get(Roll.NAY);
if (roll.voteBreakdown.get(Roll.PRESENT) > 0)
breakdown += "-" + roll.voteBreakdown.get(Roll.PRESENT);
}
return roll.result + ", " + breakdown.toString();
}
private void shortDate(TextView view, Date date) {
if (date.getYear() == Calendar.getInstance().get(Calendar.YEAR)) {
view.setTextSize(18);
view.setText(new SimpleDateFormat("MMM d", Locale.US).format(date).toUpperCase(Locale.US));
} else
longDate(view, date);
}
private void longDate(TextView view, Date date) {
view.setTextSize(14);
view.setText(new SimpleDateFormat("MMM d, ''yy").format(date).toUpperCase());
}
}
}