package cgeo.geocaching;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import org.apache.commons.lang3.StringUtils;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import cgeo.geocaching.activity.AbstractActionBarActivity;
import cgeo.geocaching.address.AddressListActivity;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.connector.capability.ISearchByGeocode;
import cgeo.geocaching.connector.trackable.TrackableBrand;
import cgeo.geocaching.connector.trackable.TrackableTrackingCode;
import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.location.GeopointFormatter;
import cgeo.geocaching.search.AutoCompleteAdapter;
import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.storage.DataStore;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.EditUtils;
import cgeo.geocaching.utils.functions.Func1;
public class SearchActivity extends AbstractActionBarActivity implements CoordinatesInputDialog.CoordinateUpdate {
@BindView(R.id.buttonLatitude) protected Button buttonLatitude;
@BindView(R.id.buttonLongitude) protected Button buttonLongitude;
@BindView(R.id.search_coordinates) protected Button buttonSearchCoords;
@BindView(R.id.address) protected AutoCompleteTextView addressEditText;
@BindView(R.id.search_address) protected Button buttonSearchAddress;
@BindView(R.id.geocode) protected AutoCompleteTextView geocodeEditText;
@BindView(R.id.display_geocode) protected Button buttonSearchGeocode;
@BindView(R.id.keyword) protected AutoCompleteTextView keywordEditText;
@BindView(R.id.search_keyword) protected Button buttonSearchKeyword;
@BindView(R.id.finder) protected AutoCompleteTextView finderNameEditText;
@BindView(R.id.search_finder) protected Button buttonSearchFinder;
@BindView(R.id.owner) protected AutoCompleteTextView ownerNameEditText;
@BindView(R.id.search_owner) protected Button buttonSearchOwner;
@BindView(R.id.trackable) protected AutoCompleteTextView trackableEditText;
@BindView(R.id.display_trackable) protected Button buttonSearchTrackable;
private static final String GOOGLE_NOW_SEARCH_ACTION = "com.google.android.gms.actions.SEARCH_ACTION";
@Override
public final void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
// search suggestion for a cache
if (Intents.ACTION_GEOCACHE.equals(intent.getAction())) {
CacheDetailActivity.startActivity(this, intent.getStringExtra(SearchManager.QUERY));
finish();
return;
}
// search suggestion for a trackable
if (Intents.ACTION_TRACKABLE.equals(intent.getAction())) {
TrackableActivity.startActivity(this, null, intent.getStringExtra(SearchManager.QUERY), null, null, TrackableBrand.UNKNOWN.getId());
finish();
return;
}
// search query, from search toolbar or from google now
if (Intent.ACTION_SEARCH.equals(intent.getAction()) || GOOGLE_NOW_SEARCH_ACTION.equals(intent.getAction())) {
hideKeyboard();
final String query = intent.getStringExtra(SearchManager.QUERY);
final boolean keywordSearch = intent.getBooleanExtra(Intents.EXTRA_KEYWORD_SEARCH, true);
if (instantSearch(query, keywordSearch)) {
setResult(RESULT_OK);
} else {
// send intent back so query string is known
setResult(RESULT_CANCELED, intent);
}
finish();
return;
}
setTheme();
setContentView(R.layout.search_activity);
// set title in code, as the activity needs a hard coded title due to the intent filters
setTitle(res.getString(R.string.search));
ButterKnife.bind(this);
init();
}
@Override
public final void onConfigurationChanged(final Configuration newConfig) {
super.onConfigurationChanged(newConfig);
init();
}
@Override
public final void onResume() {
super.onResume();
init();
}
/**
* Performs a search for query either as geocode, trackable code or keyword
*
* @param nonTrimmedQuery
* String to search for
* @param keywordSearch
* Set to true if keyword search should be performed if query isn't GC or TB
* @return true if a search was performed, else false
*/
private boolean instantSearch(final String nonTrimmedQuery, final boolean keywordSearch) {
final String query = StringUtils.trim(nonTrimmedQuery);
// first check if this was a scanned URL
String geocode = ConnectorFactory.getGeocodeFromURL(query);
// otherwise see if this is a pure geocode
if (StringUtils.isEmpty(geocode)) {
geocode = StringUtils.upperCase(StringUtils.trim(query));
}
final IConnector connector = ConnectorFactory.getConnector(geocode);
if (connector instanceof ISearchByGeocode && geocode != null) {
CacheDetailActivity.startActivity(this, geocode.toUpperCase(Locale.US));
return true;
}
// Check if the query is a TB code
TrackableBrand trackableBrand = ConnectorFactory.getTrackableConnector(geocode).getBrand();
// check if the query contains a TB code
if (trackableBrand == TrackableBrand.UNKNOWN) {
final String tbCode = ConnectorFactory.getTrackableFromURL(query);
if (StringUtils.isNotBlank(tbCode)) {
trackableBrand = ConnectorFactory.getTrackableConnector(tbCode).getBrand();
geocode = tbCode;
}
}
// check if the query contains a TB tracking code
if (trackableBrand == TrackableBrand.UNKNOWN) {
final TrackableTrackingCode tbTrackingCode = ConnectorFactory.getTrackableTrackingCodeFromURL(query);
if (!tbTrackingCode.isEmpty()) {
trackableBrand = tbTrackingCode.brand;
geocode = tbTrackingCode.trackingCode;
}
}
if (trackableBrand != TrackableBrand.UNKNOWN && geocode != null) {
final Intent trackablesIntent = new Intent(this, TrackableActivity.class);
trackablesIntent.putExtra(Intents.EXTRA_GEOCODE, geocode.toUpperCase(Locale.US));
trackablesIntent.putExtra(Intents.EXTRA_BRAND, trackableBrand.getId());
startActivity(trackablesIntent);
return true;
}
if (keywordSearch) { // keyword fallback, if desired by caller
CacheListActivity.startActivityKeyword(this, query.trim());
return true;
}
return false;
}
private void init() {
buttonLatitude.setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
updateCoordinates();
}
});
buttonLongitude.setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
updateCoordinates();
}
});
buttonSearchCoords.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View arg0) {
findByCoordsFn();
}
});
setSearchAction(addressEditText, buttonSearchAddress, new Runnable() {
@Override
public void run() {
findByAddressFn();
}
}, null);
setSearchAction(geocodeEditText, buttonSearchGeocode, new Runnable() {
@Override
public void run() {
findByGeocodeFn();
}
}, new Func1<String, String[]>() {
@Override
public String[] call(final String input) {
return DataStore.getSuggestionsGeocode(input);
}
});
setSearchAction(keywordEditText, buttonSearchKeyword, new Runnable() {
@Override
public void run() {
findByKeywordFn();
}
}, new Func1<String, String[]>() {
@Override
public String[] call(final String input) {
return DataStore.getSuggestionsKeyword(input);
}
});
setSearchAction(finderNameEditText, buttonSearchFinder, new Runnable() {
@Override
public void run() {
findByFinderFn();
}
}, new Func1<String, String[]>() {
@Override
public String[] call(final String input) {
return DataStore.getSuggestionsFinderName(input);
}
});
setSearchAction(ownerNameEditText, buttonSearchOwner, new Runnable() {
@Override
public void run() {
findByOwnerFn();
}
}, new Func1<String, String[]>() {
@Override
public String[] call(final String input) {
return DataStore.getSuggestionsOwnerName(input);
}
});
setSearchAction(trackableEditText, buttonSearchTrackable, new Runnable() {
@Override
public void run() {
findTrackableFn();
}
}, new Func1<String, String[]>() {
@Override
public String[] call(final String input) {
return DataStore.getSuggestionsTrackableCode(input);
}
});
}
private static void setSearchAction(final AutoCompleteTextView editText, final Button button, @NonNull final Runnable runnable, @Nullable final Func1<String, String[]> suggestionFunction) {
EditUtils.setActionListener(editText, runnable);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View arg0) {
runnable.run();
}
});
if (suggestionFunction != null) {
editText.setAdapter(new AutoCompleteAdapter(editText.getContext(), android.R.layout.simple_dropdown_item_1line, suggestionFunction));
}
}
private void updateCoordinates() {
final CoordinatesInputDialog coordsDialog = CoordinatesInputDialog.getInstance(null, null);
coordsDialog.setCancelable(true);
coordsDialog.show(getSupportFragmentManager(), "wpedit_dialog");
}
@Override
public void updateCoordinates(final Geopoint gp) {
buttonLatitude.setText(gp.format(GeopointFormatter.Format.LAT_DECMINUTE));
buttonLongitude.setText(gp.format(GeopointFormatter.Format.LON_DECMINUTE));
}
private void findByCoordsFn() {
final String latText = StringUtils.trim(buttonLatitude.getText().toString());
final String lonText = StringUtils.trim(buttonLongitude.getText().toString());
if (StringUtils.isEmpty(latText) || StringUtils.isEmpty(lonText)) {
final GeoData geo = Sensors.getInstance().currentGeo();
buttonLatitude.setText(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE));
buttonLongitude.setText(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
} else {
try {
CacheListActivity.startActivityCoordinates(this, new Geopoint(latText, lonText), null);
} catch (final Geopoint.ParseException e) {
showToast(res.getString(e.resource));
}
}
}
private void findByKeywordFn() {
// find caches by coordinates
final String keyText = StringUtils.trim(keywordEditText.getText().toString());
if (StringUtils.isBlank(keyText)) {
Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_keyword);
return;
}
CacheListActivity.startActivityKeyword(this, keyText);
}
private void findByAddressFn() {
final String addText = StringUtils.trim(addressEditText.getText().toString());
if (StringUtils.isBlank(addText)) {
Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_address);
return;
}
final Intent addressesIntent = new Intent(this, AddressListActivity.class);
addressesIntent.putExtra(Intents.EXTRA_KEYWORD, addText);
startActivity(addressesIntent);
}
private void findByFinderFn() {
final String usernameText = StringUtils.trim(finderNameEditText.getText().toString());
if (StringUtils.isBlank(usernameText)) {
Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_user);
return;
}
CacheListActivity.startActivityFinder(this, usernameText);
}
private void findByOwnerFn() {
findByOwnerFn(ownerNameEditText.getText().toString());
}
private void findByOwnerFn(final String userName) {
final String usernameText = StringUtils.trimToEmpty(userName);
if (StringUtils.isBlank(usernameText)) {
Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_user);
return;
}
CacheListActivity.startActivityOwner(this, usernameText);
}
private void findByGeocodeFn() {
final String geocodeText = StringUtils.trimToEmpty(geocodeEditText.getText().toString());
if (StringUtils.isBlank(geocodeText) || geocodeText.equalsIgnoreCase("GC")) {
Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_gccode);
return;
}
CacheDetailActivity.startActivity(this, geocodeText.toUpperCase(Locale.US));
}
private void findTrackableFn() {
final String trackableText = StringUtils.trimToEmpty(trackableEditText.getText().toString());
if (StringUtils.isBlank(trackableText) || trackableText.equalsIgnoreCase("TB")) {
Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_tb);
return;
}
final Intent trackablesIntent = new Intent(this, TrackableActivity.class);
trackablesIntent.putExtra(Intents.EXTRA_GEOCODE, trackableText.toUpperCase(Locale.US));
startActivity(trackablesIntent);
}
@Override
public final boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.search_activity_options, menu);
return true;
}
@Override
public final boolean onOptionsItemSelected(final MenuItem item) {
if (item.getItemId() == R.id.menu_search_own_caches) {
findByOwnerFn(Settings.getUserName());
return true;
}
return super.onOptionsItemSelected(item);
}
public static void startActivityScan(final String scan, final Activity fromActivity) {
final Intent searchIntent = new Intent(fromActivity, SearchActivity.class);
searchIntent.setAction(Intent.ACTION_SEARCH).
putExtra(SearchManager.QUERY, scan).
putExtra(Intents.EXTRA_KEYWORD_SEARCH, false);
fromActivity.startActivityForResult(searchIntent, Intents.SEARCH_REQUEST_CODE);
}
}