package edu.kit.pse.ws2013.routekit.controllers; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import edu.kit.pse.ws2013.routekit.map.StreetMap; import edu.kit.pse.ws2013.routekit.models.ProfileMapCombination; import edu.kit.pse.ws2013.routekit.util.FileUtil; /** * Manages the street maps and saves/loads them to/from disk. */ public class MapManager { private static MapManager instance; private final File root; private final Map<StreetMap, File> maps; private final Map<String, StreetMap> mapsByName; private MapManager(File root) { this.root = root; this.maps = new HashMap<>(); this.mapsByName = new HashMap<>(); if (!root.isDirectory()) { throw new IllegalArgumentException(root.toString() + " is not a directory!"); } for (String childString : root.list()) { File child = new File(root, childString); if (child.isDirectory()) { addMap(StreetMap.loadLazily(child), child); } } } private void addMap(StreetMap map, File f) { maps.put(map, f); mapsByName.put(map.getName(), map); } private void removeMap(StreetMap map) { maps.remove(map); mapsByName.remove(map.getName()); } /** * Deletes all precalculations ({@link ProfileMapCombination * ProfileMapCombinations} in the {@link ProfileMapManager}) with the same * map name as {@code map}. */ private void deletePrecalculations(StreetMap map) { for (ProfileMapCombination precalculation : new HashSet<>( ProfileMapManager.getInstance().getPrecalculations())) { if (map.equals(precalculation.getStreetMap())) { ProfileMapManager.getInstance().deletePrecalculation( precalculation, false); } } } /** * Removes the given map from the internal list, * {@link ProfileMapManager#deletePrecalculation(ProfileMapCombination) * deletes} all its precalculations and deletes it from disk. * * @param map * The map that shall be deleted. */ public void deleteMap(StreetMap map) { if (map.isDefault()) { throw new IllegalArgumentException("Can’t delete a default map!"); } try { FileUtil.rmRf(maps.get(map)); } catch (IOException e) { } deletePrecalculations(map); removeMap(map); ProfileMapManager.getInstance().checkIfCurrentStillExists(); try { ProfileMapManager.getInstance().rewriteIndex(); } catch (IOException e) { e.printStackTrace(); } } /** * Adds the given map to the internal list and saves it on disk. * * @param map * The map that shall be saved. * @throws IOException * @throws IllegalArgumentException * If the map name is {@link #checkMapName(String) invalid}. */ public void saveMap(StreetMap map) throws IOException { StreetMap existing = mapsByName.get(map.getName()); if (existing == null) { if (!checkMapName(map.getName())) { throw new IllegalArgumentException("Invalid map name!"); } } else { deletePrecalculations(map); } File f = maps.get(existing); if (f == null) { f = new File(root, map.getName()); f.mkdir(); } map.save(f); addMap(map, f); } /** * Returns all maps in the internal list. * * @return All maps. */ public Set<StreetMap> getMaps() { return maps.keySet(); } /** * Returns {@code true} iff the given name is a valid name for a new map. * * @param name * The map name. * @return {@code true} if {@code name} can be used as the name of a new * map, {@code false} otherwise. * @see FileUtil#checkMapName(String) */ public boolean checkMapName(String name) { if (!FileUtil.checkMapName(name)) { return false; } for (String s : mapsByName.keySet()) { if (name.equalsIgnoreCase(s)) { return false; } } return true; } /** * Initializes the {@link MapManager}. * * @param rootDirectory * The directory that contains all maps. * * @throws IllegalStateException * If the MapManager is already initialized. */ public static void init(File rootDirectory) { if (instance != null) { throw new IllegalStateException("Already initialized!"); } instance = new MapManager(rootDirectory); } /** * Returns the {@link MapManager} instance. This is only allowed if the * MapManager was previously {@link #init() initialized}. * * @return The MapManager instance. * @throws IllegalStateException * If the MapManager is uninitialized. */ public static MapManager getInstance() { if (instance == null) { throw new IllegalStateException("Not yet initialized!"); } return instance; } }