package com.zpig333.runesofwizardry.util.json;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagByte;
import net.minecraft.nbt.NBTTagByteArray;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagDouble;
import net.minecraft.nbt.NBTTagEnd;
import net.minecraft.nbt.NBTTagFloat;
import net.minecraft.nbt.NBTTagInt;
import net.minecraft.nbt.NBTTagIntArray;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagLong;
import net.minecraft.nbt.NBTTagShort;
import net.minecraft.nbt.NBTTagString;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import org.apache.logging.log4j.Level;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.zpig333.runesofwizardry.core.WizardryLogger;
/**
* Converts a NBTTagCompound to and from a JsonObject
* @author Xilef11
*
*/
public class NBTJson implements JsonDeserializer<NBTTagCompound>, JsonSerializer<NBTTagCompound> {
@Override
public JsonElement serialize(NBTTagCompound src, Type typeOfSrc,JsonSerializationContext context) {
JsonObject object = new JsonObject();
JsonObject tagMap = new JsonObject();
//XXX recheck the names when updating Forge version
Map<?, ?> map = ReflectionHelper.getPrivateValue(NBTTagCompound.class,src,"tagMap","field_74784_a");
for(Map.Entry<?,?> e: map.entrySet()){
//if(o instanceof Map.Entry){
//Map.Entry e = (Map.Entry)o;
//key is String, value is NBTBase
JsonObject tag = new JsonObject();
String key = (String)e.getKey();
NBTBase val = (NBTBase)e.getValue();
byte type = val.getId();
tag.addProperty("type", type);
JsonElement value = context.serialize(val);
tag.add("tag",value);
tagMap.add(key, tag);
//}
}
object.add("tagMap", tagMap);
return object;
}
@Override
public NBTTagCompound deserialize(JsonElement json, Type typeOfT,JsonDeserializationContext context) throws JsonParseException {
NBTTagCompound tagCompound = new NBTTagCompound();
JsonObject map = json.getAsJsonObject().get("tagMap").getAsJsonObject();
for(Map.Entry<String,JsonElement> e : map.entrySet()){
String key = e.getKey();
JsonObject tag = e.getValue().getAsJsonObject();
byte type = tag.get("type").getAsByte();
JsonElement val = tag.get("tag");
NBTBase value;
try {
value = deserializewithReflection(type, tag, context);
} catch (Exception e1) {
WizardryLogger.logException(Level.ERROR, e1, "Could not deserialize NBT using reflection");
value = deserializeType(type, val, context);
}
tagCompound.setTag(key, value);
}
return tagCompound;
}
private NBTBase deserializeType(byte type, JsonElement tag, JsonDeserializationContext context){
NBTBase value;
//there may be a better way
switch(type){
case 0:
value= context.deserialize(tag, NBTTagEnd.class);
break;
case 1:
value = context.deserialize(tag, NBTTagByte.class);
break;
case 2:
value = context.deserialize(tag, NBTTagShort.class);
break;
case 3:
value = context.deserialize(tag, NBTTagInt.class);
break;
case 4:
value = context.deserialize(tag, NBTTagLong.class);
break;
case 5:
value = context.deserialize(tag, NBTTagFloat.class);
break;
case 6:
value = context.deserialize(tag, NBTTagDouble.class);
break;
case 7:
value = context.deserialize(tag, NBTTagByteArray.class);
break;
case 8:
value = context.deserialize(tag, NBTTagString.class);
break;
case 9:
value = context.deserialize(tag, NBTTagList.class);
break;
case 10:
value = context.deserialize(tag, NBTTagCompound.class);
break;
case 11:
value = context.deserialize(tag, NBTTagIntArray.class);
break;
default: value = context.deserialize(tag, NBTBase.class);
}
return value;
}
private NBTBase deserializewithReflection(byte type, JsonElement tag, JsonDeserializationContext context) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//Method create = ReflectionHelper.findMethod(NBTBase.class, null, new String[]{"createNewByType","func_150284_a"}, NBTBase.class);
Method create = ReflectionHelper.findMethod(NBTBase.class, "createNewByType","func_150284_a", NBTBase.class);
Class<?> nbtClass = null;
nbtClass = create.invoke(null, type).getClass();
return context.deserialize(tag, nbtClass);
}
}