LocationRepository.java

package com.jadventure.game.repository;

import com.jadventure.game.entities.NPC;
import com.jadventure.game.items.Item;
import com.jadventure.game.navigation.ILocation;
import com.jadventure.game.navigation.Location;
import com.jadventure.game.navigation.LocationType;
import com.jadventure.game.navigation.Coordinate;
import com.jadventure.game.GameBeans;
import com.jadventure.game.QueueProvider;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import com.google.gson.Gson;
import com.jadventure.game.JAdventure;

import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class loads the locations from the locations.json file on start.
 * It also provides methods for getting the initial location and the current location.
 */
public class LocationRepository {
    private ItemRepository itemRepo = GameBeans.getItemRepository();
    private String fileName;
    private Map<Coordinate, ILocation> locations;
    private static LocationRepository instance;

    public LocationRepository(String profileName) {
        locations = new HashMap<Coordinate, ILocation>();
        fileName = "json/profiles/" + profileName + "/locations.json";
        load();
    }

    public static LocationRepository createRepo(String profileName) {
        if ("".equals(profileName)) {
            return instance;
        }
        if (instance == null) {
            instance = new LocationRepository(profileName);
        } else if (!instance.getFileName().contains(profileName)) {
            instance = new LocationRepository(profileName);
        }
        return instance;
    }

    private String getFileName() {
        return fileName;
    }

    private void load() {
        JsonParser parser = new JsonParser();
        File f = new File(fileName);
        if (!f.exists()) {
            copyLocationsFile();
        }
        try {
            Reader reader = new FileReader(fileName);
            JsonObject json = parser.parse(reader).getAsJsonObject();
            for(Map.Entry<String, JsonElement> entry: json.entrySet()) {
                locations.put(new Coordinate(entry.getKey()), loadLocation(entry.getValue().getAsJsonObject()));
            }
            reader.close();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
            System.exit(-1);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private ILocation loadLocation(JsonObject json) {
        Coordinate coordinate = new Coordinate(json.get("coordinate").getAsString());
        String title = json.get("title").getAsString();
        String description = json.get("description").getAsString();
        LocationType locationType = LocationType.valueOf(json.get("locationType").getAsString());
        ILocation location = new Location(coordinate, title, description, locationType);
        location.setDangerRating(json.get("danger").getAsInt());
        if (json.has("items")) {
            List<String> items = new Gson().fromJson(json.get("items"), new TypeToken<List<String>>(){}.getType());
            for (String id : items) {
                location.addItem(itemRepo.getItem(id));
            }
        }
        if (json.has("npcs")) {
            List<String> npcs = new Gson().fromJson(json.get("npcs"), new TypeToken<List<String>>(){}.getType());
            for (String npc : npcs) {
                location.addNpc(npc);
            }
        }
        return location;
    }

    public void writeLocations() {
        try {
            JsonObject jsonObject = new JsonObject();
            for (Map.Entry<Coordinate,ILocation> entry : locations.entrySet()) {
                ILocation location = entry.getValue();
                JsonObject locationJsonElement = new JsonObject();
                locationJsonElement.addProperty("title", location.getTitle());
                locationJsonElement.addProperty("coordinate", location.getCoordinate().toString());
                locationJsonElement.addProperty("description", location.getDescription());
                locationJsonElement.addProperty("locationType", location.getLocationType().toString());
                locationJsonElement.addProperty("danger", String.valueOf(location.getDangerRating()));
                JsonArray itemList = new JsonArray();
                List<Item> items = location.getItems();
                if (items.size() > 0) {
                    for (Item item : items) {
                        JsonPrimitive itemJson = new JsonPrimitive(item.getId());
                        itemList.add(itemJson);
                    }
                    locationJsonElement.add("items", itemList);
                }
                JsonArray npcList = new JsonArray();
                List<NPC> npcs = location.getNpcs();
                if (npcs.size() > 0) {
                    for (NPC npc : npcs) {
                        JsonPrimitive npcJson = new JsonPrimitive(npc.getId());
                        npcList.add(npcJson);
                    }
                    locationJsonElement.add("npcs", npcList);
                }
                jsonObject.add(location.getCoordinate().toString(), locationJsonElement);
            }
            Writer writer = new FileWriter(fileName);
            Gson gson = new Gson();
            gson.toJson(jsonObject, writer);
            writer.close();
            QueueProvider.offer("The game locations were saved.");
        } catch (IOException ex) {
            QueueProvider.offer("Unable to save to file " + fileName);
        }
    }

    public ILocation getInitialLocation() {
        String profileName = fileName.split("/")[2];
        instance = null;
        LocationRepository.createRepo(profileName);
        load();
        Coordinate coordinate = new Coordinate(0, 0, -1);
        return getLocation(coordinate);
    }

    public ILocation getLocation(Coordinate coordinate) {
        if (coordinate == null) {
            return null;
        }
        if (!locations.containsKey(coordinate)) {
            throw new RepositoryException("Argument 'coordinate' with value '" + coordinate.toString() + "' not found in repository");
        }
        return locations.get(coordinate);
    }

    private void copyLocationsFile() {
        File source = new File("json/original_data/locations.json");
        File dest = new File(fileName);
        dest.mkdirs();
        try {
        Files.copy(source.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void addLocation(ILocation location) {
        locations.put(location.getCoordinate(), location);
    }
}