org.onebusaway.webapp.gwt.where_library.impl.CombinedSearchHandlerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.onebusaway.webapp.gwt.where_library.impl.CombinedSearchHandlerImpl.java

Source

/**
 * Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * 
 */
package org.onebusaway.webapp.gwt.where_library.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.onebusaway.transit_data.model.RoutesAndStopsBean;
import org.onebusaway.webapp.gwt.common.control.Place;
import org.onebusaway.webapp.gwt.common.control.PlaceImpl;
import org.onebusaway.webapp.gwt.common.control.PlaceSearch;
import org.onebusaway.webapp.gwt.where_library.services.CombinedSearchResult;

import com.google.gwt.core.client.JsArray;
import com.google.gwt.maps.client.geocode.LocationCallback;
import com.google.gwt.maps.client.geocode.Placemark;
import com.google.gwt.maps.client.geom.LatLngBounds;
import com.google.gwt.search.client.SearchCompleteHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;

class CombinedSearchHandlerImpl extends Timer
        implements AsyncCallback<RoutesAndStopsBean>, SearchCompleteHandler, LocationCallback {

    private static final double PLACE_MERGE_DISTANCE = 25.0;

    private LatLngBounds _bounds;

    private AsyncCallback<CombinedSearchResult> _callback;

    private boolean _resultsSent = false;

    private boolean _routeAndStopResultReceived = false;

    private boolean _addressResultsReceived = false;

    private boolean _localResultsReceived = false;

    private boolean _placeSearchTimeout = false;

    private RoutesAndStopsBean _routeAndStopResult;

    private List<Place> _addresses = new ArrayList<Place>();

    private List<Place> _places = new ArrayList<Place>();

    public CombinedSearchHandlerImpl(LatLngBounds bounds, int placeTimeoutMillis,
            AsyncCallback<CombinedSearchResult> callback) {
        _bounds = bounds;
        _callback = callback;
        schedule(placeTimeoutMillis);
    }

    /****
     * {@link Timer} Interface
     ****/

    /**
     * This is fired when the timer has expired
     */
    @Override
    public void run() {
        _placeSearchTimeout = true;
        checkAndSendResults();
    }

    /****
     * {@link AsyncCallback} Interface
     ****/

    @Override
    public void onSuccess(RoutesAndStopsBean routesAndStopsResult) {
        _routeAndStopResultReceived = true;
        _routeAndStopResult = routesAndStopsResult;
        checkAndSendResults();
    }

    @Override
    public void onFailure(Throwable ex) {
        _callback.onFailure(ex);
    }

    /****
     * {@link LocationCallback} Interface
     ****/

    @Override
    public void onSuccess(JsArray<Placemark> placemarks) {

        for (int i = 0; i < placemarks.length(); i++) {
            Placemark mark = placemarks.get(i);
            Place place = getPlacemarkAsPlace(mark);
            _addresses.add(place);
            System.out.println("address=" + place);
        }

        _addressResultsReceived = true;
        checkAndSendResults();
    }

    @Override
    public void onFailure(int statusCode) {
        System.err.println("address search failure: code=" + statusCode);
    }

    /****
     * {@link SearchCompleteHandler} Interface
     ****/

    @Override
    public void onSearchComplete(SearchCompleteEvent event) {

        System.out.println("search event=" + event);

        PlaceSearch.getSeachCompleteEventAsPlaces(event, _places);

        _localResultsReceived = true;
        checkAndSendResults();
    }

    /****
     * Private Methods
     ****/

    private void checkAndSendResults() {

        boolean placeResults = (_addressResultsReceived && _localResultsReceived) || _placeSearchTimeout;

        if (_routeAndStopResultReceived && placeResults)
            sendResults();
    }

    private void sendResults() {

        if (_resultsSent)
            return;

        _resultsSent = true;

        _addresses = consolidatePlaces(_addresses);
        _places = consolidatePlaces(_places);
        consolidatePlacesNearAddresses();

        CombinedSearchResult results = new CombinedSearchResult();
        if (_routeAndStopResult != null) {
            results.setRoutes(_routeAndStopResult.getRoutes().getRoutes());
            results.setStops(_routeAndStopResult.getStops().getStops());
        }

        results.setAddresses(_addresses);
        results.setPlaces(_places);

        _callback.onSuccess(results);
    }

    private Place getPlacemarkAsPlace(Placemark mark) {

        String name = null;
        List<String> description = new ArrayList<String>();

        if (mark.getStreet() != null) {
            name = mark.getStreet();
            if (mark.getCity() != null)
                description.add(mark.getCity());
            if (mark.getState() != null)
                description.add(mark.getState());
            if (mark.getPostalCode() != null)
                description.add(mark.getPostalCode());
        } else if (mark.getCity() != null) {
            name = mark.getCity();
            if (mark.getState() != null)
                name += ", " + mark.getState();
        } else if (mark.getState() != null) {
            name = mark.getState();
            if (mark.getCounty() != null)
                description.add(mark.getCountry());
        }

        return new PlaceImpl(name, description, mark.getPoint(), mark.getAccuracy());
    }

    private List<Place> consolidatePlaces(List<Place> places) {

        for (Iterator<Place> it = places.iterator(); it.hasNext();) {
            Place place = it.next();
            if (place.getName() == null)
                it.remove();
        }

        // Merge nearby place results that are very similar
        places = PlaceSearch.mergeNearbyEntries(places, PLACE_MERGE_DISTANCE);

        List<Place> placesInRange = new ArrayList<Place>();
        if (_bounds != null) {
            for (Place place : places) {
                if (_bounds.containsLatLng(place.getLocation()))
                    placesInRange.add(place);
            }
        }

        if (!placesInRange.isEmpty())
            places = placesInRange;

        return places;
    }

    private void consolidatePlacesNearAddresses() {
        for (Iterator<Place> it = _places.iterator(); it.hasNext();) {
            Place place = it.next();
            for (Place address : _addresses) {
                double distance = place.getLocation().distanceFrom(address.getLocation());
                if (distance < PLACE_MERGE_DISTANCE) {
                    it.remove();
                    continue;
                }
            }
        }
    }
}