package io.andrewohara.tinkertime.controllers;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
import java.sql.SQLException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import io.andrewohara.common.Listenable;
import io.andrewohara.common.workflows.tasks.TaskCallback;
import io.andrewohara.tinkertime.controllers.workflows.ModWorkflowBuilder;
import io.andrewohara.tinkertime.controllers.workflows.ModWorkflowBuilderFactory;
import io.andrewohara.tinkertime.controllers.workflows.TaskLauncher;
import io.andrewohara.tinkertime.io.crawlers.CrawlerFactory.UnsupportedHostException;
import io.andrewohara.tinkertime.models.mod.Mod;
/**
* Controller for initiating Asynchronous Tasks for Mod Processing.
*
* All Mod-Related Actions are to be initiated through this Controller.
* All Asynchronous tasks initiated are executed by the executors of this class,
* and the tasks are represented by {@link io.andrewohara.common.workflows.Workflow} classes.
*
* @author Andrew O'Hara
*/
@Singleton
public class ModManager extends Listenable<TaskCallback> {
private final TaskLauncher taskLauncher;
private final ModWorkflowBuilderFactory workflowBuilderFactory;
private final ModLoader modLoader;
private Mod selectedMod;
@Inject
ModManager(ModWorkflowBuilderFactory workflowBuilderFactory, ModLoader modLoader, TaskLauncher taskLauncher){
this.workflowBuilderFactory = workflowBuilderFactory;
this.modLoader = modLoader;
this.taskLauncher = taskLauncher;
}
// -- Interface --------------------------------------------------------
public Mod getSelectedMod() throws NoModSelectedException {
if (selectedMod == null){
throw new NoModSelectedException();
}
return selectedMod;
}
public void selectMod(Mod mod){
this.selectedMod = mod;
}
public void updateMod(Mod mod, boolean forceUpdate) throws ModUpdateFailedException {
if (!mod.isUpdateable()){
throw new ModUpdateFailedException(mod, "Mod is a local zip only, and cannot be updated.");
}
try {
ModWorkflowBuilder builder = workflowBuilderFactory.createBuilder(mod);
builder.updateMod(forceUpdate);
if (mod.isEnabled()){
builder.enableMod();
}
taskLauncher.submitDownloadWorkflow(builder);
} catch (UnsupportedHostException | ModNotDownloadedException e) {
throw new ModUpdateFailedException(e);
}
}
public boolean downloadNewMod(URL url) throws SQLException, ModUpdateFailedException {
if (modLoader.getByUrl(url) == null){
Mod newMod = modLoader.newMod(url);
updateMod(newMod, false);
return true;
}
return false;
}
public void addModZip(Path zipPath) throws SQLException{
Mod newMod = modLoader.newLocalMod(zipPath);
ModWorkflowBuilder builder = workflowBuilderFactory.createBuilder(newMod);
builder.addLocalMod(zipPath);
taskLauncher.submitDownloadWorkflow(builder);
}
public void updateMods() throws ModUpdateFailedException, ModNotDownloadedException{
for (Mod mod : modLoader.getMods()){
if (mod.isUpdateable()){
updateMod(mod, false);
}
}
}
public void toggleMod(final Mod mod) {
ModWorkflowBuilder builder = workflowBuilderFactory.createBuilder(mod);
try {
if (mod.isEnabled()){
builder.disableMod();
} else {
builder.enableMod();
}
taskLauncher.submitFileWorkflow(builder);
} catch (ModNotDownloadedException e){
// Ignore user input if mod not downloaded
}
}
public void deleteMod(Mod mod) throws CannotDeleteModException {
if (mod.isBuiltIn()){
throw new CannotDeleteModException(mod, "Built-in");
}
ModWorkflowBuilder builder = workflowBuilderFactory.createBuilder(mod);
builder.deleteMod();
taskLauncher.submitFileWorkflow(builder);
}
public void checkForModUpdates() throws UnsupportedHostException{
for (final Mod mod : modLoader.getMods()){
try {
if (mod.isUpdateable()){
ModWorkflowBuilder builder = workflowBuilderFactory.createBuilder(mod);
builder.checkForUpdates(true);
taskLauncher.submitDownloadWorkflow(builder);
}
} catch (UnsupportedHostException ex) {
throw new RuntimeException(ex);
}
}
}
public void tryUpdateModManager() throws UnsupportedHostException, MalformedURLException, SQLException {
Mod tempMod = Mod.newModManagerMod();
ModWorkflowBuilder builder = workflowBuilderFactory.createBuilder(tempMod);
builder.checkForUpdates(false);
builder.downloadModInBrowser(tempMod);
taskLauncher.submitDownloadWorkflow(builder);
}
////////////////
// Exceptions //
////////////////
@SuppressWarnings("serial")
public static class ModNotDownloadedException extends Exception {
public ModNotDownloadedException(Mod mod, String message){
super("Error for " + mod + ": " + message);
}
}
@SuppressWarnings("serial")
public static class ModUpdateFailedException extends Exception {
public ModUpdateFailedException(Exception e){
super(e);
}
public ModUpdateFailedException(Mod mod, String message){
super("Error for " + mod + ": " + message);
}
}
@SuppressWarnings("serial")
public static class NoModSelectedException extends Exception {
}
@SuppressWarnings("serial")
public static class CannotDeleteModException extends Exception {
public CannotDeleteModException(Mod mod, String reason){
super(String.format("Cannot delete %s: %s", mod, reason));
}
}
}