/*
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.catnut.support.app;

import android.app.ListFragment;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

/**
 * Subclass of {@link android.support.v4.app.ListFragment} which provides automatic support for
 * providing the 'swipe-to-refresh' UX gesture by wrapping the the content view in a
 * {@link android.support.v4.widget.SwipeRefreshLayout}.
 */
public class SwipeRefreshListFragment extends ListFragment {
	private SwipeRefreshLayout mSwipeRefreshLayout;

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
							 Bundle savedInstanceState) {

		// Create the list fragment's content view by calling the super method
		final View listFragmentView = super.onCreateView(inflater, container, savedInstanceState);

		// Now create a SwipeRefreshLayout to wrap the fragment's content view
		mSwipeRefreshLayout = new ListFragmentSwipeRefreshLayout(container.getContext());

		// Add the list fragment's content view to the SwipeRefreshLayout, making sure that it fills
		// the SwipeRefreshLayout
		mSwipeRefreshLayout.addView(listFragmentView,
				ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

		// Make sure that the SwipeRefreshLayout will fill the fragment
		mSwipeRefreshLayout.setLayoutParams(
				new ViewGroup.LayoutParams(
						ViewGroup.LayoutParams.MATCH_PARENT,
						ViewGroup.LayoutParams.MATCH_PARENT));

		// Now return the SwipeRefreshLayout as this fragment's content view
		return mSwipeRefreshLayout;
	}

	/**
	 * Set the {@link android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener} to listen for
	 * initiated refreshes.
	 *
	 * @see android.support.v4.widget.SwipeRefreshLayout#setOnRefreshListener(android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener)
	 */
	public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener) {
		mSwipeRefreshLayout.setOnRefreshListener(listener);
	}

	/**
	 * Returns whether the {@link android.support.v4.widget.SwipeRefreshLayout} is currently
	 * refreshing or not.
	 *
	 * @see android.support.v4.widget.SwipeRefreshLayout#isRefreshing()
	 */
	public boolean isRefreshing() {
		return mSwipeRefreshLayout.isRefreshing();
	}

	/**
	 * Set whether the {@link android.support.v4.widget.SwipeRefreshLayout} should be displaying
	 * that it is refreshing or not.
	 *
	 * @see android.support.v4.widget.SwipeRefreshLayout#setRefreshing(boolean)
	 */
	public void setRefreshing(boolean refreshing) {
		mSwipeRefreshLayout.setRefreshing(refreshing);
	}

	/**
	 * Set the color scheme for the {@link android.support.v4.widget.SwipeRefreshLayout}.
	 *
	 * @see android.support.v4.widget.SwipeRefreshLayout#setColorScheme(int, int, int, int)
	 */
	public void setColorScheme(int colorRes1, int colorRes2, int colorRes3, int colorRes4) {
		mSwipeRefreshLayout.setColorScheme(colorRes1, colorRes2, colorRes3, colorRes4);
	}

	/**
	 * @return the fragment's {@link android.support.v4.widget.SwipeRefreshLayout} widget.
	 */
	public SwipeRefreshLayout getSwipeRefreshLayout() {
		return mSwipeRefreshLayout;
	}

	/**
	 * Sub-class of {@link android.support.v4.widget.SwipeRefreshLayout} for use in this
	 * {@link android.support.v4.app.ListFragment}. The reason that this is needed is because
	 * {@link android.support.v4.widget.SwipeRefreshLayout} only supports a single child, which it
	 * expects to be the one which triggers refreshes. In our case the layout's child is the content
	 * view returned from
	 * {@link android.support.v4.app.ListFragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)}
	 * which is a {@link android.view.ViewGroup}.
	 *
	 * <p>To enable 'swipe-to-refresh' support via the {@link android.widget.ListView} we need to
	 * override the default behavior and properly signal when a gesture is possible. This is done by
	 * overriding {@link #canChildScrollUp()}.
	 */
	private class ListFragmentSwipeRefreshLayout extends SwipeRefreshLayout {

		public ListFragmentSwipeRefreshLayout(Context context) {
			super(context);
		}

		/**
		 * As mentioned above, we need to override this method to properly signal when a
		 * 'swipe-to-refresh' is possible.
		 *
		 * @return true if the {@link android.widget.ListView} is visible and can scroll up.
		 */
		@Override
		public boolean canChildScrollUp() {
			final ListView listView = getListView();
			if (listView.getVisibility() == View.VISIBLE) {
				return canListViewScrollUp(listView);
			} else {
				return false;
			}
		}

	}

	/**
	 * Utility method to check whether a {@link ListView} can scroll up from it's current position.
	 * Handles platform version differences, providing backwards compatible functionality where
	 * needed.
	 */
	private static boolean canListViewScrollUp(ListView listView) {
		if (android.os.Build.VERSION.SDK_INT >= 14) {
			// For ICS and above we can call canScrollVertically() to determine this
			return ViewCompat.canScrollVertically(listView, -1);
		} else {
			// Pre-ICS we need to manually check the first visible item and the child view's top
			// value
			return listView.getChildCount() > 0 &&
					(listView.getFirstVisiblePosition() > 0
							|| listView.getChildAt(0).getTop() < listView.getPaddingTop());
		}
	}
}