package com.project.website.canvas.client.canvastools.map; import java.util.Collections; import java.util.List; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.HashBiMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.project.gwtmapstraction.client.mxn.MapProvider; import com.project.gwtmapstraction.client.mxn.MapstractionMapType; import com.project.shared.client.events.SimpleEvent; import com.project.shared.client.events.SimpleEvent.Handler; import com.project.shared.client.events.SingleEvent; import com.project.shared.client.net.DynamicSourceLoader; import com.project.shared.client.utils.HandlerUtils; import com.project.shared.client.utils.SchedulerUtils; import com.project.shared.data.Pair; import com.project.shared.data.funcs.AsyncFunc; import com.project.shared.data.funcs.Func; import com.project.shared.utils.MapUtils; import com.project.website.canvas.shared.data.MapData.MapType; public class MapToolStaticUtils { private static final String GOOGLE_MAPS_V3_SCRIPT_URL = "http://maps.googleapis.com/maps/api/js?sensor=false"; private static final String OPENLAYERS_SCRIPT_URL = "http://openlayers.org/api/OpenLayers.js"; private static final String MICROSOFT_MAP_6_3_URL = "http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.3"; public static final List<MapProvider> AVAILABLE_PROVIDERS = Collections.unmodifiableList(Lists.newArrayList( MapProvider.GOOGLE_V3, MapProvider.MICROSOFT, MapProvider.OPENLAYERS )); private static final Iterable<String> MAPSTRACTION_AVAILABLE_API_STRINGS = Iterables.transform(AVAILABLE_PROVIDERS, new Function<MapProvider, String>(){ @Override public String apply(MapProvider arg) { return arg.getApiString(); } }); private static final String MAPSTRACTION_AVAILABLE_APIS = Joiner.on(',').join(MAPSTRACTION_AVAILABLE_API_STRINGS); private static final String MAPSTRACTION_SCRIPT_PROVIDER_PREFIX_URL = "mapstraction/mxn."; private static final String MAPSTRACTION_SCRIPT_FILE_URL = "mapstraction/mxn.js"; private static final String MAPSTRACTION_SCRIPT_CORE_FILE_URL = "mapstraction/mxn.core.js"; // private static final String MAPSTRACTION_SCRIPT_WITH_PARAMS_URL // = MAPSTRACTION_SCRIPT_FILE_URL + "?(" + MAPSTRACTION_AVAILABLE_APIS + ")"; protected static boolean loaded = false; public static final SingleEvent<Void> apiLoadedEvent = new SingleEvent<Void>(); public static void loadApi() { Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { MapToolStaticUtils.getLoadMapScriptsAsyncFunc() .then(apiLoadedEvent.getDispatchFunc()) .run(null); } }); } private static class MapTypePair extends Pair<MapType, MapstractionMapType> { private static final long serialVersionUID = 1L; public MapTypePair(MapType a, MapstractionMapType b) { super(a, b); } } private static HashBiMap<MapType, MapstractionMapType> mapTypeConversionMap = MapUtils.putPairs(HashBiMap.<MapType, MapstractionMapType>create(), new MapTypePair[]{ new MapTypePair(MapType.HYBRID, MapstractionMapType.HYBRID), new MapTypePair(MapType.PHYSICAL, MapstractionMapType.PHYSICAL), new MapTypePair(MapType.ROAD, MapstractionMapType.ROAD), new MapTypePair(MapType.SATELLITE, MapstractionMapType.SATELLITE) }); public static MapType fromMapstractionMapType(MapstractionMapType mapstractionMapType) { return mapTypeConversionMap.inverse().get(mapstractionMapType); } public static MapstractionMapType fromMapType(MapType mapType) { return mapTypeConversionMap.get(mapType); } public static void loadMapScriptsAsync(Handler<Void> loadHandler) { getLoadMapScriptsAsyncFunc().then(HandlerUtils.toFunc(loadHandler)) .run(null); } private static boolean isAvailable(MapProvider provider) { return AVAILABLE_PROVIDERS.contains(provider); } public static AsyncFunc<Void,Void> getLoadMapScriptsAsyncFunc() { AsyncFunc<Void, Void> res = AsyncFunc.immediate(); if (MapToolStaticUtils.loaded) { return res; } for (MapProvider provider : AVAILABLE_PROVIDERS) { res = res.and(getLoadProviderAsyncFunc(provider)) .constResult(null); } res = res.then(DynamicSourceLoader.getLoadAsyncFunc(MAPSTRACTION_SCRIPT_FILE_URL)); res = res.then(DynamicSourceLoader.getLoadAsyncFunc(MAPSTRACTION_SCRIPT_CORE_FILE_URL)); for (MapProvider provider : AVAILABLE_PROVIDERS) { res = res.then(DynamicSourceLoader.getLoadAsyncFunc(getProviderCoreMxnScriptUrl(provider, "core"))); } res = res.then(SchedulerUtils.getDeferredAsyncFunc()); return res.then(new Func.VoidAction() { @Override public void exec() { MapToolStaticUtils.loaded = true; } }); } private static String getProviderCoreMxnScriptUrl(MapProvider provider, String module) { return MAPSTRACTION_SCRIPT_PROVIDER_PREFIX_URL + provider.getApiString() + "." + module + ".js"; } public static boolean isApiLoaded() { return MapToolStaticUtils.loaded; } private static AsyncFunc<Void, Void> getLoadProviderAsyncFunc(MapProvider provider) { if (false == isAvailable(provider)) { throw new RuntimeException("Provider is not available: " + provider.name()); } AsyncFunc<Void, Void> res = AsyncFunc.immediate(); switch (provider) { case GOOGLE_V3: res = res.then(getLoadGoogleV3MapProviderAsyncFunc()); break; case MICROSOFT: res = res.then(DynamicSourceLoader.getLoadAsyncFunc(MICROSOFT_MAP_6_3_URL)); case OPENLAYERS: res = res.then(DynamicSourceLoader.getLoadAsyncFunc(OPENLAYERS_SCRIPT_URL)); default: break; } return res; } private static AsyncFunc<Void, Void> getLoadGoogleV3MapProviderAsyncFunc() { return new AsyncFunc<Void, Void>() { @Override protected <S, E> void run(Void arg, final Func<Void, S> successHandler, Func<Throwable, E> errorHandler) { loadGoogleV3MapProvider(new Handler<Void>(){ @Override public void onFire(Void arg) { successHandler.apply(null); } }); } }; } // TODO: refactor this into DynamicScriptLoader // for scripts that have a callback private static void loadGoogleV3MapProvider(SimpleEvent.Handler<Void> handler) { if (googleV3MapProviderLoaded) { HandlerUtils.fireDeferred(handler, null); return; } // see http://code.google.com/apis/maps/documentation/javascript/basics.html#Async String source = GOOGLE_MAPS_V3_SCRIPT_URL + "&callback=" + GoogleV3MapProviderCallbackName; defineGoogleV3MapProviderLoadedCallback(); googleMapV3ScriptLoadedSuccessEvent.addHandler(handler); DynamicSourceLoader.getLoadAsyncFunc(source).run(null); } private static SimpleEvent<Void> googleMapV3ScriptLoadedSuccessEvent = new SimpleEvent<Void>(); private static boolean googleV3MapProviderLoaded = false; private static final String GoogleV3MapProviderCallbackName = "GoogleV3MapProviderLoadedCallback"; private static final native void defineGoogleV3MapProviderLoadedCallback() /*-{ $wnd.GoogleV3MapProviderLoadedCallback = @com.project.website.canvas.client.canvastools.map.MapToolStaticUtils::GoogleMapV3ProviderLoaded(); }-*/; static void GoogleMapV3ProviderLoaded() { googleV3MapProviderLoaded = true; SimpleEvent<Void> event = googleMapV3ScriptLoadedSuccessEvent; googleMapV3ScriptLoadedSuccessEvent = null; event.dispatch(null); } }