package net.minecraft.src;

import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Hashtable;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import net.minecraft.client.Minecraft;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 * MightyPork ❤ XML
 * 
 * @author MightyPork
 */
public class PCma_CropList {

	/**
	 * Call this method to explicitly init static fields
	 */
	public static void ping() {}

	/**
	 * Folder with the crops xml files
	 */
	private static final File folder = new File(Minecraft.getMinecraftDir() + "/config/PC_CROPS");

	/** hash table of crops - ID -> entry */
	private static Hashtable<Integer, PCma_CropEntry> crops = new Hashtable<Integer, PCma_CropEntry>();

	/**
	 * Get Crop entry for given block ID
	 * 
	 * @param id
	 *            block ID
	 * @return the entry or null
	 */
	public static PCma_CropEntry getEntryForBlock(int id) {
		return crops.get(id);
	}

	static {

		System.out.println("\nPowerCraft: Loading XML configuration for crops.");

		if (!folder.exists()) {
			folder.mkdir();
		}

		if (!(new File(folder + "/" + "default.xml")).exists()) {

			try {
				FileWriter out = new FileWriter(new File(folder + "/" + "default.xml"));

				//@formatter:off
				out.write("<?xml version='1.1' ?>\n" + "<!-- \n" + "  BLOCK HARVESTER CONFIG FILE\n"
						+ "  You can add your own crops into this file.\n" + "  Any other xml files in this folder will be parsed too.\n\n"
						+ "  If you make a setup file for some mod, please post it on forums.\n\n" + "  Special values:\n"
						+ "    metaMature  = -1  ...  any metadata\n" + "    metaReplant = -1  ...  do not replant\n\n"
						+ "    Item meta   <  0  ...  get item with meta = blockMeta & abs(THIS_NUMBER) - useful for leaves\n\n"
						+ "  Item meta can be ranged - use 4-7 for random meta in range 4 to 7 (inclusive).\n"
						+ "  You can also use range for item count (eg. 0-5). \n\n"
						+ "  Higher rarity number means more rare. Use 1 for regular drops. \n"
						+ "-->\n\n"
						+ "<crops>\n"
						+ "\n"
						+ "\t<crop name='Wheat'>\n" + "\t\t<block id='59' metaMature='7' metaReplant='0' />\n"
						+ "\t\t<item id='296' meta='0' count='1' rarity='1' priority='1' /><!-- wheat -->\n"
						+ "\t\t<item id='295' meta='0' count='0-2' rarity='1' priority='1' /><!-- seeds -->\n"
						+ "\t</crop>\n"
						+ "\n"
						+ "\t<crop name='Nether Wart'>\n"
						+ "\t\t<block id='115' metaMature='3' metaReplant='0' />\n"
						+ "\t\t<item id='372' meta='0' count='2-5' rarity='1' priority='1' /><!-- wart seeds -->\n"
						+ "\t</crop>\n"
						+ "\n"
						+ "\t<crop name='Leaves'>\n"
						+ "\t\t<block id='18' metaMature='-1' metaReplant='-1' />\n"
						+ "\t\t<item id='260' meta='0'  count='1' rarity='1/200' priority='1' /><!-- apple -->\n"
						+ "\t\t<item id='6'   meta='-3' count='1' rarity='1/20'  priority='2' /><!-- sapling -->\n"
						+ "\t\t<item id='18'  meta='-3' count='1' rarity='1'   priority='3' /><!-- leaf -->\n"
						+ "\t</crop>\n"
						+ "\n"
						+ "</crops>");
				//@formatter:on

				out.close();

			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		String[] files = folder.list(new FilenameFilter() {

			@Override
			public boolean accept(File arg0, String arg1) {
				return arg1.matches("[^.]+[.]xml");
			}
		});

		for (String filename : files) {

			System.out.println(" - loading file " + filename + "...");
			File file = new File(folder + "/" + filename);
			parseFile(file);

		}

		System.out.println("Crops configuration loaded.\n");

	}

	/*
	 * <?xml version="1.0" encoding="UTF-8" ?>
	 * <crops>
	 * <crop name="My Crop">
	 * <block id="79" metaReplant="0" metaMature="7">
	 * <item id="318" meta="0" count="1-2" rarity="1">
	 * <item id="319" meta="1-5" count="1-2" rarity="4">
	 * </crop>
	 * </crops>
	 */

	/**
	 * Load and parse XML file with crops specs
	 * 
	 * @param file
	 *            the file to load
	 */
	private static void parseFile(File file) {

		try {

			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(file);

			doc.getDocumentElement().normalize();

			NodeList cropsList = doc.getElementsByTagName("crop");
			cropsList.getLength();

			croploop:
			for (int i = 0; i < cropsList.getLength(); i++) {

				Node cropNode = cropsList.item(i);
				if (cropNode.getNodeType() == Node.ELEMENT_NODE) {

					// process one crop entry

					Element crop = (Element) cropNode;

					// <block>
					NodeList blocks = crop.getElementsByTagName("block");
					if (blocks.getLength() != 1) {
						System.out.println("PC: Error while parsing " + file + " - invalid no. of <block>s in one <crop>");
						continue croploop;
					}

					Element block = (Element) blocks.item(0);

					// <item>
					NodeList items = crop.getElementsByTagName("item");
					if (blocks.getLength() < 1) {
						System.out.println("PC: Error while parsing " + file + " - no <item>s in <crop>");
						continue croploop;
					}

					int itemCount = items.getLength();

					PCma_CropEntry entry = new PCma_CropEntry();

					// <block attrs>
					String block_id_s = block.getAttribute("id");

					if (block_id_s.equals("") || !block_id_s.matches("[0-9]+")) {
						System.out.println("PC: Error while parsing " + file + " - bad block ID");
						continue croploop;
					}

					int block_id = Integer.parseInt(block_id_s);

					String block_meta_replant_s = block.getAttribute("metaReplant");

					if (block_meta_replant_s.equals("") || !block_meta_replant_s.matches("[-]?[0-9]+")) {
						System.out.println("PC: Error while parsing " + file + " - bad replant meta");
						continue croploop;
					}

					int meta_replant = Integer.parseInt(block_meta_replant_s);

					String block_meta_mature_s = block.getAttribute("metaMature");

					if (block_meta_mature_s.equals("") || !block_meta_mature_s.matches("[-]?[0-9]+")) {
						System.out.println("PC: Error while parsing " + file + " - bad mature meta");
						continue croploop;
					}

					int meta_mature = Integer.parseInt(block_meta_mature_s);

					// store block
					entry.setBlockInfo(block_id, meta_mature, meta_replant);

					itemloop:
					for (int j = 0; j < itemCount; j++) {

						try {
							int item_meta_a, item_meta_b, item_count_a, item_count_b, item_rarity_a, item_rarity_b, item_priority, item_id;

							Element item = (Element) items.item(j);

							// id
							String item_id_s = item.getAttribute("id");

							if (item_id_s.equals("") || !item_id_s.matches("[0-9]+")) {
								System.out.println("PC: Error while parsing " + file + " - bad item ID");
								continue croploop;
							}

							item_id = Integer.parseInt(item_id_s);

							// priority
							String item_priority_s = item.getAttribute("priority");

							if (item_id_s.equals("")) {

								item_priority_s = "1";

							} else if (!item_id_s.matches("[0-9]+")) {
								System.out.println("PC: Error while parsing " + file + " - bad item ID");
								continue croploop;
							}

							item_priority = Integer.parseInt(item_priority_s);

							// rarity 1/200
							String item_rarity_s = item.getAttribute("rarity");

							if (item_rarity_s.equals("")) {

								item_rarity_s = "1";

							}
							if (!item_rarity_s.matches("[0-9]+([/][0-9]+)?")) {
								System.out.println("PC: Error while parsing " + file + " - bad item rarity");
								continue croploop;
							}

							String[] item_rarity_parts = item_rarity_s.split("/");

							if (item_rarity_parts.length == 1) {
								item_rarity_a = 1;
								item_rarity_b = Integer.parseInt(item_rarity_parts[0]);
							} else {
								item_rarity_a = Integer.parseInt(item_rarity_parts[0]);
								item_rarity_b = Integer.parseInt(item_rarity_parts[1]);

								if (item_rarity_a > item_rarity_b) {
									item_rarity_a = item_rarity_b = 1;
								}
							}

							// meta start-stop
							String item_meta_s = item.getAttribute("meta");

							if (item_meta_s.equals("")) {
								item_meta_s = "0";
							} else if (!item_meta_s.matches("[-]?[0-9]+") && !item_meta_s.matches("[0-9]+[-][0-9]+")) {
								System.out.println("PC: Error while parsing " + file + " - bad item meta");
								continue croploop;
							}

							String[] item_meta_parts;

							if (item_meta_s.matches("[-]?[0-9]+")) {
								item_meta_parts = new String[1];
								item_meta_parts[0] = item_meta_s;

							} else {
								item_meta_parts = item_meta_s.split("-");
							}

							if (item_meta_parts.length == 1) {
								item_meta_a = item_meta_b = Integer.parseInt(item_meta_parts[0]);
							} else {
								item_meta_a = Integer.parseInt(item_meta_parts[0]);
								item_meta_b = Integer.parseInt(item_meta_parts[1]);

								if (item_meta_b < item_meta_a) {
									item_meta_b = item_meta_a;
								}
							}

							// cout start-stop
							String item_count_s = item.getAttribute("count");

							if (item_count_s.equals("")) {

								item_count_s = "1";

							} else if (!item_count_s.matches("[0-9]+(-[0-9]+)?")) {
								System.out.println("PC: Error while parsing " + file + " - bad item count");
								continue croploop;
							}

							String[] item_count_parts = item_count_s.split("-");

							if (item_count_parts.length == 1) {
								item_count_a = item_count_b = Integer.parseInt(item_count_parts[0]);
							} else {
								item_count_a = Integer.parseInt(item_count_parts[0]);
								item_count_b = Integer.parseInt(item_count_parts[1]);

								if (item_count_b < item_count_a) {
									item_count_b = item_count_a;
								}
							}

							// store item
							entry.addDropItem(item_id, item_meta_a, item_meta_b, item_count_a, item_count_b, item_rarity_a, item_rarity_b,
									item_priority);

						} catch (NumberFormatException e) {
							continue itemloop;
						}

					}

					crops.put(block_id, entry);

				}

			}

		} catch (SAXParseException err) {
			System.out.println("** Parsing error" + ", line " + err.getLineNumber() + ", uri " + err.getSystemId());
			System.out.println(" " + err.getMessage());
		} catch (SAXException e) {
			Exception x = e.getException();
			((x == null) ? e : x).printStackTrace();
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

}
