package in.twizmwaz.cardinal.rotation;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import in.twizmwaz.cardinal.Cardinal;
import in.twizmwaz.cardinal.rotation.exception.RotationLoadException;
import in.twizmwaz.cardinal.util.Contributor;
import in.twizmwaz.cardinal.util.DomUtils;
import in.twizmwaz.cardinal.util.MojangUtils;
import in.twizmwaz.cardinal.util.NumUtils;
import in.twizmwaz.cardinal.util.WebUtils;
import org.apache.commons.io.Charsets;
import org.bukkit.Bukkit;
import org.jdom2.Document;
import org.jdom2.Element;
import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.util.*;
import java.util.logging.Level;
public class Rotation {
private File rotationFile;
private boolean isOnlineRotation;
private List<LoadedMap> rotation;
private List<LoadedMap> loaded;
private int position;
private File repo;
public Rotation() throws RotationLoadException {
if (Cardinal.getInstance().getConfig().getBoolean("rotation.online") && Cardinal.getInstance().getConfig().getString("rotation.url").toLowerCase().startsWith("http")) {
isOnlineRotation = true;
}
this.rotationFile = new File(Cardinal.getInstance().getConfig().getString("rotation.file"));
refreshRepo();
refreshRotation();
}
/**
* Refreshes the maps in the repository and the data associated with them
*
* @throws RotationLoadException
*/
public void refreshRepo() throws RotationLoadException {
loaded = new ArrayList<>();
this.repo = new File(Cardinal.getInstance().getConfig().getString("repo"));
List<String> requirements = Arrays.asList("map.xml", "region", "level.dat");
for (File map : repo.listFiles()) {
if (map.isFile()) continue;
if (Arrays.asList(map.list()).containsAll(requirements)) {
try {
Document xml = DomUtils.parse(new File(map.getPath() + "/map.xml"));
String name = xml.getRootElement().getChild("name").getText();
String version = xml.getRootElement().getChild("version").getText();
String objective = xml.getRootElement().getChild("objective").getText();
List<Contributor> authors = new ArrayList<>();
for (Element authorsElement : xml.getRootElement().getChildren("authors")) {
for (Element author : authorsElement.getChildren()) {
authors.add(parseContributor(author));
}
}
List<Contributor> contributors = new ArrayList<>();
for (Element contributorsElement : xml.getRootElement().getChildren("contributors")) {
for (Element contributor : contributorsElement.getChildren()) {
contributors.add(parseContributor(contributor));
}
}
List<String> rules = new ArrayList<>();
for (Element rulesElement : xml.getRootElement().getChildren("rules")) {
for (Element rule : rulesElement.getChildren()) {
rules.add(rule.getText().trim());
}
}
int maxPlayers = 0;
for (Element teams : xml.getRootElement().getChildren("teams")) {
for (Element team : teams.getChildren()) {
maxPlayers = maxPlayers + NumUtils.parseInt(team.getAttributeValue("max"));
}
}
loaded.add(new LoadedMap(name, version, objective, authors, contributors, rules, maxPlayers, map));
} catch (Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Failed to load map at " + map.getAbsolutePath());
if (Cardinal.getInstance().getConfig().getBoolean("displayMapLoadErrors")) {
Bukkit.getLogger().log(Level.INFO, "Showing error, this can be disabled in the config: ");
e.printStackTrace();
}
}
}
}
try {
updatePlayers();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* Refreshes the plugin's default rotation
*/
public void refreshRotation() {
rotation = new ArrayList<>();
try {
if (!rotationFile.exists() && !isOnlineRotation) {
List<String> maps = Lists.newArrayList();
for (LoadedMap map : loaded) maps.add(map.getName());
FileWriter writer = new FileWriter(rotationFile);
for (String map : maps) writer.write(map + System.lineSeparator());
writer.close();
}
if (isOnlineRotation) {
WebUtils.readURLAndSaveToFile(new URL(Cardinal.getInstance().getConfig().getString("rotation.url")), rotationFile);
}
List<String> lines = Files.readAllLines(rotationFile.toPath(), Charsets.UTF_8);
for (String line : lines) {
for (LoadedMap map : loaded) {
if (map.getName().replaceAll(" ", "").equalsIgnoreCase(line.replaceAll(" ", ""))) {
rotation.add(map);
break;
}
}
}
} catch (IOException e) {
List<String> lines = new ArrayList<>();
for (int x = 0; x < 8; x++) {
try {
rotation.add(loaded.get(x));
} catch (IndexOutOfBoundsException ex) {
}
}
Bukkit.getLogger().log(Level.WARNING, "Failed to load rotation file, using a temporary rotation instead.");
}
position = 0;
}
/**
* Move the position in the rotation by one. If the end of the rotation is reached, it will be automatically reset.
*/
public int move() {
position++;
if (position > rotation.size() - 1) {
position = 0;
}
return position;
}
/**
* @return Returns the next map in the rotation
*/
public LoadedMap getNext() {
return rotation.get(position);
}
/**
* @return Returns the rotation
*/
public List<LoadedMap> getRotation() {
return rotation;
}
/**
* @return Returns all loaded maps
*/
public List<LoadedMap> getLoaded() {
return loaded;
}
/**
* @return Gets the rotation index of the next map
*/
public int getNextIndex() {
return position;
}
/**
* @param string The name of map to be searched for
* @return The map
*/
public LoadedMap getMap(String string) {
for (LoadedMap map : loaded) {
if (map.getName().toLowerCase().startsWith(string.toLowerCase())) return map;
}
return null;
}
public LoadedMap getCurrent() {
try {
return rotation.get(position - 1);
} catch (IndexOutOfBoundsException e) {
return rotation.get(0);
}
}
private Contributor parseContributor(Element element) {
if (element.getAttributeValue("uuid") != null) {
return new Contributor(UUID.fromString(element.getAttributeValue("uuid")), element.getAttributeValue("contribution"));
} else return new Contributor(element.getText(), element.getAttributeValue("contribution"));
}
@SuppressWarnings("unchecked")
private void updatePlayers() throws IOException, ClassNotFoundException {
HashMap<UUID, String> names;
try {
names = (HashMap<UUID, String>) new ObjectInputStream(new FileInputStream(new File(Cardinal.getInstance().getDataFolder().getPath() + ".names.ser"))).readObject();
} catch (FileNotFoundException e) {
names = Maps.newHashMap();
}
for (LoadedMap map : loaded) {
for (Contributor contributor : map.getAuthors()) {
if (contributor.getName() == null) {
String localName = Bukkit.getOfflinePlayer(contributor.getUniqueId()).getName();
if (localName != null) {
contributor.setName(localName);
} else if (names.containsKey(contributor.getUniqueId())) {
contributor.setName(names.get(contributor.getUniqueId()));
} else {
names.put(contributor.getUniqueId(), MojangUtils.getNameByUUID(contributor.getUniqueId()));
contributor.setName(names.get(contributor.getUniqueId()));
}
}
}
for (Contributor contributor : map.getContributors()) {
if (contributor.getName() == null) {
String localName = Bukkit.getOfflinePlayer(contributor.getUniqueId()).getName();
if (localName != null) {
contributor.setName(localName);
} else if (names.containsKey(contributor.getUniqueId())) {
contributor.setName(names.get(contributor.getUniqueId()));
} else {
names.put(contributor.getUniqueId(), MojangUtils.getNameByUUID(contributor.getUniqueId()));
contributor.setName(names.get(contributor.getUniqueId()));
}
}
}
}
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(Cardinal.getInstance().getDataFolder().getPath() + "/.names.ser")));
out.writeObject(names);
out.close();
}
}