package io.andrewohara.tinkertime.controllers.workflows.tasks;
import io.andrewohara.common.workflows.tasks.WorkflowTask;
import io.andrewohara.tinkertime.models.ModFile;
import io.andrewohara.tinkertime.models.mod.Mod;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.io.IOUtils;
import com.j256.ormlite.dao.Dao;
public class AnalyzeModZipTask extends WorkflowTask {
private final Mod mod;
private final Dao<ModFile, Integer> modFilesDao;
public AnalyzeModZipTask(Mod mod, Dao<ModFile, Integer> modFilesDao) {
super("Analyzing Mod");
this.mod = mod;
this.modFilesDao = modFilesDao;
}
@Override
public boolean execute() throws Exception {
Collection<ModFile> files = new LinkedList<>();
String readmeText = null;
Path zipPath = mod.getZipPath();
if (zipPath == null){
throw new FileNotFoundException();
} else if(!zipPath.toFile().exists()){
throw new FileNotFoundException(zipPath.toString());
}
try(ZipFile zipFile = new ZipFile(zipPath.toFile())){
Path gameDataPath = null;
//Make first pass of entries to get key information
Enumeration<? extends ZipEntry> entries = zipFile.entries();
for (ZipEntry entry; entries.hasMoreElements(); ){
entry = entries.nextElement();
// Find Gamedata path
if (gameDataPath == null && entry.getName().toLowerCase().contains("gamedata")){
// Once a candidate has been found, find the exact path to the folder
Path tempPath = Paths.get(entry.getName());
while(tempPath != null && gameDataPath == null){
if (tempPath.getFileName().toString().toLowerCase().equals("gamedata")){
gameDataPath = tempPath;
} else {
tempPath = tempPath.getParent();
}
}
}
// Find Readme text
if (readmeText == null && !entry.isDirectory() && entry.getName().toLowerCase().contains("readme")){
try(StringWriter writer = new StringWriter(); InputStream is = zipFile.getInputStream(entry)){
IOUtils.copy(is, writer);
readmeText = writer.toString();
} catch (IOException e) {}
}
}
// Make second pass of entries to get all Mod Files
entries = zipFile.entries();
if (gameDataPath == null){
// If no gameDataPath, get all files with a path length of at least 2.
// This is because, we only get files which are within folders in the root of the zip
for (ZipEntry entry; entries.hasMoreElements(); ){
entry = entries.nextElement();
Path entryPath = Paths.get(entry.getName());
if (!entry.isDirectory() && entryPath.getNameCount() >= 2){
files.add(new ModFile(mod, entry.getName(), entryPath, modFilesDao));
}
}
} else {
// Get all files within the GameData directory
for (ZipEntry entry; entries.hasMoreElements(); ){
entry = entries.nextElement();
Path entryPath = Paths.get(entry.getName());
if (
!entry.isDirectory() &&
entryPath.startsWith(gameDataPath) && !entryPath.equals(gameDataPath) &&
!(entry.getName().contains("ModuleManager") && entry.getName().endsWith(".dll"))
){
files.add(new ModFile(mod, entry.getName(), gameDataPath.relativize(entryPath), modFilesDao));
}
}
}
// If no files found, make third pass to get DLLs in root
if (files.isEmpty()){
entries = zipFile.entries();
for (ZipEntry entry; entries.hasMoreElements(); ){
entry = entries.nextElement();
if (entry.getName().endsWith(".dll")){
Path entryPath = Paths.get(entry.getName());
Path path = gameDataPath == null ? entryPath : gameDataPath.relativize(entryPath);
files.add(new ModFile(mod, entry.getName(), path, modFilesDao));
}
}
}
}
mod.setModFiles(files);
mod.setReadmeText(readmeText);
return true;
}
@Override
protected int findTargetProgress() throws IOException {
return 0;
}
}