public class GitHubApiService extends IntentService {

    public static final String ACTION_GET_URI = "action_get_uri";

    public static final String ACTION_EVENTS_LIST_USER_PUBLIC = "action_events_list_user_public";

    public static final String ACTION_EVENTS_LIST_USER_RECEIVED = "action_events_list_user_received";

    public static final String ACTION_EVENTS_LIST_TIMELINE = "action_events_list_timeline";

    public static final String ACTION_ISSUES_LIST_SELF = "action_issues_list_self";

    public static final String ACTION_ORGS_LIST_MEMBERS = "action_orgs_list_members";

    public static final String ACTION_ORGS_SELF_MEMBERSHIPS = "action_orgs_self_memberships";

    public static final String ACTION_ORGS_USER_MEMBERSHIPS = "action_orgs_user_memberships";

    public static final String ACTION_REPOS_GET_REPO = "action_repos_get_repo";

    public static final String ACTION_REPOS_LIST_ORG_OWNED = "action_repos_list_org_owned";

    public static final String ACTION_REPOS_LIST_SELF_OWNED = "action_repos_list_self_owned";

    public static final String ACTION_REPOS_LIST_USER_OWNED = "action_repos_list_user_owned";

    public static final String ACTION_REPOS_LIST_USER_WATCHED = "action_repos_list_user_watched";

    public static final String ACTION_USERS_GET_USER = "action_users_get_user";

    public static final String ACTION_USERS_LIST_FOLLOWERS = "action_users_list_followers";

    public static final String ACTION_USERS_LIST_FOLLOWING = "action_users_list_following";

    public static final String ARG_ACCOUNT = "arg_account";

    public static final String ARG_ANONYMOUS = "arg_anonymous";

    public static final String ARG_BASIC_USERNAME = "arg_basic_username";

    public static final String ARG_BASIC_PASSWORD = "arg_basic_password";

    public static final String ARG_FORCE_REFRESH = "arg_force_refresh";

    public static final String ARG_OAUTH_TOKEN = "arg_oauth_token";

    public static final String ARG_START_PAGE = "arg_start_page";

    public static final String EXTRA_ERROR = "extra_error";

    public static final String EXTRA_HAS_NEXT = "extra_has_next";

    public static final String EXTRA_NEXT_PAGE = "extra_next_page";

    public static final String EXTRA_RESULT_JSON = "extra_result_json";

    public static final String PARAM_DIRECTION = "param_direction";

    public static final String PARAM_FILTER = "param_filter";

    public static final String PARAM_LABELS = "param_labels";

    public static final String PARAM_LOGIN = "param_login";

    public static final String PARAM_REPO_OWNER = "param_repo_owner";

    public static final String PARAM_REPO_NAME = "param_repo_name";

    public static final String PARAM_SINCE = "param_since";

    public static final String PARAM_SORT = "param_sort";

    public static final String PARAM_STATE = "param_state";

    public static final String USER_AGENT = "Hubroid/GitHubJava";

    private static String sApiHostname = HOST_API;

    private static int sApiPort = -1;

    private static String sApiScheme = PROTOCOL_HTTPS;

    private GitHubClient mGitHubClient;

    /**
     * Sets the Api hostname to connect to.
     *
     * Default is {@link IGitHubConstants#HOST_API}.
     */
    public static void setApiHostname(final String hostname) {
        sApiHostname = hostname;
    }

    /**
     * Sets the port to connect to the host with. Default is -1.
     */
    public static void setApiPort(final int port) {
        sApiPort = port;
    }

    /**
     * Sets the scheme to connect to the host with.
     *
     * Default is {@link IGitHubConstants#PROTOCOL_HTTPS}.
     */
    public static void setApiScheme(final String scheme) {
        sApiScheme = scheme;
    }

    public GitHubApiService() {
        super("GitHubApiService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent == null) {
            return;
        }

        mGitHubClient = new GitHubClient(sApiHostname, sApiPort, sApiScheme);
        mGitHubClient.setUserAgent(USER_AGENT);

        if (!intent.getBooleanExtra(ARG_ANONYMOUS, false)) {
            if (intent.hasExtra(ARG_OAUTH_TOKEN)) {
                mGitHubClient.setOAuth2Token(intent.getStringExtra(ARG_OAUTH_TOKEN));
            } else if (intent.hasExtra(ARG_BASIC_USERNAME) && intent.hasExtra(ARG_BASIC_PASSWORD)) {
                mGitHubClient.setCredentials(intent.getStringExtra(ARG_BASIC_USERNAME),
                        intent.getStringExtra(ARG_BASIC_PASSWORD));
            } else if (intent.hasExtra(ARG_ACCOUNT) &&
                    intent.getParcelableExtra(ARG_ACCOUNT) != null) {
                final Account account = intent.getParcelableExtra(ARG_ACCOUNT);
                try {
                    final String oauthToken =
                            new OAuthUserProvider().getOAuthResponse(this, account).access_token;
                    if (oauthToken != null) {
                        mGitHubClient.setOAuth2Token(oauthToken);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (AccountsException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                }
            }
        }

        if (intent.getAction().equals(ACTION_GET_URI)) {
            final GitHubRequest request = new GitHubRequest();
            request.setUri(intent.getData().toString());

            GitHubResponse response;
            try {
                response = mGitHubClient.get(request);
            } catch (IOException e) {
                response = null;
                e.printStackTrace();
            }

            final Intent resultIntent = new Intent(ACTION_GET_URI, intent.getData());
            if (response != null) {
                resultIntent.putExtra(EXTRA_HAS_NEXT, response.getNext() != null);
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(response.getBody()));
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_EVENTS_LIST_USER_PUBLIC)) {
            final EventService es = new EventService(mGitHubClient);
            ArrayList<Event> result = null;
            PageIterator<Event> iterator = null;
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);

            if (intent.hasExtra(PARAM_LOGIN)) {
                iterator = es.pageUserEvents(intent.getStringExtra(PARAM_LOGIN), true, startPage,
                        REQUEST_PAGE_SIZE);
            }

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<Event>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_EVENTS_LIST_USER_PUBLIC);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_EVENTS_LIST_USER_RECEIVED)) {
            final EventService es = new EventService(mGitHubClient);
            ArrayList<Event> result = null;
            PageIterator<Event> iterator = null;
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);

            if (intent.hasExtra(PARAM_LOGIN)) {
                iterator = es.pageUserReceivedEvents(intent.getStringExtra(PARAM_LOGIN), false,
                        startPage, REQUEST_PAGE_SIZE);
            }

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<Event>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_EVENTS_LIST_USER_RECEIVED);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_EVENTS_LIST_TIMELINE)) {
            final EventService es = new EventService(mGitHubClient);
            ArrayList<Event> result = null;
            PageIterator<Event> iterator;
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);

            iterator = es.pagePublicEvents(startPage, REQUEST_PAGE_SIZE);

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<Event>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_EVENTS_LIST_TIMELINE);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_ISSUES_LIST_SELF)) {
            final IssueService is = new IssueService(mGitHubClient);
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);
            ArrayList<RepositoryIssue> result = null;
            PageIterator<RepositoryIssue> iterator;
            HashMap<String, String> params = new HashMap<String, String>();

            if (intent.hasExtra(PARAM_FILTER)) {
                params.put("filter", intent.getStringExtra(PARAM_FILTER));
            }
            if (intent.hasExtra(PARAM_STATE)) {
                params.put("state", intent.getStringExtra(PARAM_STATE));
            }
            if (intent.hasExtra(PARAM_LABELS)) {
                params.put("labels", intent.getStringExtra(PARAM_LABELS));
            }
            if (intent.hasExtra(PARAM_SORT)) {
                params.put("sort", intent.getStringExtra(PARAM_SORT));
            }
            if (intent.hasExtra(PARAM_DIRECTION)) {
                params.put("direction", intent.getStringExtra(PARAM_DIRECTION));
            }
            if (intent.hasExtra(PARAM_SINCE)) {
                params.put("since", intent.getStringExtra(PARAM_SINCE));
            }

            iterator = is.pageIssues(params, startPage, REQUEST_PAGE_SIZE);

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<RepositoryIssue>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_ISSUES_LIST_SELF);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_ORGS_SELF_MEMBERSHIPS)) {
            final OrganizationService os = new OrganizationService(mGitHubClient);
            List<User> result;
            try {
                result = os.getOrganizations();
            } catch (IOException e) {
                result = null;
                e.printStackTrace();
            }

            final Intent resultIntent = new Intent(ACTION_ORGS_SELF_MEMBERSHIPS);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_REPOS_GET_REPO)) {
            final RepositoryService rs = new RepositoryService(mGitHubClient);
            Repository result;
            try {
                result = rs.getRepository(intent.getStringExtra(PARAM_REPO_OWNER),
                        intent.getStringExtra(PARAM_REPO_NAME));
            } catch (IOException e) {
                result = null;
                e.printStackTrace();
            }

            final Intent resultIntent = new Intent(ACTION_REPOS_GET_REPO);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_REPOS_LIST_ORG_OWNED)) {
            final RepositoryService rs = new RepositoryService(mGitHubClient);
            ArrayList<Repository> result = null;
            PageIterator<Repository> iterator;
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);

            iterator = rs.pageOrgRepositories(intent.getStringExtra(PARAM_LOGIN),
                    startPage, REQUEST_PAGE_SIZE);

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<Repository>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_REPOS_LIST_ORG_OWNED);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_REPOS_LIST_SELF_OWNED)) {
            final RepositoryService rs = new RepositoryService(mGitHubClient);
            ArrayList<Repository> result = null;
            PageIterator<Repository> iterator;
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);

            Map<String, String> filter = new HashMap<String, String>();
            filter.put("type", "owner");
            filter.put("sort", "pushed");

            iterator = rs.pageRepositories(filter, startPage, REQUEST_PAGE_SIZE);

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<Repository>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_REPOS_LIST_SELF_OWNED);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_REPOS_LIST_USER_OWNED)) {
            final RepositoryService rs = new RepositoryService(mGitHubClient);
            ArrayList<Repository> result = null;
            PageIterator<Repository> iterator;
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);

            iterator = rs.pageRepositories(intent.getStringExtra(PARAM_LOGIN),
                    startPage, REQUEST_PAGE_SIZE);

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<Repository>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_REPOS_LIST_USER_OWNED);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_REPOS_LIST_USER_WATCHED)) {
            final WatcherService ws = new WatcherService(mGitHubClient);
            ArrayList<Repository> result = null;
            PageIterator<Repository> iterator;
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);

            try {
                iterator = ws.pageWatched(intent.getStringExtra(PARAM_LOGIN),
                        startPage, REQUEST_PAGE_SIZE);
            } catch (IOException e) {
                iterator = null;
            }

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<Repository>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_REPOS_LIST_USER_WATCHED);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_USERS_GET_USER)) {
            final UserService us = new UserService(mGitHubClient);
            User result;
            try {
                result = us.getUser(intent.getStringExtra(PARAM_LOGIN));
            } catch (IOException e) {
                result = null;
                e.printStackTrace();
            }

            final Intent resultIntent = new Intent(ACTION_USERS_GET_USER);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_USERS_LIST_FOLLOWERS)) {
            final UserService us = new UserService(mGitHubClient);
            ArrayList<User> result = null;
            PageIterator<User> iterator;
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);

            iterator = us.pageFollowers(intent.getStringExtra(PARAM_LOGIN),
                    startPage, REQUEST_PAGE_SIZE);

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<User>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_USERS_LIST_FOLLOWERS);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        } else if (intent.getAction().equals(ACTION_USERS_LIST_FOLLOWING)) {
            final UserService us = new UserService(mGitHubClient);
            ArrayList<User> result = null;
            PageIterator<User> iterator;
            final int startPage = intent.getIntExtra(ARG_START_PAGE, 1);

            iterator = us.pageFollowing(intent.getStringExtra(PARAM_LOGIN),
                    startPage, REQUEST_PAGE_SIZE);

            if (iterator != null && iterator.hasNext()) {
                result = new ArrayList<User>();
                result.addAll(iterator.next());
            }

            final Intent resultIntent = new Intent(ACTION_USERS_LIST_FOLLOWING);
            if (result != null) {
                resultIntent.putExtra(EXTRA_RESULT_JSON, GsonUtils.toJson(result));
                resultIntent.putExtra(EXTRA_HAS_NEXT, iterator.hasNext());
                resultIntent.putExtra(EXTRA_NEXT_PAGE, iterator.getNextPage());
            } else {
                resultIntent.putExtra(EXTRA_ERROR, true);
            }
            sendBroadcast(resultIntent);
        }
    }
} public abstract class BaseListAdapter<T> extends BaseAdapter {

    protected LayoutInflater mInflater;

    private ArrayList<T> mData;

    private boolean mNotifyOnChange;

    private BaseActivity mContext;

    public BaseListAdapter(BaseActivity context) {
        super();

        mContext = context;
        mInflater = LayoutInflater.from(mContext);
        mData = new ArrayList<T>();
    }

    public BaseActivity getContext() {
        return mContext;
    }

    public void clear() {
        mData.clear();
        if (mNotifyOnChange) {
            notifyDataSetChanged();
        }
    }

    public ArrayList<T> getAll() {
        return mData;
    }

    public void addAll(Collection<? extends T> collection) {
        mData.addAll(collection);
        if (mNotifyOnChange) {
            notifyDataSetChanged();
        }
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    public T getItem(int position) {
        return mData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        if (observer != null) {
            super.unregisterDataSetObserver(observer);
        }
    }

    protected void fillWithItems(List<T> data, boolean append) {
        if (!append) {
            clear();
        }
        addAll(data);
    }

    public void fillWithItems(List<T> data) {
        fillWithItems(data, false);
    }

    public void appendWithItems(List<T> data) {
        fillWithItems(data, true);
    }

    public void setNotifyOnChange(boolean notifyOnChange) {
        mNotifyOnChange = notifyOnChange;
    }
} public class RepositoryListAdapter extends BaseListAdapter<Repository> {

    public static class ViewHolder {

        TextView owner;

        TextView name;

        TextView description;

        TextView forks;

        TextView stars;
    }

    public RepositoryListAdapter(BaseActivity context) {
        super(context);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.repository_list_item, null);
            holder = new ViewHolder();

            holder.owner = (TextView) convertView.findViewById(R.id.tv_repository_owner);
            holder.name = (TextView) convertView.findViewById(R.id.tv_repository_name);
            holder.description =
                    (TextView) convertView.findViewById(R.id.tv_repository_description);
            holder.forks = (TextView) convertView.findViewById(R.id.tv_repository_forks);
            holder.stars = (TextView) convertView.findViewById(R.id.tv_repository_stars);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        final Repository r = getItem(position);

        holder.owner.setText(r.getOwner().getLogin());
        holder.name.setText(r.getName());
        holder.description.setText(r.getDescription());
        holder.forks.setText(Integer.toString(r.getForks()));
        holder.stars.setText(Integer.toString(r.getWatchers()));

        return convertView;
    }
} public abstract class PagedListFragment<T> extends BaseListFragment<T>
        implements AbsListView.OnScrollListener {

    private static final String EXTRA_LIST_ITEMS = "extra_list_items";

    private boolean mHasNext = true;

    private boolean mLoadingMore;

    private int mNextPage = 1;

    private BroadcastReceiver mBroadcastReceiver;

    private TypeToken<List<T>> mListTypeToken;

    private View mLoadingIndicator;

    private boolean mShowingLoadingIndicator;

    protected abstract class PagedListBroadcastReceiver extends BroadcastReceiver {

        public abstract List<T> handleReceive(Context context, Intent intent, List<T> items);

        @Override
        public void onReceive(Context context, Intent intent) {
            if (context == null || intent == null) {
                return;
            }

            /*
             * Return if we didn't receive the broadcast we asked for.
             */
            if (!onCreateServiceIntent().getAction().equals(intent.getAction())) {
                return;
            }

            if (intent.getBooleanExtra(EXTRA_ERROR, false)) {
                getBaseActivity().popShortToast("An error occurred.");
            } else {
                final ArrayList<T> listItems = new ArrayList<T>();
                final String resultJson = intent.getStringExtra(EXTRA_RESULT_JSON);
                List<T> fetchedItems = null;
                if (resultJson != null) {
                    fetchedItems = GsonUtils.fromJson(resultJson, mListTypeToken.getType());
                }

                fetchedItems = handleReceive(context, intent, fetchedItems);

                if (fetchedItems != null) {
                    listItems.addAll(fetchedItems);
                }

                if (!mLoadingMore) {
                    getWrappedListAdapter().fillWithItems(listItems);
                } else {
                    getWrappedListAdapter().appendWithItems(listItems);
                }

                mHasNext = intent.getBooleanExtra(EXTRA_HAS_NEXT, false);
                mNextPage = intent.getIntExtra(EXTRA_NEXT_PAGE, -1);

                setLoadingIndicatorVisible(mHasNext);
                getListView().setOnScrollListener((mHasNext) ? PagedListFragment.this : null);

                getWrappedListAdapter().notifyDataSetChanged();
            }

            setListShown(true);

            mLoadingMore = false;
        }
    }

    public abstract PagedListBroadcastReceiver onCreateBroadcastReceiver();

    public abstract IntentFilter onCreateIntentFilter();

    public abstract Intent onCreateServiceIntent();

    public void startLoading(final boolean forceRefresh) {
        if (mLoadingMore && !forceRefresh) {
            return;
        }
        final Intent startServiceIntent = onCreateServiceIntent();
        if (startServiceIntent != null) {
            startServiceIntent.putExtra(ARG_START_PAGE, mNextPage);
            getBaseActivity().startService(startServiceIntent);
        }
    }

    public void setLoadingIndicatorVisible(final boolean show) {
        if (mShowingLoadingIndicator != show && getListAdapter() != null) {
            if (show) {
                getListAdapter().addFooter(mLoadingIndicator, null, false);
            } else {
                getListAdapter().removeFooter(mLoadingIndicator);
            }
        }
        mShowingLoadingIndicator = show;
    }

    public PagedListFragment(final TypeToken<List<T>> listTypeToken) {
        mListTypeToken = listTypeToken;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        /* Grab the loading indicator layout during view creation */
        mLoadingIndicator = inflater.inflate(R.layout.loading_indicator, null, false);

        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mBroadcastReceiver = onCreateBroadcastReceiver();
        if (mBroadcastReceiver != null) {
            final IntentFilter filter = onCreateIntentFilter();
            if (filter != null) {
                getBaseActivity().registerReceiver(mBroadcastReceiver, filter);
            }
        }

        if (savedInstanceState == null) {
            if (getWrappedListAdapter() != null && getWrappedListAdapter().isEmpty()) {
                setListShown(false);
                startLoading(false);
            }
        } else {
            mHasNext = savedInstanceState.getBoolean(EXTRA_HAS_NEXT, true);
            mNextPage = savedInstanceState.getInt(EXTRA_NEXT_PAGE, -1);

            final String itemsJson = savedInstanceState.getString(EXTRA_LIST_ITEMS);
            if (itemsJson != null) {
                final List<T> items = GsonUtils.fromJson(itemsJson, mListTypeToken.getType());

                getWrappedListAdapter().fillWithItems(items);
                getWrappedListAdapter().notifyDataSetChanged();

                setLoadingIndicatorVisible(mNextPage > 0 && mHasNext);
                getListView().setOnScrollListener((mNextPage > 0 && mHasNext) ? this : null);

                setListShown(true);
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        if (mBroadcastReceiver != null) {
            try {
                getBaseActivity().unregisterReceiver(mBroadcastReceiver);
            } catch (IllegalArgumentException e) {
                /* Ignore this. */
            }
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView absListView, int i) {        /* stub */
    }

    @Override
    public void onScroll(AbsListView absListView, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
		/*
		 * We want to bail out on the following cases:
		 *  - There are no more pages in the iterator to load
		 *  - We're already trying to load more items
		 * Otherwise, we trigger the load of the next page and
		 * display its results in the list.
		 */
        if (mNextPage < 0 || !mHasNext) {
            return;
        }
        if (mLoadingMore) {
            return;
        }
        if (getListView().getLastVisiblePosition() + 1 >= getListAdapter().getCount()) {
            Log.d("hubroid", ">> onScroll() -> Going to load more!");
            startLoading(false);
            mLoadingMore = true;
        }
    }


    @Override
    public void onCreateActionBar(ActionBar bar, Menu menu, MenuInflater inflater) {
        super.onCreateActionBar(bar, menu, inflater);

        menu.findItem(R.id.actionbar_action_refresh).setVisible(true);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.actionbar_action_refresh) {
            setListShown(false);
            getListView().setOnScrollListener(this);
            mHasNext = true;
            mNextPage = 1;
            startLoading(true);
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putBoolean(EXTRA_HAS_NEXT, mHasNext);

        outState.putInt(EXTRA_HAS_NEXT, mNextPage);

        if (getWrappedListAdapter() != null && getWrappedListAdapter().getAll() != null) {
            final ArrayList<T> items = getWrappedListAdapter().getAll();
            outState.putString(EXTRA_LIST_ITEMS, GsonUtils.toJson(items));
        }
    }
} public final static String ARG_TARGET_REPO = "target_repo"; public static final String ACTION_REPOS_LIST_ORG_OWNED = "action_repos_list_org_owned"; public static final String ACTION_REPOS_LIST_SELF_OWNED = "action_repos_list_self_owned"; public static final String ACTION_REPOS_LIST_USER_OWNED = "action_repos_list_user_owned"; public static final String ACTION_REPOS_LIST_USER_WATCHED = "action_repos_list_user_watched"; public static final String ARG_ACCOUNT = "arg_account"; public static final String PARAM_LOGIN = "param_login";
import com.google.gson.reflect.TypeToken;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import net.idlesoft.android.apps.github.R;
import net.idlesoft.android.apps.github.services.GitHubApiService;
import net.idlesoft.android.apps.github.ui.adapters.BaseListAdapter;
import net.idlesoft.android.apps.github.ui.adapters.RepositoryListAdapter;
import net.idlesoft.android.apps.github.ui.fragments.PagedListFragment;
import org.eclipse.egit.github.core.Repository;
import org.eclipse.egit.github.core.client.GsonUtils;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static net.idlesoft.android.apps.github.HubroidConstants.ARG_TARGET_REPO;
import static net.idlesoft.android.apps.github.services.GitHubApiService.ACTION_REPOS_LIST_ORG_OWNED;
import static net.idlesoft.android.apps.github.services.GitHubApiService.ACTION_REPOS_LIST_SELF_OWNED;
import static net.idlesoft.android.apps.github.services.GitHubApiService.ACTION_REPOS_LIST_USER_OWNED;
import static net.idlesoft.android.apps.github.services.GitHubApiService.ACTION_REPOS_LIST_USER_WATCHED;
import static net.idlesoft.android.apps.github.services.GitHubApiService.ARG_ACCOUNT;
import static net.idlesoft.android.apps.github.services.GitHubApiService.PARAM_LOGIN;
/*
 * Copyright (c) 2012 Eddie Ringle
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this list of conditions
 * and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
 * and the following disclaimer in the documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package net.idlesoft.android.apps.github.ui.fragments.app;








public class RepositoryListFragment extends PagedListFragment<Repository> {

    public static final int LIST_USER = 1;

    public static final int LIST_STARRED = 2;

    public static final String ARG_LIST_TYPE = "list_type";

    private int mListType;

    public RepositoryListFragment() {
        super(new TypeToken<List<Repository>>() {
        });
    }

    @Override
    public PagedListBroadcastReceiver onCreateBroadcastReceiver() {
        return new PagedListBroadcastReceiver() {
            @Override
            public List<Repository> handleReceive(Context context, Intent intent,
                    List<Repository> items) {
                if (items == null) {
                    return null;
                }

                ArrayList<Repository> processed = new ArrayList<Repository>();

                if (intent.getAction().equals(ACTION_REPOS_LIST_USER_WATCHED)) {
                    /*
                     * In the case of a list of repositories a user is watching, we want to strip
                     * out all repositories belonging to the current context.
                     */
                    for (Repository repo : items) {
                        if (repo == null || repo.getOwner() == null) {
                            continue;
                        }
                        if (repo.getOwner().getLogin().equals(
                                getBaseActivity().getCurrentContextLogin())) {
                            continue;
                        }
                        processed.add(repo);
                    }
                    return processed;
                } else {
                    return items;
                }
            }
        };
    }

    @Override
    public IntentFilter onCreateIntentFilter() {
        final IntentFilter filter = new IntentFilter();

        /*
         * Make sure we only receive what we might actually want.
         */
        switch (mListType) {
            case LIST_USER:
                filter.addAction(ACTION_REPOS_LIST_ORG_OWNED);
                filter.addAction(ACTION_REPOS_LIST_SELF_OWNED);
                filter.addAction(ACTION_REPOS_LIST_USER_OWNED);
                break;
            case LIST_STARRED:
                filter.addAction(ACTION_REPOS_LIST_USER_WATCHED);
                break;
        }

        return filter;
    }

    @Override
    public Intent onCreateServiceIntent() {
        final Intent getRepositoriesIntent = new Intent(getBaseActivity(), GitHubApiService.class);
        getRepositoriesIntent.putExtra(ARG_ACCOUNT, getBaseActivity().getCurrentUserAccount());

        switch (mListType) {
            case LIST_USER:
                if (!getTargetUser().getLogin().equals(
                        getBaseActivity().getCurrentContextLogin())) {
                    getRepositoriesIntent.setAction(ACTION_REPOS_LIST_USER_OWNED);
                    getRepositoriesIntent.putExtra(PARAM_LOGIN, getTargetUser().getLogin());
                } else {
                    final Map<String, String> filter = new HashMap<String, String>();
                    if (getTargetUser().getLogin().equals(
                            getBaseActivity().getCurrentUserLogin())) {
                        getRepositoriesIntent.setAction(ACTION_REPOS_LIST_SELF_OWNED);
                    } else {
                        getRepositoriesIntent.setAction(ACTION_REPOS_LIST_ORG_OWNED);
                        getRepositoriesIntent.putExtra(PARAM_LOGIN, getTargetUser().getLogin());
                    }
                }
                break;
            case LIST_STARRED:
                getRepositoriesIntent.setAction(ACTION_REPOS_LIST_USER_WATCHED);
                getRepositoriesIntent.putExtra(PARAM_LOGIN, getTargetUser().getLogin());
                break;
        }

        return getRepositoriesIntent;
    }

    @Override
    public BaseListAdapter<Repository> onCreateListAdapter() {
        return new RepositoryListAdapter(getBaseActivity());
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final Bundle args = getArguments();
        if (args != null) {
            mListType = args.getInt(ARG_LIST_TYPE, LIST_USER);
        }
    }

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
        /*
         * Send the user off to the Repository activity
         */
        final Repository target = getListAdapter().getWrappedAdapter().getItem(position);
        final Bundle args = new Bundle();
        args.putString(ARG_TARGET_REPO, GsonUtils.toJson(target));