package com.forgeessentials.data.v2;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.forgeessentials.data.v2.types.ItemStackType;
import com.forgeessentials.data.v2.types.NBTTagCompoundType;
import com.forgeessentials.data.v2.types.UserIdentType;
import com.forgeessentials.util.output.LoggingHandler;
import com.google.common.base.Throwables;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializer;
import com.google.gson.annotations.Expose;
public class DataManager implements ExclusionStrategy
{
public static interface DataType<T> extends JsonSerializer<T>, JsonDeserializer<T>
{
Class<T> getType();
}
private static DataManager instance;
private static Gson gson;
private static Map<Class<?>, JsonSerializer<?>> serializers = new HashMap<>();
private static Map<Class<?>, JsonDeserializer<?>> deserializers = new HashMap<>();
private static boolean formatsChanged;
private File basePath;
static
{
addDataType(new UserIdentType());
addDataType(new ItemStackType());
addDataType(new NBTTagCompoundType());
}
public DataManager(File basePath)
{
this.basePath = basePath;
}
public static DataManager getInstance()
{
if (instance == null)
throw new RuntimeException("Tried to access DataManager before its initialization");
return instance;
}
public static void setInstance(DataManager instance)
{
DataManager.instance = instance;
}
public static void addDataType(DataType<?> type)
{
serializers.put(type.getType(), type);
deserializers.put(type.getType(), type);
formatsChanged = true;
}
public static <T> void addSerializer(Class<T> clazz, JsonSerializer<T> type)
{
serializers.put(clazz, type);
formatsChanged = true;
}
public static <T> void addDeserializer(Class<T> clazz, JsonDeserializer<T> type)
{
deserializers.put(clazz, type);
formatsChanged = true;
}
public void save(Object src, String key)
{
try (FileWriter out = new FileWriter(getTypeFile(src.getClass(), key)))
{
getGson().toJson(src, out);
}
catch (Throwable e)
{
Throwables.propagate(e);
}
}
public void saveAll(Map<?, ?> dataMap)
{
for (Entry<?, ?> element : dataMap.entrySet())
save(element.getValue(), element.getKey().toString());
}
public boolean delete(Class<?> clazz, String key)
{
File file = getTypeFile(clazz, key);
return file.delete();
}
public boolean exists(Class<?> clazz, String key)
{
File file = getTypeFile(clazz, key);
return file.exists();
}
public <T> Map<String, T> loadAll(Class<T> clazz)
{
File[] files = getTypePath(clazz).listFiles();
Map<String, T> objects = new HashMap<>();
if (files != null)
for (File file : files)
if (!file.isDirectory() && file.getName().endsWith(".json"))
{
String key = file.getName().replace(".json", "");
T o = load(clazz, key);
if (o != null)
objects.put(key, o);
}
return objects;
}
public <T> T load(Class<T> clazz, String key)
{
File file = getTypeFile(clazz, key);
if (!file.exists())
return null;
try (BufferedReader br = new BufferedReader(new FileReader(file)))
{
T obj = getGson().fromJson(br, clazz);
if (obj instanceof Loadable)
((Loadable) obj).afterLoad();
return obj;
}
catch (JsonParseException e)
{
LoggingHandler.felog.error(String.format("Error parsing data file \"%s\"", file.getAbsolutePath()));
e.printStackTrace();
}
catch (IOException e)
{
LoggingHandler.felog.error(String.format("Error loading data file \"%s\"", file.getAbsolutePath()));
e.printStackTrace();
}
return null;
}
public <T> T load(Type type, String key)
{
File file = getTypeFile(type.getClass(), key);
if (!file.exists())
return null;
try (BufferedReader br = new BufferedReader(new FileReader(file)))
{
return getGson().fromJson(br, type);
}
catch (JsonParseException e)
{
LoggingHandler.felog.error(String.format("Error parsing data file \"%s\"", file.getAbsolutePath()));
e.printStackTrace();
}
catch (IOException e)
{
LoggingHandler.felog.error(String.format("Error loading data file \"%s\"", file.getAbsolutePath()));
e.printStackTrace();
}
return null;
}
@Override
public boolean shouldSkipField(FieldAttributes f)
{
Expose expose = f.getAnnotation(Expose.class);
if (expose != null && (!expose.serialize() || !expose.deserialize()))
return true;
return false;
}
@Override
public boolean shouldSkipClass(Class<?> clazz)
{
return false;
}
public Gson getGson()
{
if (gson == null || formatsChanged)
{
GsonBuilder builder = new GsonBuilder();
builder.setPrettyPrinting();
builder.setExclusionStrategies(this);
for (Entry<Class<?>, JsonSerializer<?>> format : serializers.entrySet())
builder.registerTypeAdapter(format.getKey(), format.getValue());
for (Entry<Class<?>, JsonDeserializer<?>> format : deserializers.entrySet())
builder.registerTypeAdapter(format.getKey(), format.getValue());
gson = builder.create();
}
return gson;
}
private File getTypePath(Class<?> clazz)
{
File path = new File(basePath, clazz.getSimpleName());
path.mkdirs();
return path;
}
private File getTypeFile(Class<?> clazz, String key)
{
return new File(getTypePath(clazz), key + ".json");
}
}