package boston.Bus.Map.util;
import android.util.Log;
import android.widget.Toast;
import com.schneeloch.bostonbusmap_library.data.RouteTitles;
import com.schneeloch.bostonbusmap_library.data.StopLocation;
import boston.Bus.Map.data.UpdateArguments;
import boston.Bus.Map.main.Main;
import com.schneeloch.bostonbusmap_library.provider.IDatabaseAgent;
import com.schneeloch.bostonbusmap_library.transit.ITransitSystem;
public class SearchHelper
{
private final Main context;
private final RouteTitles dropdownRouteKeysToTitles;
private final String query;
private String suggestionsQuery;
private static final int QUERY_NONE = 0;
private static final int QUERY_ROUTE = 1;
private static final int QUERY_STOP = 2;
private int queryType = QUERY_NONE;
private final UpdateArguments arguments;
private final IDatabaseAgent databaseAgent;
public SearchHelper(Main context, RouteTitles dropdownRouteKeysToTitles,
UpdateArguments arguments, String query, IDatabaseAgent databaseAgent)
{
this.context = context;
this.dropdownRouteKeysToTitles = dropdownRouteKeysToTitles;
this.query = query;
this.arguments = arguments;
this.databaseAgent = databaseAgent;
}
/**
* Search for query and do whatever actions we do when that happens
*/
public void runSearch(Runnable onFinish)
{
searchRoutes(onFinish);
}
/**
* Try a search on the list of routes. If it matches, do that. Else, it's a geocode
*/
private void searchRoutes(final Runnable onFinish) {
String lowercaseQuery = query.toLowerCase();
String printableQuery = query;
//remove these words from the search
String[] wordsToRemove = new String[] {"route", "subway", "bus", "stop", "direction"};
queryType = QUERY_NONE;
String censoredQuery = query;
for (String wordToRemove : wordsToRemove)
{
boolean itEndsWith = lowercaseQuery.endsWith(" " + wordToRemove);
boolean itStartsWith = lowercaseQuery.startsWith(wordToRemove + " ");
boolean wholeWord = lowercaseQuery.equals(wordToRemove);
boolean middleWord = lowercaseQuery.contains(" " + wordToRemove + " ");
if (itEndsWith || itStartsWith || wholeWord || middleWord)
{
String adjustedCensoredQuery;
if (wholeWord)
{
adjustedCensoredQuery = "";
}
else if (itEndsWith)
{
adjustedCensoredQuery = censoredQuery.substring(0, censoredQuery.length() - (1 + wordToRemove.length()));
}
else if (itStartsWith)
{
adjustedCensoredQuery = censoredQuery.substring(1 + wordToRemove.length());
}
else
{
adjustedCensoredQuery = censoredQuery.replace(" " + wordToRemove + " ", "");
}
lowercaseQuery = adjustedCensoredQuery.toLowerCase();
censoredQuery = adjustedCensoredQuery;
if (wordToRemove.equals("route"))
{
queryType = QUERY_ROUTE;
}
else if (wordToRemove.equals("stop"))
{
queryType = QUERY_STOP;
}
}
}
String queryWithoutSpaces = censoredQuery;
if (censoredQuery.contains(" "))
{
queryWithoutSpaces = censoredQuery.replaceAll(" ", "");
lowercaseQuery = queryWithoutSpaces.toLowerCase();
}
//indexingQuery is query which may be slightly altered to match one of the route keys
String indexingQuery = lowercaseQuery;
if (indexingQuery.length() >= 2)
{
//this is kind of a hack. We need subway lines to start with a capital letter to search for them properly
indexingQuery = indexingQuery.substring(0, 1).toUpperCase() + queryWithoutSpaces.substring(1);
}
//NOTE: the next section is currently never run since we set queryContainsStop to true if queryContainsRoute was false
final String finalLowercaseQuery = lowercaseQuery;
final String finalIndexingQuery = indexingQuery;
final String finalPrintableQuery = printableQuery;
returnResults(onFinish, finalIndexingQuery, finalLowercaseQuery, finalPrintableQuery);
}
private void returnResults(Runnable onFinish, String indexingQuery, String lowercaseQuery, String printableQuery) {
final ITransitSystem transitSystem = arguments.getTransitSystem();
if (queryType == QUERY_NONE || queryType == QUERY_ROUTE)
{
String routeKey = getAsRoute(indexingQuery, lowercaseQuery);
if (routeKey != null)
{
//done!
context.setNewRoute(routeKey, false, true);
String routeTitle = dropdownRouteKeysToTitles.getTitle(routeKey);
suggestionsQuery = "route " + routeTitle;
}
else
{
Toast.makeText(context, "Route '" + printableQuery + "' could not be found.", Toast.LENGTH_LONG).show();
}
}
else if (queryType == QUERY_STOP)
{
// ideally we'd use RoutePool instead of DatabaseHelper, since RoutePool will
// reuse existing stops if they match. But stop is temporary so it doesn't really matter
String exactQuery;
if (printableQuery.startsWith("stop "))
{
exactQuery = printableQuery.substring(5);
}
else
{
exactQuery = printableQuery;
}
StopLocation stop = databaseAgent.getStopByTagOrTitle(
lowercaseQuery, exactQuery, transitSystem);
if (stop != null)
{
context.setNewStop(stop.getFirstRoute(), stop.getStopTag());
suggestionsQuery = "stop " + stop.getTitle();
}
else
{
//invalid stop id, or we just didn't parse it correctly
Toast.makeText(context, "Stop '" + printableQuery + "' could not be found.", Toast.LENGTH_LONG).show();
}
}
else
{
//shouldn't happen
Log.e("BostonBusMap", "Error: query is neither about stops, routes, or directions");
}
onFinish.run();
}
private String getAsRoute(String indexingQuery, String lowercaseQuery)
{
return arguments.getTransitSystem().searchForRoute(indexingQuery, lowercaseQuery);
}
public String getSuggestionsQuery()
{
return suggestionsQuery;
}
}