package cgeo.geocaching.sorting;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v4.view.ActionProvider;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import cgeo.geocaching.R;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.TextUtils;
import cgeo.geocaching.utils.functions.Action1;
/**
* Provides a sub menu for sorting caches. Register your listener in the onCreateOptionsMenu of the containing activity.
*
*/
public class SortActionProvider extends ActionProvider implements OnMenuItemClickListener {
private static final int MENU_GROUP = 1;
private final Context context;
private final ArrayList<ComparatorEntry> registry = new ArrayList<>(20);
/**
* Callback triggered on selecting a new sort order.
*/
private Action1<CacheComparator> onClickListener;
/**
* Currently selected filter. Used for radio button indication.
*/
private CacheComparator selection;
// Used to change menu Filter label
private boolean isEventsOnly = false;
private static final class ComparatorEntry {
private final String name;
private final Class<? extends CacheComparator> cacheComparator;
ComparatorEntry(final String name, final Class<? extends CacheComparator> cacheComparator) {
this.name = name;
this.cacheComparator = cacheComparator;
}
@Override
public String toString() {
return name;
}
}
/**
* Creates a new instance. ActionProvider classes should always implement a
* constructor that takes a single Context parameter for inflating from menu XML.
*
* @param context
* Context for accessing resources.
*/
public SortActionProvider(final Context context) {
super(context);
this.context = context;
}
private void register(@StringRes final int resourceId, final Class<? extends CacheComparator> comparatorClass) {
registry.add(new ComparatorEntry(context.getString(resourceId), comparatorClass));
}
private void registerComparators() {
registry.clear();
register(R.string.caches_sort_distance, DistanceComparator.class);
if (isEventsOnly) {
register(R.string.caches_sort_eventdate, EventDateComparator.class);
} else {
register(R.string.caches_sort_date_hidden, DateComparator.class);
}
register(R.string.caches_sort_difficulty, DifficultyComparator.class);
register(R.string.caches_sort_finds, FindsComparator.class);
register(R.string.caches_sort_geocode, GeocodeComparator.class);
register(R.string.caches_sort_inventory, InventoryComparator.class);
register(R.string.caches_sort_name, NameComparator.class);
register(R.string.caches_sort_favorites, PopularityComparator.class);
register(R.string.caches_sort_favorites_ratio, PopularityRatioComparator.class);
register(R.string.caches_sort_rating, RatingComparator.class);
register(R.string.caches_sort_size, SizeComparator.class);
register(R.string.caches_sort_state, StateComparator.class);
register(R.string.caches_sort_storage, StorageTimeComparator.class);
register(R.string.caches_sort_terrain, TerrainComparator.class);
register(R.string.caches_sort_date_logged, VisitComparator.class);
register(R.string.caches_sort_vote, VoteComparator.class);
// sort the menu labels alphabetically for easier reading
Collections.sort(registry, new Comparator<ComparatorEntry>() {
@Override
public int compare(final ComparatorEntry lhs, final ComparatorEntry rhs) {
return TextUtils.COLLATOR.compare(lhs.name, rhs.name);
}
});
}
@Override
public View onCreateActionView() {
// must return null, otherwise onPrepareSubMenu is not called
return null;
}
@Override
public boolean hasSubMenu() {
return true;
}
@Override
public void onPrepareSubMenu(final SubMenu subMenu) {
subMenu.clear();
registerComparators();
for (int i = 0; i < registry.size(); i++) {
final ComparatorEntry comparatorEntry = registry.get(i);
final MenuItem menuItem = subMenu.add(MENU_GROUP, i, i, comparatorEntry.name);
menuItem.setOnMenuItemClickListener(this).setCheckable(true);
if (selection == null) {
if (comparatorEntry.cacheComparator == null) {
menuItem.setChecked(true);
}
} else if (selection.getClass().equals(comparatorEntry.cacheComparator)) {
menuItem.setChecked(true);
}
}
subMenu.setGroupCheckable(MENU_GROUP, true, true);
}
@Override
public boolean onMenuItemClick(final MenuItem item) {
callListener(registry.get(item.getItemId()).cacheComparator);
return true;
}
private void callListener(final Class<? extends CacheComparator> cacheComparator) {
try {
if (cacheComparator == null) {
onClickListener.call(null);
} else {
final CacheComparator comparator = cacheComparator.newInstance();
onClickListener.call(comparator);
}
} catch (Exception e) { // no multi-catch below SDK 19
Log.e("selectComparator", e);
}
}
public void setClickListener(@NonNull final Action1<CacheComparator> onClickListener) {
this.onClickListener = onClickListener;
}
public void setSelection(final CacheComparator selection) {
this.selection = selection;
}
public void setIsEventsOnly(final boolean isEventsOnly) {
this.isEventsOnly = isEventsOnly;
}
}