package xenxier.minecraft.servermagic.console.command;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.FileUtils;
import org.json.simple.JSONObject;
import xenxier.minecraft.servermagic.Activity;
import xenxier.minecraft.servermagic.MinecraftServerProperties;
import xenxier.minecraft.servermagic.Reference;
import xenxier.minecraft.servermagic.console.Console;
import xenxier.minecraft.servermagic.event.Event;
public class RestoreWorldCommand extends Command {
private static final String USAGE = "Usage: rollback <time> <minutes/hours/days>";
public RestoreWorldCommand() {
super("rollback");
}
@Override
public void execute() {
System.out.println("Restores the current world from a ServerMagic backup closet to the amount of time requested");
System.out.println(USAGE);
}
@Override
public void execute(String arguments[]) {
if (arguments.length < 2) {
System.out.println("This command requires two arguments.");
System.out.println(USAGE);
return;
}
if (!(arguments[1].toLowerCase().equals("minutes") || arguments[1].toLowerCase().equals("hours") || arguments[1].toLowerCase().equals("days"))) {
System.out.println("The second argument must be either minutes, hours or days. Was '" + arguments[1] + "'.");
System.out.println(USAGE);
return;
}
try {
// Get a long as the time to go back from the string
int time = Integer.parseInt(arguments[0]);
// Get the second argument as a TimeUnit
TimeUnit time_unit = TimeUnit.valueOf(arguments[1].toUpperCase());
// Get folder listing
File world_folder = new File(Reference.home_folder + File.separator + "backup" + File.separator + "worlds" + File.separator + Console.current_server.server_name + File.separator + new MinecraftServerProperties(new File(Console.current_server.server_dir + File.separator + "server.properties")).getValueOf("level-name"));
String[] world_list = world_folder.list();
// Create a calendar and remove a number of minutes based on our variables:
Calendar cal = Calendar.getInstance();
int time_in_minutes = (int) time_unit.toMinutes(time);
cal.add(Calendar.MINUTE, 0 - time_in_minutes);
// Get the ideal target world backup:
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HHmmss");
format.setTimeZone(cal.getTimeZone());
String target = format.format(cal.getTime());
Long[] numerical_world_list = new Long[world_list.length];
// Loop through our world backup list:
for (int i = 0; i < world_list.length; i++) {
if (world_list[i].equals(target)) {
// If it equals target, restore:
restoreWorld(target);
return;
}
// Parse this into an integer and add it to our int world list
numerical_world_list[i] = Long.parseLong(world_list[i].replace("_", ""));
}
// Get closest date tag:
Long intDateTag = getLongInArrayClosestToNewLong(numerical_world_list, Long.parseLong(target.replace("_", "")));
// Transform it into a string and re-add the underscore:
String stringDateTag = String.valueOf(intDateTag);
stringDateTag = new StringBuilder(stringDateTag).insert(8, "_").toString();
// Restore:
restoreWorld(stringDateTag);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
private static void restoreWorld(String datetag) throws IOException, InterruptedException {
// Get JSON:
JSONObject backup_json = (JSONObject) ((JSONObject) Console.current_server.server_json.get("backup")).get("world-restore");
if (backup_json.get("start") != null) {
Event.parse(Console.current_server, backup_json.get("start").toString());
} else {
Console.current_server.passCommand("say Server will restart to complete world restore in 30 seconds.");
}
if (backup_json.get("time") != null) {
Thread.sleep((long) backup_json.get("time") * 1000);
} else {
Thread.sleep(30 * 1000);
}
// Stop the server
Console.current_server.passCommand("stop");
while (Console.current_server.server_thread.isAlive()) {
Thread.sleep(500);
};
// Replace the world:
String world = new MinecraftServerProperties(new File(Console.current_server.server_dir + File.separator + "server.properties")).getValueOf("level-name");
FileUtils.deleteDirectory(new File(Console.current_server.server_dir + File.separator + world));
FileUtils.copyDirectory(new File(Reference.home_folder + File.separator + "backup" + File.separator + "worlds" + File.separator + Console.current_server.server_name + File.separator + world + File.separator + datetag), new File(Console.current_server.server_dir + File.separator + world));
// Start the server (selecting a dead server with true restarts it and hides the restart messages):
Activity.selectServer(Console.current_server.server_id, true);
if (backup_json != null) {
Event.parse(Console.current_server, backup_json.get("end").toString());
}
System.out.println("Restored world " + world + " from backup " + datetag + " succesfully.");
}
private static long getLongInArrayClosestToNewLong(Long[] numerical_world_list, long myNumber) {
long distance = Math.abs(numerical_world_list[0] - myNumber);
int idx = 0;
for(int c = 1; c < numerical_world_list.length; c++){
long cdistance = Math.abs(numerical_world_list[c] - myNumber);
if(cdistance < distance){
idx = c;
distance = cdistance;
}
}
return numerical_world_list[idx];
}
}