/*
 * Caveworld
 *
 * Copyright (c) 2014 kegare
 * https://github.com/kegare
 *
 * This mod is distributed under the terms of the Minecraft Mod Public License 1.0, or MMPL.
 * Please check the contents of the license located in http://www.mod-buildcraft.com/MMPL-1.0.txt
 */

package com.kegare.caveworld.plugin.mceconomy;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;

import mceconomy.api.MCEconomyAPI;
import mceconomy.api.shop.IProductItem;
import mceconomy.api.shop.IProductList;
import mceconomy.api.shop.ProductItem;
import mceconomy.api.shop.ProductList;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.StrBuilder;

import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.io.Files;
import com.google.common.io.LineProcessor;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.kegare.caveworld.block.CaveBlock;
import com.kegare.caveworld.core.Config;
import com.kegare.caveworld.plugin.CaveModPlugin;
import com.kegare.caveworld.util.CaveLog;

public class MCEconomyPlugin extends CaveModPlugin
{
	public static boolean MCECONOMY = false;
	public static int MINERS_SHOP = -1;

	private final IProductList shopProductList = new ProductList()
	{
		@Override
		public String getProductListName()
		{
			return "Miner's Shop";
		}
	};

	public MCEconomyPlugin()
	{
		super("MCEconomy");
	}

	@Override
	protected void init()
	{
		MCECONOMY = true;

		MCEconomyAPI.addPurchaseItem(new ItemStack(CaveBlock.portalCaveworld), 2000);

		if (CaveBlock.rope != null)
		{
			MCEconomyAPI.addPurchaseItem(new ItemStack(CaveBlock.rope), 2);
		}

		MINERS_SHOP = MCEconomyAPI.registerProductList(shopProductList);

		loadProductItems();
	}

	private void initProductItems()
	{
		shopProductList.getProductList().clear();

		if (Config.hardcoreEnabled)
		{
			shopProductList.addItemProduct(new ProductItem(new ItemStack(Item.bread, 6), 30));
			shopProductList.addItemProduct(new ProductItem(new ItemStack(Block.sapling, 1, 0), 15));
			shopProductList.addItemProduct(new ProductItem(new ItemStack(Block.sapling, 1, 1), 15));
			shopProductList.addItemProduct(new ProductItem(new ItemStack(Block.sapling, 1, 2), 15));
			shopProductList.addItemProduct(new ProductItem(new ItemStack(Block.sapling, 1, 3), 15));
			shopProductList.addItemProduct(new ProductItem(new ItemStack(Item.seeds, 10), 10));
			shopProductList.addItemProduct(new ProductItem(new ItemStack(Item.bed), 100));
		}

		shopProductList.addItemProduct(new ProductItem(new ItemStack(Block.torchWood, 64), 50));
		shopProductList.addItemProduct(new ProductItem(new ItemStack(Item.swordIron), 100));
		shopProductList.addItemProduct(new ProductItem(new ItemStack(Item.pickaxeIron), 150));
		shopProductList.addItemProduct(new ProductItem(new ItemStack(Item.axeIron), 150));
		shopProductList.addItemProduct(new ProductItem(new ItemStack(Item.shovelIron), 50));
		shopProductList.addItemProduct(new ProductItem(new ItemStack(Item.hoeIron), 100));

		if (CaveBlock.rope != null)
		{
			shopProductList.addItemProduct(new ProductItem(new ItemStack(CaveBlock.rope, 5), 10));
		}
	}

	private boolean loadProductItems()
	{
		File file = Config.getConfigFile("shop");

		try
		{
			if (file.exists() && file.canRead())
			{
				String data = Files.readLines(file, Charsets.US_ASCII, new LineProcessor<String>()
				{
					private final StringBuilder builder = new StringBuilder();

					@Override
					public boolean processLine(String line) throws IOException
					{
						if (!Strings.isNullOrEmpty(line))
						{
							line = StringUtils.deleteWhitespace(line);

							if (!line.startsWith("#"))
							{
								builder.append(line);
							}
						}

						return true;
					}

					@Override
					public String getResult()
					{
						return builder.toString();
					}
				});

				if (!Strings.isNullOrEmpty(data) && loadProductItemsFromString(data))
				{
					return true;
				}
			}

			initProductItems();

			return shopProductList.getItemProductSize() > 0;
		}
		catch (Exception e)
		{
			if (shopProductList.getItemProductSize() <= 0)
			{
				initProductItems();
			}

			File dest = new File(file.getParentFile(), file.getName() + ".bak");

			if (dest.exists())
			{
				dest.delete();
			}

			file.renameTo(dest);

			CaveLog.log(Level.SEVERE, e, "A critical error occured reading the " + file.getName() + " file, defaults will be used - the invalid file is backed up at " + dest.getName());
		}
		finally
		{
			CaveLog.info("Loaded %d %s product items", shopProductList.getItemProductSize(), shopProductList.getProductListName());

			saveProductItems();
		}

		return false;
	}

	private boolean loadProductItemsFromString(String data)
	{
		List<Map<String, Object>> json = new Gson().fromJson(data, new TypeToken<List<Map<String, Object>>>(){}.getType());

		for (Map<String, Object> entry : json)
		{
			if (!entry.containsKey("itemID") || !entry.containsKey("productCost"))
			{
				continue;
			}

			Item item = Item.itemsList[((Number)entry.get("itemID")).intValue()];
			int damage = entry.containsKey("itemDamage") ? ((Number)entry.get("itemDamage")).intValue() : 0;
			int size = entry.containsKey("itemStackSize") ? ((Number)entry.get("itemStackSize")).intValue() : 1;
			int cost = ((Number)entry.get("productCost")).intValue();

			if (item == null || size <= 0 || cost <= 0)
			{
				continue;
			}

			shopProductList.addItemProduct(new ProductItem(new ItemStack(item, size, damage), cost));
		}

		return shopProductList.getItemProductSize() > 0;
	}

	private boolean saveProductItems()
	{
		try
		{
			File file = Config.getConfigFile("shop");
			String dest = null;

			if (file.exists() && file.canRead())
			{
				dest = FileUtils.readFileToString(file);
			}

			StrBuilder builder = new StrBuilder(dest == null ? 2048 : dest.length());

			builder.append("# Configuration file - ").append(shopProductList.getProductListName()).appendln(" product items");
			builder.appendNewLine();
			builder.appendln('[');

			for (Iterator<IProductItem> products = shopProductList.getProductList().iterator(); products.hasNext();)
			{
				IProductItem product = products.next();
				ItemStack item = product.getProductItem();

				builder.appendln("  {");
				builder.append("    \"itemID\": ").append(item.itemID).appendln(',');

				if (item.getItemDamage() != 0)
				{
					builder.append("    \"itemDamage\": ").append(item.getItemDamage()).appendln(',');
				}

				if (item.stackSize > 1)
				{
					builder.append("    \"itemStackSize\": ").append(item.stackSize).appendln(',');
				}

				builder.append("    \"productCost\": ").appendln(product.getcost());
				builder.append("  }");

				if (products.hasNext())
				{
					builder.append(',');
				}

				builder.appendNewLine();
			}

			String data = builder.append(']').toString();

			if (dest != null && data.equals(dest))
			{
				return false;
			}

			FileUtils.writeStringToFile(file, data);

			return true;
		}
		catch (Exception e)
		{
			CaveLog.log(Level.SEVERE, e, "An error occurred trying to saving %s product items", shopProductList.getProductListName());
		}

		return false;
	}
}