package com.forgeessentials.permissions.persistence;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.forgeessentials.api.UserIdent;
import com.forgeessentials.api.permissions.AreaZone;
import com.forgeessentials.api.permissions.FEPermissions;
import com.forgeessentials.api.permissions.GroupEntry;
import com.forgeessentials.api.permissions.ServerZone;
import com.forgeessentials.api.permissions.WorldZone;
import com.forgeessentials.api.permissions.Zone;
import com.forgeessentials.api.permissions.Zone.PermissionList;
import com.forgeessentials.commons.selections.AreaBase;
import com.forgeessentials.commons.selections.AreaShape;
import com.forgeessentials.permissions.core.ZonePersistenceProvider;
import com.forgeessentials.util.output.LoggingHandler;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class JsonProvider extends ZonePersistenceProvider
{
private File path;
private Gson gson;
public JsonProvider(File path)
{
this.path = new File(path, "/Permissions");
gson = new GsonBuilder().disableHtmlEscaping().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().create();
}
@Override
public ServerZone load()
{
ServerZone serverZone = new ServerZone();
loadGroups(serverZone);
loadUsers(serverZone);
loadWorlds(serverZone);
return serverZone;
}
private void loadGroups(ServerZone serverZone)
{
GroupsData groupsData = null;
try
{
BufferedReader reader = new BufferedReader(new FileReader(path + "/groups.json"));
groupsData = gson.fromJson(reader, GroupsData.class);
}
catch (IOException e)
{
LoggingHandler.felog.error("Could not load groups data: " + e.getMessage());
return;
}
for (String group : groupsData.groups.keySet())
{
GroupData groupData = groupsData.groups.get(group);
PermissionList list = PermissionList.fromList(groupData.permissions);
list.put(FEPermissions.PREFIX, groupData.prefix);
list.put(FEPermissions.SUFFIX, groupData.suffix);
list.put(FEPermissions.GROUP_PRIORITY, Integer.toString(groupData.priority));
list.put(FEPermissions.GROUP, Zone.PERMISSION_TRUE);
if (groupData.Default)
{
list.put("fe.internal.group.default", Zone.PERMISSION_TRUE);
}
serverZone.getOrCreateGroupPermissions(group).putAll(list);
}
}
private void loadUsers(ServerZone serverZone)
{
UsersData usersData = null;
try
{
BufferedReader reader = new BufferedReader(new FileReader(path + "/users.json"));
usersData = gson.fromJson(reader, UsersData.class);
}
catch (IOException e)
{
LoggingHandler.felog.error("Could not load groups data: " + e.getMessage());
return;
}
for (String uuid : usersData.users.keySet())
{
UserData userData = usersData.users.get(uuid);
UserIdent ident = UserIdent.get(uuid, userData.username);
PermissionList list = PermissionList.fromList(userData.permissions);
list.put(FEPermissions.PREFIX, userData.prefix);
list.put(FEPermissions.SUFFIX, userData.suffix);
serverZone.getOrCreatePlayerPermissions(ident).putAll(list);
for (String group : userData.groups)
{
serverZone.addPlayerToGroup(ident, group);
}
}
}
private void loadWorlds(ServerZone serverZone)
{
List<File> files = new ArrayList<File>();
Path p = FileSystems.getDefault().getPath(path.getAbsolutePath());
try (DirectoryStream<Path> ds = Files.newDirectoryStream(p, "world_*.json"))
{
for (Path p2 : ds)
{
files.add(p2.toFile());
}
}
catch (IOException e)
{
LoggingHandler.felog.error("Failed to get list of world files: " + e.getMessage());
}
for (File file : files)
{
WorldZoneData wzd = null;
try
{
BufferedReader reader = new BufferedReader(new FileReader(file));
wzd = gson.fromJson(reader, WorldZoneData.class);
}
catch (IOException e)
{
LoggingHandler.felog.error(String.format("Failed to load world file &s: &s", file.getName(), e.getMessage()));
return;
}
WorldZone wz = new WorldZone(serverZone, wzd.dimId, wzd.id);
for (String group : wzd.groups.keySet())
{
wz.getGroupPermissions().put(group, PermissionList.fromList(wzd.groups.get(group).permissions));
}
for (String uuid : wzd.players.keySet())
{
wz.getPlayerPermissions().put(UserIdent.get(uuid, wzd.players.get(uuid).username), PermissionList.fromList(wzd.players.get(uuid).permissions));
}
for (AreaZoneData azd : wzd.zones)
{
AreaZone az = new AreaZone(wz, azd.name, azd.area, azd.id);
az.setHidden(azd.hidden);
az.setShape(azd.shape);
az.setPriority(azd.priority);
for (String group : azd.groups.keySet())
{
az.getGroupPermissions().put(group, PermissionList.fromList(azd.groups.get(group).permissions));
}
for (String uuid : azd.players.keySet())
{
az.getPlayerPermissions().put(UserIdent.get(uuid, azd.players.get(uuid).username),
PermissionList.fromList(azd.players.get(uuid).permissions));
}
}
}
}
@Override
public void save(ServerZone serverZone)
{
path.mkdirs();
saveGroups(serverZone);
saveUsers(serverZone);
saveWorlds(serverZone);
}
public void saveGroups(ServerZone zone)
{
GroupsData groupsData = new GroupsData();
groupsData.groups.putAll(getGroupDataMap(zone, zone.getGroups()));
String json = gson.toJson(groupsData);
try
{
FileWriter globalGroups = new FileWriter(new File(path + "/groups.json"));
globalGroups.write(json);
globalGroups.close();
}
catch (IOException e)
{
LoggingHandler.felog.error("Failed to save groups.json: " + e.getMessage());
}
}
public void saveUsers(ServerZone serverZone)
{
File newPath = new File(path + "/users.json");
UsersData usersData = new UsersData();
usersData.users.putAll(getUserDataMap(serverZone, serverZone.getPlayerGroups().keySet()));
String json = gson.toJson(usersData);
try
{
FileWriter writer = new FileWriter(newPath);
writer.write(json);
writer.close();
}
catch (IOException e)
{
LoggingHandler.felog.error("Failed to save users.json: " + e.getMessage());
}
}
public void saveWorlds(ServerZone serverZone)
{
for (Entry<Integer, WorldZone> wzEntry : serverZone.getWorldZones().entrySet())
{
Integer wzDimId = wzEntry.getKey();
WorldZone wz = wzEntry.getValue();
String pathName = String.format("/world_%d.json", wzDimId);
File newPath = new File(path + pathName);
WorldZoneData worldZoneData = new WorldZoneData(wz.getId(), wzDimId);
worldZoneData.groups.putAll(getGroupDataMap(wz, wz.getGroupPermissions().keySet()));
worldZoneData.players.putAll(getUserDataMap(wz, wz.getPlayerPermissions().keySet()));
for (AreaZone az : wz.getAreaZones())
{
AreaZoneData areaZoneData = new AreaZoneData(az.getId(), az.getPriority(), az.isHidden(), az.getName(), az.getArea(), az.getShape());
areaZoneData.groups.putAll(getGroupDataMap(az, az.getGroupPermissions().keySet()));
areaZoneData.players.putAll(getUserDataMap(az, az.getPlayerPermissions().keySet()));
worldZoneData.zones.add(areaZoneData);
}
String json = gson.toJson(worldZoneData);
try
{
FileWriter writer = new FileWriter(newPath);
writer.write(json);
writer.close();
}
catch (IOException e)
{
LoggingHandler.felog.error(String.format("Failed to save world_%d.json: %s", wzDimId, e.getMessage()));
}
}
}
// public void removeInternals(List<String> list)
// {
// ArrayList<String> remove = new ArrayList<String>();
// for(String perm : list)
// {
// if(perm.contains("fe.internal"))
// remove.add(perm);
// }
// list.removeAll(remove);
// }
private Map<String, GroupData> getGroupDataMap(Zone zone, Set<String> groups)
{
boolean global = zone instanceof ServerZone;
Map<String, GroupData> groupDataMap = new HashMap<String, GroupData>();
for (String group : groups)
{
PermissionList groupList = new PermissionList(zone.getGroupPermissions(group));
String prefix = groupList.remove(FEPermissions.PREFIX);
if (prefix == null)
prefix = "";
String suffix = groupList.remove(FEPermissions.SUFFIX);
if (suffix == null)
suffix = "";
Boolean Default = Boolean.getBoolean(groupList.remove("fe.internal.group.default"));
Integer priority = null;
String prioNode = groupList.remove(FEPermissions.GROUP_PRIORITY);
if (prioNode != null)
{
priority = Integer.parseInt(groupList.remove(FEPermissions.GROUP_PRIORITY));
}
groupList.remove(FEPermissions.GROUP);
if (!global)
{
prefix = null;
suffix = null;
priority = null;
Default = null;
}
List<String> list = groupList.toList();
GroupData groupData = new GroupData(prefix, suffix, Default, priority);
groupData.permissions.addAll(list);
groupDataMap.put(group, groupData);
}
return groupDataMap;
}
private Map<String, UserData> getUserDataMap(Zone zone, Set<UserIdent> users)
{
boolean global = zone instanceof ServerZone;
Map<String, UserData> userDataMap = new HashMap<String, UserData>();
for (UserIdent user : users)
{
String uuid = (user.getUuid() == null ? null : user.getUuid().toString());
String username = user.getUsername();
PermissionList permList = new PermissionList(zone.getPlayerPermissions(user));
String prefix = permList.remove(FEPermissions.PREFIX);
if (prefix == null)
prefix = "";
String suffix = permList.remove(FEPermissions.SUFFIX);
if (suffix == null)
suffix = "";
if (uuid == null)
{
uuid = user.getUsername();
username = null;
}
if (!global)
{
prefix = null;
suffix = null;
}
List<String> list = permList.toList();
UserData userData = new UserData(username, prefix, suffix);
userData.permissions.addAll(list);
if (global)
{
userData.groups.addAll(GroupEntry.toList(((ServerZone) zone).getPlayerGroups(user)));
}
else
{
userData.groups = null;
}
userDataMap.put(uuid, userData);
}
return userDataMap;
}
// helper classes
public static class GroupsData
{
public Map<String, GroupData> groups;
public GroupsData()
{
groups = new HashMap<String, GroupData>();
}
}
public static class GroupData
{
public String prefix;
public String suffix;
public Boolean Default;
public Integer priority;
public List<String> permissions;
public GroupData(String prefix, String suffix, Boolean Default, Integer priority)
{
this.prefix = prefix;
this.suffix = suffix;
this.Default = Default;
this.priority = priority;
permissions = new ArrayList<String>();
}
}
public static class GroupMembers
{
public String name;
public List<String> members;
public GroupMembers(String name)
{
this.name = name;
members = new ArrayList<String>();
}
}
public static class WorldZoneData
{
public int id, dimId;
public List<AreaZoneData> zones;
public Map<String, GroupData> groups;
public Map<String, UserData> players;
public WorldZoneData(int id, int dimId)
{
this.id = id;
groups = new HashMap<String, GroupData>();
players = new HashMap<String, UserData>();
zones = new ArrayList<AreaZoneData>();
}
}
public static class AreaZoneData
{
public int id;
public String name;
public boolean hidden;
public int priority;
public Map<String, GroupData> groups;
public Map<String, UserData> players;
public AreaBase area;
public AreaShape shape;
public AreaZoneData(int id, int priority, boolean hidden, String name, AreaBase area, AreaShape shape)
{
this.id = id;
this.priority = priority;
this.hidden = hidden;
this.name = name;
this.area = area;
this.shape = shape;
groups = new HashMap<String, GroupData>();
players = new HashMap<String, UserData>();
}
}
public static class UsersData
{
public Map<String, UserData> users;
public UsersData()
{
users = new HashMap<String, UserData>();
}
}
public static class UserData
{
public String username;
public String prefix;
public String suffix;
public List<String> groups;
public List<String> permissions;
public UserData(String username, String prefix, String suffix)
{
this.username = username;
this.prefix = prefix;
this.suffix = suffix;
groups = new ArrayList<String>();
permissions = new ArrayList<String>();
}
}
}