package de.tum.in.tumcampusapp.managers; import android.content.Context; import android.database.Cursor; import android.text.format.DateUtils; import com.google.common.base.Optional; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; 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.cards.CafeteriaMenuCard; import de.tum.in.tumcampusapp.cards.generic.Card; import de.tum.in.tumcampusapp.models.cafeteria.Cafeteria; import de.tum.in.tumcampusapp.models.cafeteria.CafeteriaMenu; /** * Cafeteria Manager, handles database stuff, external imports */ public class CafeteriaManager extends AbstractManager implements Card.ProvidesCard { private static final int TIME_TO_SYNC = 604800; // 1 week public static final String CAFETERIAS_URL = "https://tumcabe.in.tum.de/Api/mensen"; /** * Get Cafeteria object by JSON object * <p> * Example JSON: e.g. * {"mensa":"4", "id":"411","name":"Mensa Leopoldstraße","anschrift" * :"Leopoldstraße 13a, München", "latitude":0.0000, "longitude":0.0000} * * @param json See example * @return Cafeteria object * @throws JSONException */ private static Cafeteria getFromJson(JSONObject json) throws JSONException { return new Cafeteria(json.getInt(Const.JSON_ID), json.getString(Const.JSON_NAME), json.getString(Const.JSON_ADDRESS), json.getDouble(Const.JSON_LATITUDE), json.getDouble(Const.JSON_LONGITUDE)); } /** * Constructor, open/create database, create table if necessary * * @param context Context */ public CafeteriaManager(Context context) { super(context); // create table if needed db.execSQL("CREATE TABLE IF NOT EXISTS cafeterias (id INTEGER PRIMARY KEY, name VARCHAR, address VARCHAR, latitude REAL, longitude REAL)"); } /** * Download cafeterias from external interface (JSON) * * @param force True to force download over normal sync period, else false * @throws JSONException */ public void downloadFromExternal(boolean force) throws JSONException { SyncManager sync = new SyncManager(mContext); // Update table schemata if table exists if (!force && !sync.needSync(this, TIME_TO_SYNC)) { return; } Optional<JSONArray> jsonArray = new NetUtils(mContext).downloadJsonArray(CAFETERIAS_URL, CacheManager.VALIDITY_ONE_MONTH, false); if (!jsonArray.isPresent()) { return; } removeCache(); // write cafeterias into database, transaction = speedup JSONArray arr = jsonArray.get(); db.beginTransaction(); try { for (int i = 0; i < arr.length(); i++) { replaceIntoDb(getFromJson(arr.getJSONObject(i))); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } sync.replaceIntoDb(this); } /** * Returns all cafeterias * * @return Database cursor (id, name, address, latitude, longitude) */ public Cursor getAllFromDb() { return db.query("cafeterias", null, null, null, null, null, null); } /** * Removes all cache items */ public void removeCache() { db.execSQL("DELETE FROM cafeterias"); } /** * Replace or Insert a cafeteria in the database * * @param c Cafeteria object * @throws Exception */ void replaceIntoDb(Cafeteria c) { if (c.id <= 0) { throw new IllegalArgumentException("Invalid id."); } if (c.name.isEmpty()) { throw new IllegalArgumentException("Invalid name."); } db.execSQL("REPLACE INTO cafeterias (id, name, address, latitude, longitude) VALUES (?, ?, ?, ?, ?)", new String[]{String.valueOf(c.id), c.name, c.address, Double.toString(c.latitude), Double.toString(c.longitude)}); } /** * Shows card for the best matching cafeteria. * * @param context Context * @see LocationManager#getCafeteria() */ @Override public void onRequestCard(Context context) { // Choose which mensa should be shown int cafeteriaId = new LocationManager(context).getCafeteria(); if (cafeteriaId == -1) { return; } // Get all available cafeterias from database Cursor cursor = getAllFromDb(); String cafeteriaName = ""; if (cursor.moveToFirst() && cursor.getColumnCount() >= 2) { do { final int key = cursor.getInt(0); if (key == cafeteriaId) { cafeteriaName = cursor.getString(1); break; } } while (cursor.moveToNext()); } cursor.close(); // Get available dates for cafeteria menus CafeteriaMenuManager cmm = new CafeteriaMenuManager(context); Cursor cursorCafeteriaDates = cmm.getDatesFromDb(); // Try with next available date cursorCafeteriaDates.moveToFirst(); // Get today or tomorrow if today is sunday e.g. if(cursorCafeteriaDates.getCount() == 0) { return; } final int idCol = cursorCafeteriaDates.getColumnIndex(Const.ID_COLUMN); String dateStr = cursorCafeteriaDates.getString(idCol); Date date = Utils.getDate(dateStr); // If it is 3pm or later mensa has already closed so display the menu for the following day Calendar now = Calendar.getInstance(); if (DateUtils.isToday(date.getTime()) && now.get(Calendar.HOUR_OF_DAY) >= 15) { cursorCafeteriaDates.moveToNext(); // Get following day try { dateStr = cursorCafeteriaDates.getString(idCol); date = Utils.getDate(dateStr); }catch (Exception ignore) { return; } } cursorCafeteriaDates.close(); List<CafeteriaMenu> menus = cmm.getTypeNameFromDbCardList(cafeteriaId, dateStr, date); if (!menus.isEmpty()) { CafeteriaMenuCard card = new CafeteriaMenuCard(context); card.setCardMenus(cafeteriaId, cafeteriaName, dateStr, date, menus); card.apply(); } } /** * returns the menus of the best matching cafeteria */ public Map<String, List<CafeteriaMenu>> getBestMatchMensaInfo(Context context) { // Choose which mensa should be shown int cafeteriaId = new LocationManager(context).getCafeteria(); if (cafeteriaId == -1) { Utils.log("could not get a Cafeteria form locationManager!"); return null; } // Get all available cafeterias from database Cursor cursor = getAllFromDb(); String cafeteriaName = ""; // get the cafeteria's name if (cursor.moveToFirst()) { do { final int key = cursor.getInt(0); if (key == cafeteriaId) { cafeteriaName = cursor.getString(1); break; } } while (cursor.moveToNext()); } cursor.close(); // Get available dates for cafeteria menus CafeteriaMenuManager cmm = new CafeteriaMenuManager(context); Cursor cursorCafeteriaDates = cmm.getDatesFromDb(); final int idCol = cursorCafeteriaDates.getColumnIndex(Const.ID_COLUMN); // Try with next available date cursorCafeteriaDates.moveToFirst(); // Get today or tomorrow if today is sunday e.g. String dateStr = cursorCafeteriaDates.getString(idCol); Date date = Utils.getDate(dateStr); // If it is 3pm or later mensa has already closed so display the menu for the following day Calendar now = Calendar.getInstance(); if (DateUtils.isToday(date.getTime()) && now.get(Calendar.HOUR_OF_DAY) >= 15) { cursorCafeteriaDates.moveToNext(); // Get following day dateStr = cursorCafeteriaDates.getString(idCol); date = Utils.getDate(dateStr); } cursorCafeteriaDates.close(); List<CafeteriaMenu> menus = cmm.getTypeNameFromDbCardList(cafeteriaId, dateStr, date); String mensaKey = cafeteriaName + ' ' + dateStr; Map<String, List<CafeteriaMenu>> selectedMensaMenus = new HashMap<>(1); selectedMensaMenus.put(mensaKey, menus); return selectedMensaMenus; } public String getBestMatchMensaName(Context context) { // Choose which mensa should be shown int cafeteriaId = new LocationManager(context).getCafeteria(); if (cafeteriaId == -1) { Utils.log("could not get a Cafeteria form locationManager!"); return null; } // Get all available cafeterias from database Cursor cursor = getAllFromDb(); String cafeteriaName = ""; // get the cafeteria's name if (cursor.moveToFirst()) { do { final int key = cursor.getInt(0); if (key == cafeteriaId) { cafeteriaName = cursor.getString(1); break; } } while (cursor.moveToNext()); } cursor.close(); // Get available dates for cafeteria menus CafeteriaMenuManager cmm = new CafeteriaMenuManager(context); Cursor cursorCafeteriaDates = cmm.getDatesFromDb(); final int idCol = cursorCafeteriaDates.getColumnIndex(Const.ID_COLUMN); // Try with next available date cursorCafeteriaDates.moveToFirst(); // Get today or tomorrow if today is sunday e.g. String dateStr = cursorCafeteriaDates.getString(idCol); Date date = Utils.getDate(dateStr); // If it is 3pm or later mensa has already closed so display the menu for the following day Calendar now = Calendar.getInstance(); if (DateUtils.isToday(date.getTime()) && now.get(Calendar.HOUR_OF_DAY) >= 15) { cursorCafeteriaDates.moveToNext(); // Get following day dateStr = cursorCafeteriaDates.getString(idCol); } cursorCafeteriaDates.close(); return cafeteriaName + ' ' + dateStr; } }