/**
* Copyright (C) 2013 Romain Guefveneu.
*
* This file is part of naonedbus.
*
* Naonedbus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Naonedbus is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.naonedbus.fragment;
import java.util.Comparator;
import java.util.List;
import net.naonedbus.NBApplication;
import net.naonedbus.R;
import net.naonedbus.activity.impl.MapActivity;
import net.naonedbus.bean.Equipement;
import net.naonedbus.bean.async.AsyncResult;
import net.naonedbus.comparator.EquipementComparator;
import net.naonedbus.comparator.EquipementDistanceComparator;
import net.naonedbus.fragment.impl.MapFragment;
import net.naonedbus.helper.StateHelper;
import net.naonedbus.manager.impl.EquipementManager;
import net.naonedbus.manager.impl.EquipementManager.SousType;
import net.naonedbus.provider.impl.NaoLocationManager;
import net.naonedbus.provider.impl.NaoLocationManager.NaoLocationListener;
import net.naonedbus.widget.adapter.impl.EquipementArrayAdapter;
import net.naonedbus.widget.indexer.ArraySectionIndexer;
import net.naonedbus.widget.indexer.impl.EquipementDistanceIndexer;
import net.naonedbus.widget.indexer.impl.EquipementNomIndexer;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.View;
import android.widget.ListAdapter;
import android.widget.ListView;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
public abstract class EquipementFragment extends CustomListFragment {
private final static int SORT_NOM = 0;
private final static int SORT_DISTANCE = 1;
private final static SparseIntArray MENU_MAPPING = new SparseIntArray();
static {
MENU_MAPPING.append(SORT_NOM, R.id.menu_sort_name);
MENU_MAPPING.append(SORT_DISTANCE, R.id.menu_sort_distance);
}
private static int COUNT = 0;
protected final SparseArray<Comparator<Equipement>> comparators;
protected final SparseArray<ArraySectionIndexer<Equipement>> indexers;
protected NaoLocationManager myLocationProvider;
protected int currentSortPreference = SORT_NOM;
private StateHelper mStateHelper;
private DistanceTask mLoaderDistance;
private final Equipement.Type mType;
private SousType mSousType;
protected int localCount = -1;
public EquipementFragment(final int layoutId, final Equipement.Type type) {
super(layoutId);
mType = type;
myLocationProvider = NBApplication.getLocationProvider();
indexers = new SparseArray<ArraySectionIndexer<Equipement>>();
indexers.append(SORT_NOM, new EquipementNomIndexer());
indexers.append(SORT_DISTANCE, new EquipementDistanceIndexer());
comparators = new SparseArray<Comparator<Equipement>>();
comparators.append(SORT_NOM, new EquipementComparator<Equipement>());
comparators.append(SORT_DISTANCE, new EquipementDistanceComparator<Equipement>());
localCount = COUNT++;
}
public EquipementFragment(final int layoutId, final Equipement.Type type, final SousType sousType) {
this(layoutId, type);
mSousType = sousType;
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
myLocationProvider.addListener(locationListener);
// Initaliser le comparator avec la position actuelle.
locationListener.onLocationChanged(myLocationProvider.getLastLocation());
// Gestion du tri par défaut
mStateHelper = new StateHelper(getActivity());
currentSortPreference = mStateHelper.getSortType(this, SORT_NOM);
}
@Override
public void onStart() {
super.onStart();
loadContent();
}
@Override
public void onPause() {
mStateHelper.setSortType(this, currentSortPreference);
super.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
myLocationProvider.removeListener(locationListener);
}
@Override
public void onListItemClick(final ListView l, final View v, final int position, final long id) {
final Equipement equipement = (Equipement) getListAdapter().getItem(position);
final Intent intent = new Intent(getActivity(), MapActivity.class);
intent.putExtra(MapFragment.PARAM_ITEM_ID, equipement.getId());
intent.putExtra(MapFragment.PARAM_ITEM_TYPE, equipement.getType().getId());
startActivity(intent);
}
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.fragment_equipements, menu);
menu.findItem(MENU_MAPPING.get(currentSortPreference)).setChecked(true);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
item.setChecked(true);
switch (item.getItemId()) {
case R.id.menu_sort_name:
currentSortPreference = SORT_NOM;
sort();
return true;
case R.id.menu_sort_distance:
currentSortPreference = SORT_DISTANCE;
sort();
return true;
default:
return false;
}
}
/**
* Actualiser les informations de distance.
*/
private void refreshDistance() {
if (myLocationProvider.isEnabled() && getListAdapter() != null
&& (mLoaderDistance == null || mLoaderDistance.getStatus() == AsyncTask.Status.FINISHED)) {
mLoaderDistance = (DistanceTask) new DistanceTask().execute();
}
}
@Override
protected AsyncResult<ListAdapter> loadContent(final Context context, final Bundle bundle) {
final AsyncResult<ListAdapter> result = new AsyncResult<ListAdapter>();
try {
final EquipementManager equipementManager = EquipementManager.getInstance();
final List<Equipement> equipements;
if (mSousType == null) {
equipements = equipementManager.getEquipementsByType(context.getContentResolver(), mType);
} else {
equipements = equipementManager.getEquipementsByType(context.getContentResolver(), mType, mSousType);
}
setDistances(equipements);
final EquipementArrayAdapter adapter = new EquipementArrayAdapter(context, equipements);
adapter.setIndexer(indexers.get(currentSortPreference));
adapter.sort(comparators.get(currentSortPreference));
result.setResult(adapter);
} catch (final Exception e) {
result.setException(e);
}
return result;
}
protected void setDistances(final List<Equipement> equipements) {
final Location location = new Location(LocationManager.GPS_PROVIDER);
final Location currentLocation = myLocationProvider.getLastLocation();
if (currentLocation != null) {
for (final Equipement item : equipements) {
final double latitude = item.getLatitude();
final double longitude = item.getLongitude();
if (latitude != 0) {
location.setLatitude(latitude);
location.setLongitude(longitude);
item.setDistance(currentLocation.distanceTo(location));
}
}
}
}
/**
* Classe de calcul de la distance des équipements.
*
* @author romain
*/
private class DistanceTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(final Void... params) {
final ListAdapter adapter = getListAdapter();
final Location equipementLocation = new Location(LocationManager.GPS_PROVIDER);
final Location currentLocation = myLocationProvider.getLastLocation();
if (currentLocation != null) {
for (int i = 0; i < adapter.getCount(); i++) {
final Equipement item = (Equipement) adapter.getItem(i);
final double latitude = item.getLatitude();
final double longitude = item.getLongitude();
if (latitude != 0) {
equipementLocation.setLatitude(latitude);
equipementLocation.setLongitude(longitude);
item.setDistance(currentLocation.distanceTo(equipementLocation));
}
}
}
return null;
}
@Override
protected void onPostExecute(final Void result) {
final EquipementArrayAdapter adapter = (EquipementArrayAdapter) getListAdapter();
adapter.notifyDataSetChanged();
}
}
/**
* Listener de changement de coordonnées GPS
*/
private final NaoLocationListener locationListener = new NaoLocationListener() {
@Override
public void onLocationChanged(final Location location) {
final EquipementDistanceComparator<Equipement> comparator = (EquipementDistanceComparator<Equipement>) comparators
.get(SORT_DISTANCE);
comparator.setReferentiel(location);
if (currentSortPreference == SORT_DISTANCE) {
refreshDistance();
}
}
@Override
public void onDisconnected() {
final EquipementDistanceComparator<Equipement> comparator = (EquipementDistanceComparator<Equipement>) comparators
.get(SORT_DISTANCE);
comparator.setReferentiel(null);
if (currentSortPreference == SORT_DISTANCE) {
currentSortPreference = SORT_NOM;
sort();
}
}
@Override
public void onConnecting() {
}
@Override
public void onLocationTimeout() {
}
};
/**
* Trier les équipements selon les préférences.
*/
private void sort() {
final EquipementArrayAdapter adapter = (EquipementArrayAdapter) getListAdapter();
setIndexerAndComparator(adapter);
adapter.notifyDataSetChanged();
}
/**
* Définir l'indexer et comparator en fonction de
* {@link #currentSortPreference}.
*
* @param adapter
*/
private void setIndexerAndComparator(final EquipementArrayAdapter adapter) {
final Comparator<Equipement> comparator;
final ArraySectionIndexer<Equipement> indexer;
if (currentSortPreference == SORT_DISTANCE && !myLocationProvider.isEnabled()) {
// Tri par défaut si pas le localisation
comparator = comparators.get(SORT_NOM);
indexer = indexers.get(SORT_NOM);
} else {
comparator = comparators.get(currentSortPreference);
indexer = indexers.get(currentSortPreference);
}
adapter.sort(comparator);
adapter.setIndexer(indexer);
}
/**
* Ajouter un comparator.
*
* @param key
* @param comparator
*/
protected void addComparator(final int key, final Comparator<Equipement> comparator) {
comparators.put(key, comparator);
}
/**
* Ajouter un indexer.
*
* @param key
* @param indexer
*/
protected void addIndexer(final int key, final ArraySectionIndexer<Equipement> indexer) {
indexers.put(key, indexer);
}
}