/*******************************************************************************
* AbyssalCraft
* Copyright (c) 2012 - 2017 Shinoow.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* Contributors:
* Shinoow - implementation
******************************************************************************/
package com.shinoow.abyssalcraft.lib.util;
import java.io.File;
import java.io.FileReader;
import java.util.Map.Entry;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.translation.I18n;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.logging.log4j.Level;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.shinoow.abyssalcraft.api.necronomicon.CraftingStack;
import com.shinoow.abyssalcraft.api.necronomicon.NecroData;
import com.shinoow.abyssalcraft.api.necronomicon.NecroData.Chapter;
import com.shinoow.abyssalcraft.api.necronomicon.NecroData.Page;
/**
* Utility class used to convert NecroData to/from Json
* @author shinoow
*
*/
public class NecroDataJsonUtil {
/**
* Converts a NecroData instance into a Json Object
* @param data NecroData to convert
* @return A Json Object
*/
public static JsonObject serializeNecroData(NecroData data){
JsonObject json = new JsonObject();
json.addProperty("type", "necrodata");
json.addProperty("version", 1);
json.addProperty("identifier", data.getIdentifier());
json.addProperty("title", data.getTitle());
if(!Strings.isNullOrEmpty(data.getInformation()))
json.addProperty("information", data.getInformation());
JsonArray chapters = new JsonArray();
for(Chapter c : data.getChapters())
chapters.add(serializeChapter(c));
json.add("chapters", chapters);
return json;
}
/**
* Converts a Json Object into a NecroData instance
* @param json Json Object to convert
* @return A NecroData instance, or null if something went wrong
*/
public static NecroData deserializeNecroData(JsonObject json){
if(getString(json, "type").equals("necrodata") && getInteger(json, "version") <= 1){
String identifier = getString(json, "identifier");
String title = getString(json, "title");
String information = getString(json, "information");
JsonArray chapters = getArray(json, "chapters");
Chapter[] chaps = null;
if(chapters != null){
chaps = new Chapter[chapters.size()];
for(int i = 0; i < chapters.size(); i++){
JsonElement e = chapters.get(i);
if(e.isJsonObject()){
Chapter c = deserializeChapter(e.getAsJsonObject());
if(c != null)
chaps[i] = c;
}
}
}
if(chaps != null){
int num = 0;
for(Chapter c : chaps)
if(c != null) num++;
if(num < chaps.length){
Chapter[] newchap = new Chapter[num];
int newIndex = 0;
for(int i = 0; i < chaps.length; i++)
if(chaps[i] != null){
newchap[newIndex] = chaps[i];
newIndex++;
}
chaps = newchap;
}
return new NecroData(identifier, title, information.length() == 0 ? null : information, chaps);
}
}
return null;
}
/**
* Converts a Chapter into a Json Object
* @param chap Chapter to convert
* @return A Json Object
*/
public static JsonObject serializeChapter(Chapter chap){
JsonObject json = new JsonObject();
json.addProperty("type", "chapter");
json.addProperty("version", 1);
json.addProperty("identifier", chap.getIdentifier());
json.addProperty("title", chap.getTitle());
JsonArray pages = new JsonArray();
for(Entry<Integer, Page> e : chap.getPages().entrySet())
pages.add(serializePage(e.getValue()));
json.add("pages", pages);
return json;
}
/**
* Converts a Json Object into a Chapter
* @param json Json Object to convert
* @return A Chapter, or null if the Json Object wasn't a Chapter
*/
public static Chapter deserializeChapter(JsonObject json){
if(getString(json, "type").equals("chapter") && getInteger(json, "version") <= 1){
String identifier = getString(json, "identifier");
String title = getString(json, "title");
Chapter chapter = new Chapter(identifier, I18n.translateToLocal(title));
JsonArray pages = getArray(json, "pages");
if(pages != null)
for(JsonElement e : pages)
if(e.isJsonObject()){
Page p = deserializePage(e.getAsJsonObject());
if(p != null)
chapter.addPage(p);
}
return chapter;
}
return null;
}
/**
* Converts a Page into a Json Object
* @param page Page to convert
* @return A Json Object
*/
public static JsonObject serializePage(Page page){
JsonObject json = new JsonObject();
json.addProperty("type", "page");
json.addProperty("version", 1);
json.addProperty("number", page.getPageNumber());
serializeIcon(json, page.getIcon());
json.addProperty("text", page.getText());
return json;
}
/**
* Converts a Json Object into a Page
* @param json Json Object to convert
* @return A Page, or null if the Json Object wasn't a Page
*/
public static Page deserializePage(JsonObject json){
if(getString(json, "type").equals("page") && getInteger(json, "version") <= 1){
int num = getInteger(json, "number");
Object icon = getIcon(json);
String text = getString(json, "text");
return new Page(num, icon, I18n.translateToLocal(text));
}
return null;
}
/**
* Serialize the display icon of a Page
* @param json Json Object to add the data to
* @param icon An Object representing the icon
*/
private static void serializeIcon(JsonObject json, Object icon){
if(icon == null) return;
if(!(icon instanceof ResourceLocation) && !(icon instanceof ItemStack) && !(icon instanceof CraftingStack)) return;
if(icon instanceof ResourceLocation){
json.addProperty("icontype", "resourcelocation");
json.addProperty("icon", icon.toString());
}
else if(icon instanceof ItemStack){
json.addProperty("icontype", "itemstack");
json.addProperty("icon", stackToString((ItemStack)icon));
}
else if(icon instanceof CraftingStack){
json.addProperty("icontype", "craftingstack");
JsonArray stuff = new JsonArray();
stuff.add(new JsonPrimitive(outputStackToString(((CraftingStack) icon).getOutput())));
for(ItemStack stack : ((CraftingStack) icon).getCraftingRecipe())
stuff.add(new JsonPrimitive(stackToString(stack)));
json.add("icon", stuff);
}
else if(icon instanceof String){
json.addProperty("icontype", "url");
json.addProperty("icon", (String)icon);
}
}
/**
* Converts an ItemStack to a String
* @param stack ItemStack to convert
* @return A String representing the contents of the ItemStack (excluding size), or an empty string
*/
private static String stackToString(ItemStack stack){
if(stack == null || stack.getItem() == null) return "";
return stack.getItem().getRegistryName() + (stack.getItemDamage() > 0 ? ":" + stack.getItemDamage() : "");
}
/**
* Converts the CraftingStack output ItemStack to a String
* @param stack ItemStack to convert
* @return A String representing the contents of the ItemStack, or an empty string
*/
private static String outputStackToString(ItemStack stack){
if(stack == null || stack.getItem() == null) return "";
return stack.getItem().getRegistryName() + ":" + stack.getCount() + (stack.getItemDamage() > 0 ? ":" + stack.getItemDamage() : "");
}
/**
* Fetches a String from a Json Object (if one is stored)
* @param json Json Object
* @param id Variable Name
* @return A String value, or an empty String
*/
private static String getString(JsonObject json, String id){
if(json == null) return "";
if(json.has(id) && json.get(id).isJsonPrimitive() && json.get(id).getAsJsonPrimitive().isString())
return json.get(id).getAsString();
else return "";
}
/**
* Fetches a String value from a Json Element
* @param json Json Element
* @return A String value, or an empty String
*/
private static String getStringValue(JsonElement json){
if(json == null) return "";
if(json.isJsonPrimitive() && json.getAsJsonPrimitive().isString())
return json.getAsString();
else return "";
}
/**
* Fetches an Integer from a Json Object (if one is stored)
* @param json Json Object
* @param id Variable Name
* @return A Integer value, or 0
*/
public static int getInteger(JsonObject json, String id){
if(json == null) return 0;
if(json.has(id) && json.get(id).isJsonPrimitive() && json.get(id).getAsJsonPrimitive().isNumber())
return json.get(id).getAsInt();
else return 0;
}
/**
* Fetches a Json Array from a Json Object (if one is stored)
* @param json Json Object
* @param id Variable Name
* @return A Json Array, or null
*/
private static JsonArray getArray(JsonObject json, String id){
if(json == null) return null;
if(json.has(id) && json.get(id).isJsonArray())
return json.get(id).getAsJsonArray();
else return null;
}
/**
* Fetches a display icon from the Json Object representing a Page
* @param json Json Object
* @return Either the appropriate Object, or null if none was found
*/
private static Object getIcon(JsonObject json){
if(json == null) return null;
String type = getString(json, "icontype");
if(type.length() == 0) return null;
if(type.equals("resourcelocation"))
return new ResourceLocation(getString(json, "icon"));
else if(type.equals("itemstack"))
return getStack(getString(json, "icon"));
else if(type.equals("craftingstack"))
return getCStack(getArray(json, "icon"));
else if(type.equals("url"))
return getString(json, "icon");
return null;
}
/**
* Fetches an ItemStack from a String value
* @param str String value
* @return An ItemStack, or null if the Item was invalid
*/
private static ItemStack getStack(String str){
if(Strings.isNullOrEmpty(str)) return null;
String[] stuff = str.split(":");
Item item = Item.REGISTRY.getObject(new ResourceLocation(stuff[0], stuff[1]));
if(item != null)
return new ItemStack(item, 1, stuff.length == 3 ? Integer.valueOf(stuff[2]) : 0);
return null;
}
/**
* Fetches the CraftingStack output ItemStack from a String value
* @param str String value
* @return An ItemStack, or null if the Item was invalid
*/
private static ItemStack getOutputStack(String str){
if(Strings.isNullOrEmpty(str)) return null;
String[] stuff = str.split(":");
Item item = Item.REGISTRY.getObject(new ResourceLocation(stuff[0], stuff[1]));
if(item != null)
return new ItemStack(item, Integer.valueOf(stuff[2]), stuff.length == 4 ? Integer.valueOf(stuff[3]) : 0);
return null;
}
/**
* Creates a CraftingStack based on a Json Array
* @param array Json Array to fetch data from
* @return A CraftingStack, or null if the output was null
*/
private static CraftingStack getCStack(JsonArray array){
if(array == null) return null;
ItemStack output = getOutputStack(getStringValue(array.get(0)));
ItemStack[] recipe = new ItemStack[9];
for(int i = 1; i < 10; i++)
recipe[i-1] = getStack(getStringValue(array.get(i)));
if(output != null)
return new CraftingStack(output, (Object[])recipe);
return null;
}
/**
* Attempts to find a NecroData Json from a file
* @param file File to read from
* @return A Json Object containing a NecroData instance if it succeeded, otherwise null
*/
public static JsonObject readNecroDataJsonFromFile(File file){
if(!file.exists())
return null;
try {
FileReader fr = new FileReader(file);
JsonObject json = new Gson().fromJson(fr, JsonObject.class);
fr.close();
return json;
} catch (Exception e) {
FMLLog.log("AbyssalCraft", Level.ERROR, "Failed to read JSON file: %s", file.toString());
e.printStackTrace();
return null;
}
}
}