package org.vaadin.touchkit.extensions;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.vaadin.touchkit.gwt.client.vcom.GeolocatorClientRpc;
import org.vaadin.touchkit.gwt.client.vcom.GeolocatorServerRpc;
import org.vaadin.touchkit.gwt.client.vcom.Position;
import com.vaadin.server.AbstractExtension;
import com.vaadin.server.Extension;
import com.vaadin.ui.UI;
/**
* The Geolocator extension can be used to detect the client's geographical
* location, direction, altitude, etc.
* <p>
* Under the hood, Geolocator is a UI extension and should be used via the
* static {@link #detect(PositionCallback)} method. As the detection happens on
* the client side, it is asynchronous and the result is passed to the
* registered {@link PositionCallback}.
*/
@SuppressWarnings("serial")
public class Geolocator extends AbstractExtension {
private Map<Integer, PositionCallback> callbacks = new HashMap<Integer, PositionCallback>();
/**
* Detects the current geographic location of the client. The detection
* happens asynchronously and the position is reported to the callback given
* in the callback argument. Note that this only checks the position once,
* you need to call this method multiple times if you want to update the
* location as the client moves.
*
* @param callback
* The {@link PositionCallback} instance that is called when the
* position is available.
*/
public static void detect(PositionCallback callback) {
Geolocator locator = null;
// Do we already have a Geolocator attached?
for (Extension e : UI.getCurrent().getExtensions()) {
if (e instanceof Geolocator) {
locator = (Geolocator) e;
}
}
// Attach a Geolocator if none found.
if (locator == null) {
locator = new Geolocator();
locator.extend(UI.getCurrent());
}
locator.detectCurrentPosition(callback);
}
/**
* Constructs a GeoLocator, called by the {@link #detect(PositionCallback)}
* method.
*/
private Geolocator() {
registerRpc(new GeolocatorServerRpc() {
@Override
public void onGeolocationSuccess(int callbackId, Position position) {
callbacks.remove(callbackId).onSuccess(position);
}
@Override
public void onGeolocationError(int callbackId, int errorCode) {
callbacks.remove(callbackId).onFailure(errorCode);
}
});
}
/**
* Asks the client for the current location information and passes it along
* to the provided callback.
*
* @param callback
* the {@link PositionCallback} to call when the position data is
* available.
*/
private void detectCurrentPosition(PositionCallback callback) {
int callbackid = 0;
while (callbacks.containsKey(callbackid)) {
callbackid = new Random().nextInt();
}
callbacks.put(callbackid, callback);
getRpcProxy(GeolocatorClientRpc.class)
.detectCurrentPosition(callbackid);
}
}