/* Copyright (c) 2013 Jesper Öqvist <jesper@llbit.se>
*
* This file is part of Chunky.
*
* Chunky is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chunky is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Chunky. If not, see <http://www.gnu.org/licenses/>.
*/
package se.llbit.chunky.launcher;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import org.jastadd.util.PrettyPrinter;
import se.llbit.json.JsonArray;
import se.llbit.json.JsonObject;
import se.llbit.json.JsonValue;
import se.llbit.util.Util;
/**
* Describes Chunky version info.
* @author Jesper Öqvist <jesper@llbit.se>
*/
public class VersionInfo implements Comparable<VersionInfo> {
public enum LibraryStatus {
PASSED("Installed"),
MD5_MISMATCH("Will be downloaded (checksum mismatch)"),
INCOMPLETE_INFO("Incomplete library information"),
MISSING("Will be downloaded (file missing)"),
MALFORMED_URL("Download failed (malformed URL)"),
FILE_NOT_FOUND("Download failed (file not found)"),
DOWNLOAD_FAILED("Download failed"),
DOWNLOADED_OK("Downloaded OK");
public final String dlStatus;
private LibraryStatus(String status) {
dlStatus = status;
}
public String downloadStatus() {
return dlStatus;
}
};
public static class Library {
public final String name;
public final String md5;
public final String url;
public final int size;
public Library(String name, String md5, int size) {
this.name = name;
this.md5 = md5;
this.url = "";
this.size = size;
}
public Library(JsonObject obj) {
name = obj.get("name").stringValue("");
md5 = obj.get("md5").stringValue("");
url = obj.get("url").stringValue("");
size = obj.get("size").intValue(1);
}
public File getFile(File libDir) {
return new File(libDir, name);
}
public LibraryStatus testIntegrity(File libDir) {
if (name.isEmpty() || md5.isEmpty()) {
return LibraryStatus.INCOMPLETE_INFO;
}
File library = new File(libDir, name);
if (!library.isFile()) {
return LibraryStatus.MISSING;
}
String libMD5 = Util.md5sum(library);
if (!libMD5.equalsIgnoreCase(md5)) {
return LibraryStatus.MD5_MISMATCH;
}
return LibraryStatus.PASSED;
}
public JsonObject json() {
JsonObject obj = new JsonObject();
obj.add("name", name);
obj.add("md5", md5);
obj.add("url", url);
obj.add("size", size);
return obj;
}
@Override
public String toString() {
return name;
}
}
public static final VersionInfo LATEST =
new VersionInfo("latest", new Date());
public static final VersionInfo NONE =
new VersionInfo("none", new Date());
public final String name;
public Collection<Library> libraries = new LinkedList<Library>();
private final String timestamp;
private final Date date;
public String notes = "";
public VersionInfo(JsonObject json) {
name = json.get("name").stringValue("");
timestamp = json.get("timestamp").stringValue("");
date = Util.dateFromISO8601(timestamp);
notes = json.get("notes").stringValue("");
JsonArray libraryArray = json.get("libraries").array();
for (JsonValue lib: libraryArray.getElementList()) {
libraries.add(new Library(lib.object()));
}
}
private VersionInfo(String name, Date date) {
this.name = name;
this.timestamp = Util.ISO8601FromDate(date);
this.date = date;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof VersionInfo)) {
return false;
}
VersionInfo other = (VersionInfo) obj;
return name.equals(other.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public String toString() {
return name;
}
/**
* @return The value 0 if the argument version is as recent as this version; a
* value less than 0 if this version is more recent than the argument version;
* and a value greater than 0 if this version is older than the argument
* version.
*/
@Override
public int compareTo(VersionInfo o) {
return o.date.compareTo(date);
}
/**
* @return {@code true} if the version data contains all required information.
*/
public boolean isValid() {
if (name.isEmpty()) {
return false;
}
if (!Util.isValidISO8601(timestamp)) {
return false;
}
for (Library lib: libraries) {
if (lib.name.isEmpty() || lib.md5.isEmpty()) {
return false;
}
}
return true;
}
/**
* Write the version info to the given file.
* @param file
* @throws FileNotFoundException
*/
public void writeTo(File file) throws IOException {
PrintStream out = new PrintStream(new FileOutputStream(file));
PrettyPrinter pp = new PrettyPrinter(" ", out);
pp.print(json());
out.close();
}
private JsonObject json() {
JsonObject obj = new JsonObject();
obj.add("name", name);
obj.add("timestamp", timestamp);
obj.add("notes", notes);
JsonArray libraryArray = new JsonArray();
for (Library lib: libraries) {
libraryArray.add(lib.json());
}
obj.add("libraries", libraryArray);
return obj;
}
public String date() {
DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
return fmt.format(date);
}
}