package com.narrowtux.fmm.model; import com.narrowtux.fmm.io.dirwatch.DirectoryWatchService; import com.narrowtux.fmm.io.dirwatch.SimpleDirectoryWatchService; import com.narrowtux.fmm.io.ModpackDetectorVisitor; import com.narrowtux.fmm.io.tasks.TaskService; import javafx.application.Platform; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.ObservableMap; import javafx.collections.ObservableSet; import javafx.concurrent.Task; import java.io.*; import java.nio.file.*; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedHashSet; public class Datastore { //singleton stuff private static Datastore instance; public static Datastore getInstance() { return instance; } private ObservableSet<Modpack> modpacks = FXCollections.observableSet(new LinkedHashSet<>()); private ObservableMap<ModKey, Mod> mods = FXCollections.observableMap(new LinkedHashMap<ModKey, Mod>()); private ObjectProperty<Path> dataDir = new SimpleObjectProperty<>(null); private ObjectProperty<Path> factorioApplication = new SimpleObjectProperty<>(); private ObjectProperty<Path> storageDir = new SimpleObjectProperty<>(); private ObservableList<Save> saves = FXCollections.observableArrayList(); private FileVisitor<Path> fmmScaner = new ModpackDetectorVisitor(getModpacks(), this); public Datastore() { instance = this; SimpleDirectoryWatchService.getInstance().start(); dataDirProperty().addListener((obj, ov, nv) -> { if (nv != null) { Path fmm = getFMMDir(); DirectoryWatchService.OnFileChangeListener listener = new DirectoryWatchService.OnFileChangeListener() { @Override public void onFileCreate(String filePath) { try { Files.walkFileTree(getFMMDir().resolve(filePath), fmmScaner); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFileModify(String filePath) { try { Files.walkFileTree(getFMMDir().resolve(filePath), fmmScaner); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFileDelete(String filePath) { Path path = getFMMDir().resolve(filePath); getModpacks().stream().filter(m -> m.getPath().equals(path)).findAny().ifPresent(modpack -> getModpacks().remove(modpack)); } }; try { SimpleDirectoryWatchService.getInstance().register(listener, fmm.toAbsolutePath().toString()); } catch (IOException e) { e.printStackTrace(); } } }); } public void scanDirectory() throws IOException { Task<Void> task = new Task<Void>() { @Override protected Void call() throws Exception { try { updateTitle("Scanning"); Path path = getFMMDir(); updateProgress(0, 3); updateTitle("Scanning for mods"); Files.walk(path.resolve("mods")).filter(p -> Files.isRegularFile(p)).filter(p -> p.getFileName().toString().endsWith(".zip")) .forEach(modZipFile -> { try { ModpackDetectorVisitor.parseMod(modZipFile); } catch (IOException e) { e.printStackTrace(); } }); getMods().put(new ModKey("base", Version.valueOf("0.11.22")), new Mod("base", Version.valueOf("0.11.22"), null)); getMods().put(new ModKey("base", Version.valueOf("0.11.12")), new Mod("base", Version.valueOf("0.11.12"), null)); updateProgress(1, 3); updateTitle("Scanning for modpacks"); Files.walkFileTree(path, fmmScaner); updateProgress(2, 3); updateTitle("Scanning for savegames"); Files.walk(getDataDir().resolve("saves")) .filter(p -> Files.isRegularFile(p)) .filter(p -> p.getFileName().toString().endsWith(".zip")) .forEach(saveZipFile -> { Save save = new Save(saveZipFile); saves.add(save); }); updateProgress(3, 3); } catch (Exception e) { e.printStackTrace(); throw e; } return null; } }; TaskService.getInstance().submit(task); } public Mod getMod(String name, Version version) { ModKey key = new ModKey(name, version); Mod existing = mods.get(key); if (existing == null) { existing = new Mod(name, version, null); // create mod without path. This means this mod is not installed if (Platform.isFxApplicationThread()) { mods.put(key, existing); } else { final Mod finalExisting = existing; Platform.runLater(() -> mods.put(key, finalExisting)); } } return existing; } public ObservableSet<Modpack> getModpacks() { return modpacks; } public Path getDataDir() { return dataDir.get(); } public ObjectProperty<Path> dataDirProperty() { return dataDir; } public void setDataDir(Path dataDir) { this.dataDir.set(dataDir); } public Path getModDir() { return getDataDir().resolve("mods"); } public Path getFMMDir() { return getDataDir().resolve("fmm"); } public Path getFactorioApplication() { return factorioApplication.get(); } public ObjectProperty<Path> factorioApplicationProperty() { return factorioApplication; } public void setFactorioApplication(Path factorioApplication) { this.factorioApplication.set(factorioApplication); } public Path getStorageDir() { return storageDir.get(); } public ObjectProperty<Path> storageDirProperty() { return storageDir; } public void setStorageDir(Path storageDir) { this.storageDir.set(storageDir); } public ObservableMap<ModKey, Mod> getMods() { return mods; } public ObservableList<Save> getSaves() { return saves; } }