/*
This file is part of RateBeer For Android.
RateBeer for Android 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.
RateBeer for Android 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 RateBeer for Android. If not, see
<http://www.gnu.org/licenses/>.
*/
package com.ratebeer.android.gui.fragments;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.googlecode.androidannotations.annotations.AfterViews;
import com.googlecode.androidannotations.annotations.EFragment;
import com.googlecode.androidannotations.annotations.InstanceState;
import com.googlecode.androidannotations.annotations.OptionsItem;
import com.googlecode.androidannotations.annotations.OptionsMenu;
import com.googlecode.androidannotations.annotations.ViewById;
import com.ratebeer.android.R;
import com.ratebeer.android.api.ApiMethod;
import com.ratebeer.android.api.CommandFailureResult;
import com.ratebeer.android.api.CommandSuccessResult;
import com.ratebeer.android.api.command.GetPlacesAroundCommand;
import com.ratebeer.android.api.command.GetPlacesAroundCommand.Place;
import com.ratebeer.android.app.location.LocationUtils;
import com.ratebeer.android.app.location.MyLocation;
import com.ratebeer.android.app.location.MyLocation.LocationResult;
import com.ratebeer.android.app.location.TouchableMapViewPager;
import com.ratebeer.android.gui.components.RateBeerActivity;
import com.ratebeer.android.gui.components.RateBeerMapFragment;
import com.ratebeer.android.gui.components.SelectLocationDialog;
import com.ratebeer.android.gui.components.SelectLocationDialog.OnLocationSelectedListener;
import com.ratebeer.android.gui.components.helpers.ArrayAdapter;
import com.viewpagerindicator.TabPageIndicator;
@EFragment(R.layout.fragment_places)
@OptionsMenu(R.menu.places)
public class PlacesFragment extends RateBeerMapFragment implements OnLocationSelectedListener {
private static final int DEFAULT_RADIUS = 25;
private static final String GEOCODER_PROVIDER = "geocoder";
@InstanceState
protected ArrayList<Place> places = null;
@InstanceState
protected Location lastLocation = null;
@ViewById
protected TouchableMapViewPager pager;
@ViewById
protected TabPageIndicator titles;
private ListView placesView;
private Map<String, Place> markersMap = new HashMap<String, GetPlacesAroundCommand.Place>();
public PlacesFragment() {
}
@AfterViews
public void init() {
pager.setAdapter(new PlacesPagerAdapter());
titles.setViewPager(pager);
titles.setOnPageChangeListener(pager.getOnPageChangeListener());
if (places != null) {
publishResults(places);
}
// Retrieve already with a (old) stored location
lastLocation = getSettings().getLastUserLocation();
if (lastLocation != null) {
execute(new GetPlacesAroundCommand(getUser(), DEFAULT_RADIUS,
lastLocation.getLatitude(), lastLocation.getLongitude()));
}
// Always trigger a location update as well
refreshPlaces();
}
@OptionsItem(R.id.menu_location)
protected void onSelectNewLocation() {
new SelectLocationDialog(this).show(getFragmentManager(), "SelectLocationDialog");
}
// Implements OnLocationSelectedListener
@Override
public void onStartLocationSearch(String query) {
// Try to find a location for the user query, using a Geocoder
try {
List<Address> point = new Geocoder(getActivity()).getFromLocationName(query, 1);
if (point.size() <= 0) {
// Cannot find address: give an error
publishException(null, getString(R.string.error_nolocation));
} else {
// Found a location! Now look for places
lastLocation = new Location(GEOCODER_PROVIDER);
lastLocation.setLongitude(point.get(0).getLongitude());
lastLocation.setLatitude(point.get(0).getLatitude());
execute(new GetPlacesAroundCommand(getUser(), DEFAULT_RADIUS, lastLocation.getLatitude(),
lastLocation.getLongitude()));
}
} catch (IOException e) {
// Can't connect to Geocoder server: give an error
publishException(null, getString(R.string.error_nolocation));
}
}
// Implements OnLocationSelectedListener
@Override
public void onUseCurrentLocation() {
refreshPlaces();
}
@OptionsItem(R.id.menu_refresh)
protected void refreshPlaces() {
// Get the current location (if possible)
if (new MyLocation().getLocation(getActivity(), onLocationResult)) {
// Force the progress indicator to start
((RateBeerActivity)getActivity()).setProgress(true);
} else {
publishException(null, getString(R.string.error_locationnotsupported));
}
}
private LocationResult onLocationResult = new LocationResult() {
@Override
public void gotLocation(Location location) {
if (location == null && getView() != null) {
getView().post(new Runnable() {
@Override
public void run() {
if (getActivity() != null) {
publishException(null, getString(R.string.error_nolocation));
}
}
});
return;
}
// Now get the places at this location, if this fragment is still bound to an activity
PlacesFragment.this.lastLocation = location;
if (getActivity() != null && getView() != null && PlacesFragment.this.lastLocation != null) {
getView().post(new Runnable() {
@Override
public void run() {
getSettings().saveLastUserLocation(lastLocation);
execute(new GetPlacesAroundCommand(getUser(), DEFAULT_RADIUS,
lastLocation.getLatitude(), lastLocation.getLongitude()));
}
});
}
}
};
private OnItemClickListener onItemSelected = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Place item = ((PlacesAdapter)placesView.getAdapter()).getItem(position);
load(PlaceViewFragment_.builder().place(item).currentLocation(lastLocation).build());
}
};
@Override
public void onTaskSuccessResult(CommandSuccessResult result) {
if (result.getCommand().getMethod() == ApiMethod.GetPlacesAround) {
publishResults(((GetPlacesAroundCommand) result.getCommand()).getPlaces());
}
}
private void publishResults(ArrayList<Place> result) {
this.places = result;
//Collections.sort(result, new PlacesComparator(sortOrder));
if (placesView.getAdapter() == null) {
placesView.setAdapter(new PlacesAdapter(getActivity(), result));
} else {
((PlacesAdapter) placesView.getAdapter()).replace(result);
}
if (lastLocation != null && getMap() != null) {
// TODO: Show user location
LocationUtils.initGoogleMap(getMap(), lastLocation.getLatitude(), lastLocation.getLongitude());
for (Place place : places) {
Marker m = getMap().addMarker(new MarkerOptions()
.position(new LatLng(place.latitude, place.longitude))
.title(place.placeName)
.snippet(LocationUtils.getPlaceSnippet(getActivity(), place))
.icon(BitmapDescriptorFactory.defaultMarker(LocationUtils.getPlaceColour(place))));
markersMap.put(m.getId(), place);
}
getMap().setOnInfoWindowClickListener(onInfoWindowClicked);
getMap().setMyLocationEnabled(true);
}
}
private OnInfoWindowClickListener onInfoWindowClicked = new OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick(Marker marker) {
load(PlaceViewFragment_.builder().place(markersMap.get(marker.getId())).currentLocation(lastLocation).build());
}
};
@Override
public void onTaskFailureResult(CommandFailureResult result) {
publishException(null, result.getException());
}
@Override
protected void publishException(TextView textview, String message) {
((RateBeerActivity)getActivity()).setProgress(false);
super.publishException(textview, message);
}
private class PlacesAdapter extends ArrayAdapter<Place> {
public PlacesAdapter(Context context, List<Place> objects) {
super(context, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the right view, using a ViewHolder
ViewHolder holder;
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_place, null);
holder = new ViewHolder();
holder.placeName = (TextView) convertView.findViewById(R.id.placeName);
holder.placeType = (TextView) convertView.findViewById(R.id.placeType);
holder.distance = (TextView) convertView.findViewById(R.id.distance);
holder.city = (TextView) convertView.findViewById(R.id.city);
holder.score = (TextView) convertView.findViewById(R.id.score);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Bind the data
Place item = getItem(position);
holder.placeName.setText(item.placeName);
holder.placeType.setText(getPlaceTypeName(getActivity(), item.placeType));
holder.distance.setText(LocationUtils.getPlaceDistance(getSettings(), getResources(), item, lastLocation));
holder.city.setText(item.city);
holder.score.setText(item.avgRating == -1? "?": Integer.toString(item.avgRating));
return convertView;
}
}
public static String getPlaceTypeName(Context context, int placeType) {
switch (placeType) {
case 1:
return context.getString(R.string.places_brewpub);
case 2:
return context.getString(R.string.places_bar);
case 3:
return context.getString(R.string.places_beerstore);
case 4:
return context.getString(R.string.places_restaurant);
case 5:
return context.getString(R.string.places_brewer);
default:
return context.getString(R.string.places_unknown);
}
}
protected static class ViewHolder {
TextView placeName, placeType, distance, city, score;
}
private class PlacesPagerAdapter extends PagerAdapter {
private ListView pagerListView;
private FrameLayout pagerMapView;
public PlacesPagerAdapter() {
LayoutInflater inflater = getActivity().getLayoutInflater();
pagerListView = (ListView) inflater.inflate(R.layout.fragment_pagerlist, null);
pagerMapView = (FrameLayout) inflater.inflate(R.layout.fragment_placesmap, null);
placesView = pagerListView;
placesView.setOnItemClickListener(onItemSelected);
setMapView((MapView) pagerMapView.findViewById(R.id.map_nearby));
}
@Override
public int getCount() {
return 2;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getActivity().getString(R.string.places_nearby).toUpperCase(Locale.getDefault());
case 1:
return getActivity().getString(R.string.places_map).toUpperCase(Locale.getDefault());
}
return null;
}
@Override
public Object instantiateItem(View container, int position) {
switch (position) {
case 0:
((ViewPager) container).addView(pagerListView, 0);
return pagerListView;
case 1:
((ViewPager) container).addView(pagerMapView, 0);
return pagerMapView;
}
return null;
}
@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == (View) object;
}
}
}