package de.tum.in.tumcampusapp.tumonline; import android.content.Context; import android.os.AsyncTask; import com.google.common.base.Optional; import com.google.common.net.UrlEscapers; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import de.tum.in.tumcampusapp.R; import de.tum.in.tumcampusapp.auxiliary.Const; import de.tum.in.tumcampusapp.auxiliary.NetUtils; import de.tum.in.tumcampusapp.auxiliary.Utils; import de.tum.in.tumcampusapp.auxiliary.calendar.IntegratedCalendarEvent; import de.tum.in.tumcampusapp.managers.CacheManager; import de.tum.in.tumcampusapp.models.tumo.Geo; /** * Base class for communication with TUMRoomFinder */ public class TUMRoomFinderRequest { // Json keys public static final String KEY_ARCH_ID = "arch_id"; public static final String KEY_MAP_ID = "map_id"; public static final String KEY_DESCRIPTION = "description"; public static final String KEY_ROOM_ID = "room_id"; public static final String KEY_CAMPUS_ID = "campus"; public static final String KEY_CAMPUS_TITLE = "name"; public static final String KEY_BUILDING_TITLE = "address"; public static final String KEY_ROOM_TITLE = "info"; public static final String KEY_UTM_ZONE = "utm_zone"; public static final String KEY_UTM_EASTING = "utm_easting"; public static final String KEY_UTM_NORTHING = "utm_northing"; // Api urls private static final String API_BASE_URL = "https://tumcabe.in.tum.de/Api/roomfinder/"; private static final String API_URL_SEARCH = API_BASE_URL + "room/search/"; private static final String API_URL_DEFAULT_MAP = API_BASE_URL + "room/defaultMap/"; private static final String API_URL_MAP = API_BASE_URL + "room/map/"; private static final String API_URL_COORDINATES = API_BASE_URL + "room/coordinates/"; private static final String API_URL_AVAILABLE_MAPS = API_BASE_URL + "room/availableMaps/"; private static final String API_URL_SCHEDULE = API_BASE_URL + "room/scheduleById/"; private final NetUtils net; /** * asynchronous task for interactive fetch */ private AsyncTask<String, Void, List<Map<String, String>>> backgroundTask; public TUMRoomFinderRequest(Context context) { net = new NetUtils(context); } /** * returns the url to get the default map * * @param archId architecture id * @return url of default map */ public static String fetchDefaultMap(String archId) { return API_URL_DEFAULT_MAP + encodeUrl(archId); } /** * returns the url for any map * * @param archId architecture id * @param mapId map id * @return url of map */ public static String fetchMap(String archId, String mapId) { return API_URL_MAP + encodeUrl(archId) + '/' + encodeUrl(mapId); } /** * encodes an url * * @param pUrl input url * @return encoded url */ private static String encodeUrl(String pUrl) { String url = pUrl.replace("/", ""); //remove slashes in queries as this breaks the url return UrlEscapers.urlPathSegmentEscaper().escape(url); } /** * Converts UTM based coordinates to latitude and longitude based format */ private static Geo convertUTMtoLL(double north, double east, double zone) { double d = 0.99960000000000004; double d1 = 6378137; double d2 = 0.0066943799999999998; double d4 = (1 - Math.sqrt(1 - d2)) / (1 + Math.sqrt(1 - d2)); double d15 = east - 500000; double d11 = (zone - 1) * 6 - 180 + 3; double d3 = d2 / (1 - d2); double d10 = north / d; double d12 = d10 / (d1 * (1 - d2 / 4 - (3 * d2 * d2) / 64 - (5 * Math.pow(d2, 3)) / 256)); double d14 = d12 + ((3 * d4) / 2 - (27 * Math.pow(d4, 3)) / 32) * Math.sin(2 * d12) + ((21 * d4 * d4) / 16 - (55 * Math.pow(d4, 4)) / 32) * Math.sin(4 * d12) + ((151 * Math.pow(d4, 3)) / 96) * Math.sin(6 * d12); double d5 = d1 / Math.sqrt(1 - d2 * Math.sin(d14) * Math.sin(d14)); double d6 = Math.tan(d14) * Math.tan(d14); double d7 = d3 * Math.cos(d14) * Math.cos(d14); double d8 = (d1 * (1 - d2)) / Math.pow(1 - d2 * Math.sin(d14) * Math.sin(d14), 1.5); double d9 = d15 / (d5 * d); double d17 = d14 - ((d5 * Math.tan(d14)) / d8) * ((d9 * d9) / 2 - ((5 + 3 * d6 + 10 * d7 - 4 * d7 * d7 - 9 * d3) * Math.pow(d9, 4)) / 24 + ((61 + 90 * d6 + 298 * d7 + 45 * d6 * d6 - 252 * d3 - 3 * d7 * d7) * Math.pow(d9, 6)) / 720); d17 *= 180 / Math.PI; double d18 = (d9 - ((1 + 2 * d6 + d7) * Math.pow(d9, 3)) / 6 + ((5 - 2 * d7 + 28 * d6 - 3 * d7 * d7 + 8 * d3 + 24 * d6 * d6) * Math.pow(d9, 5)) / 120) / Math.cos(d14); d18 = d11 + d18 * 180 / Math.PI; return new Geo(d17, d18); } public void cancelRequest(boolean mayInterruptIfRunning) { // Cancel background task just if one has been established if (backgroundTask != null) { backgroundTask.cancel(mayInterruptIfRunning); } } /** * fetches the room coordinates * * @param archId architecture id * @return coordinates of the room */ public Optional<Geo> fetchCoordinates(String archId) { String url = API_URL_COORDINATES + encodeUrl(archId); Geo result = null; try { Optional<JSONObject> jsonObject = net.downloadJson(url); if (jsonObject.isPresent()) { double zone = jsonObject.get().getDouble(KEY_UTM_ZONE); double easting = jsonObject.get().getDouble(KEY_UTM_EASTING); double northing = jsonObject.get().getDouble(KEY_UTM_NORTHING); result = convertUTMtoLL(northing, easting, zone); } } catch (JSONException e) { Utils.log(String.valueOf(e)); } // if something went wrong return Optional.fromNullable(result); } /** * fetches all rooms that match the search string * * @param searchString string that was entered by the user * @return list of HashMaps representing rooms, Map: attributes -> values */ public List<Map<String, String>> fetchRooms(String searchString) { String url = API_URL_SEARCH + encodeUrl(searchString); Optional<JSONArray> jsonArray = net.downloadJsonArray(url, CacheManager.VALIDITY_DO_NOT_CACHE, true); List<Map<String, String>> roomsList = new ArrayList<>(); try { if (jsonArray.isPresent()) { JSONArray arr = jsonArray.get(); for (int i = 0; i < arr.length(); i++) { JSONObject obj = arr.getJSONObject(i); Map<String, String> roomMap = new HashMap<>(); roomMap.put(KEY_CAMPUS_ID, obj.getString(KEY_CAMPUS_ID)); roomMap.put(KEY_CAMPUS_TITLE, obj.getString(KEY_CAMPUS_TITLE)); roomMap.put(KEY_BUILDING_TITLE, obj.getString(KEY_BUILDING_TITLE)); roomMap.put(KEY_ROOM_TITLE, obj.getString(KEY_ROOM_TITLE)); roomMap.put(KEY_ARCH_ID, obj.getString(KEY_ARCH_ID)); roomMap.put(KEY_ROOM_ID, obj.getString(KEY_ROOM_ID)); // adding HashList to ArrayList roomsList.add(roomMap); } } } catch (JSONException e) { Utils.log(e); } return roomsList; } /** * fetches all available maps of the room or building * * @param archId architecture id * @return list of HashMap representing available maps */ public List<Map<String, String>> fetchAvailableMaps(String archId) { String url = API_URL_AVAILABLE_MAPS + encodeUrl(archId); Optional<JSONArray> jsonArray = net.downloadJsonArray(url, CacheManager.VALIDITY_DO_NOT_CACHE, true); List<Map<String, String>> mapsList = new ArrayList<>(); try { if (jsonArray.isPresent()) { JSONArray arr = jsonArray.get(); for (int i = 0; i < arr.length(); i++) { JSONObject obj = arr.getJSONObject(i); Map<String, String> mapMap = new HashMap<>(); mapMap.put(KEY_MAP_ID, obj.getString(KEY_MAP_ID)); mapMap.put(KEY_DESCRIPTION, obj.getString(KEY_DESCRIPTION)); // adding HashList to ArrayList mapsList.add(mapMap); } } } catch (JSONException e) { Utils.log(String.valueOf(e)); } return mapsList; } /** * fetches the room schedule for a given room * * @param roomId roomId * @return List of Events */ public List<IntegratedCalendarEvent> fetchRoomSchedule(String roomId, String startDate, String endDate, List<IntegratedCalendarEvent> scheduleList) { String url = API_URL_SCHEDULE + encodeUrl(roomId) + '/' + encodeUrl(startDate) + '/' + encodeUrl(endDate); Optional<JSONArray> jsonArray = net.downloadJsonArray(url, CacheManager.VALIDITY_DO_NOT_CACHE, true); if (!jsonArray.isPresent()) { return scheduleList; } JSONArray arr = jsonArray.get(); try { for (int i = 0; i < arr.length(); i++) { JSONObject obj = arr.getJSONObject(i); String start = obj.getString("start"); Calendar startCal = Calendar.getInstance(); startCal.setTime(Utils.getISODateTime(start)); String end = obj.getString("end"); Calendar endCal = Calendar.getInstance(); endCal.setTime(Utils.getISODateTime(end)); IntegratedCalendarEvent event = new IntegratedCalendarEvent( obj.getLong("event_id"), obj.getString(Const.JSON_TITLE), startCal, endCal, "", IntegratedCalendarEvent.getDisplayColorFromColor(0xff28921f) ); scheduleList.add(event); } } catch (JSONException e) { Utils.log(e); } return scheduleList; } /** * this fetch method will fetch the data from the TUMRoomFinder Request and * will address the listeners onFetch if the fetch succeeded, else the * onFetchError will be called * * @param context the current context (may provide the current activity) * @param listener the listener, which takes the result * @param searchString Text to search for */ public void fetchSearchInteractive(final Context context, final TUMRoomFinderRequestFetchListener listener, String searchString) { // fetch information in a background task and show progress dialog in // meantime backgroundTask = new AsyncTask<String, Void, List<Map<String, String>>>() { /** * property to determine if there is an internet connection */ boolean isOnline; @Override protected List<Map<String, String>> doInBackground( String... searchString) { // set parameter on the TUMRoomFinder request an fetch the // results isOnline = NetUtils.isConnected(context); if (!isOnline) { // not online, fetch does not make sense return null; } // we are online, return fetch result return fetchRooms(searchString[0]); } @Override protected void onPostExecute(List<Map<String, String>> result) { // handle result if (!isOnline) { listener.onNoInternetError(); return; } if (result == null) { listener.onFetchError(context .getString(R.string.empty_result)); return; } // If there could not be found any problems return usual on // Fetch method listener.onFetch(result); } }; backgroundTask.execute(searchString); } }