package net.minecraft.src;

import java.util.*;
import org.lwjgl.input.Keyboard;

import net.minecraft.client.Minecraft;

/**
 * powerCraft's Mobile module<br>
 * Provides power crystals (+generation), miner, activation crystal, power dust,
 * fishing machine and ore sniffer.
 * 
 * @author MightyPork
 * @copy (c) 2012
 * 
 */
public class mod_PCmobile extends BaseMod {
	
	private static final String pk_iactivator = "id.item.activation_crystal";
	private static final String pk_ipowerDust = "id.item.power_dust";
	private static final String pk_isniffer = "id.item.ore_sniffer";
	private static final String pk_crystal = "id.block.power_crystal";
	
	private static final String pk_crystal_gen = "opt.worldgen.power_crystals";
	private static final String pk_easycrystals = "opt.cheat.easy_crystals";
	private static final String pk_crystal_brightness = "brightness.power_crystal";

	private static final String pk_mForward = "key.miner.move_forward";
	private static final String pk_mBackward = "key.miner.move_backward";
	private static final String pk_mLeft = "key.miner.turn_left";
	private static final String pk_mRight = "key.miner.turn_right";
	private static final String pk_mAround = "key.miner.turn_around";
	private static final String pk_mUp = "key.miner.mine_up";
	private static final String pk_mDown = "key.miner.mine_down";
	private static final String pk_mBridgeOn = "key.miner.set_bridge_on";
	private static final String pk_mBridgeOff = "key.miner.set_bridge_off";
	private static final String pk_mRun = "key.miner.run_program";
	private static final String pk_mDeposit = "key.miner.store_to_chest";
	private static final String pk_mToBlocks = "key.miner.deactivate";
	private static final String pk_mMiningOn = "key.miner.set_mining_on";
	private static final String pk_mMiningOff = "key.miner.set_mining_off";
	private static final String pk_mCancel = "key.miner.reset";

	/**
	 * Configuration file
	 */
	public static PCMP conf = new PCMP("/config/PC_MOBILE.properties", "PowerCraft mobile plugin - setup file\n");

	/**
	 * Get images directory (ending with slash)
	 * @return the directory
	 */
	public static String getImgDir() {
		return "/PowerCraft/mobile/";
	}


	/**
	 * Get terrain file path (png)
	 * @return the file path
	 */
	public static String getTerrainFile() {
		return getImgDir() + "tiles.png";
	}

	@Override
	public String getPriorities() {
		return "after:mod_PCcore";
	}


	@Override
	public String getVersion() {
		return mod_PCcore.VERSION;
	}

	static {
		conf.putItem(pk_iactivator, 19001);
		conf.putItem(pk_ipowerDust, 19002);
		conf.putItem(pk_isniffer, 19004);
		conf.putBlock(pk_crystal, 232);

		conf.putBoolean(pk_crystal_gen, true, "Generate Power Crystals in the world?");
		conf.putInteger(pk_crystal_brightness, 15, "Power Crystal brightness, scale 0-15.");
		
		conf.putBoolean(pk_easycrystals, false, "Cheat:\nget power crystals by smelting diamonds & craft crystals to change color");

		conf.putKey(pk_mForward, Keyboard.KEY_NUMPAD8);
		conf.putKey(pk_mBackward, Keyboard.KEY_NUMPAD2);
		conf.putKey(pk_mLeft, Keyboard.KEY_NUMPAD4);
		conf.putKey(pk_mRight, Keyboard.KEY_NUMPAD6);
		conf.putKey(pk_mAround, Keyboard.KEY_NUMPAD5);
		conf.putKey(pk_mDown, Keyboard.KEY_SUBTRACT);
		conf.putKey(pk_mUp, Keyboard.KEY_ADD);

		conf.putKey(pk_mBridgeOn, Keyboard.KEY_O);
		conf.putKey(pk_mBridgeOff, Keyboard.KEY_P);
		conf.putKey(pk_mRun, Keyboard.KEY_NUMPADENTER);

		conf.putKey(pk_mDeposit, Keyboard.KEY_DECIMAL);
		conf.putKey(pk_mToBlocks, Keyboard.KEY_NUMPAD1);
		conf.putKey(pk_mMiningOn, Keyboard.KEY_NUMPAD7);
		conf.putKey(pk_mMiningOff, Keyboard.KEY_NUMPAD9);

		conf.putKey(pk_mCancel, Keyboard.KEY_DELETE);

		conf.apply();
	}

	/** Activation Crystal item */
	public static Item activator = new PCmo_ItemActivator(conf.getInteger(pk_iactivator)).setIconIndex(37).setItemName("PCmoActivatorItem");

	/** Power Dust item (fuel) */
	public static Item powerDust = new PCmo_ItemPowerDust(conf.getInteger(pk_ipowerDust)).setIconCoord(13, 9).setItemName("PCmoPowerDust");

	/** Ore Sniffer item */
	public static Item oreSniffer = new PCmo_ItemOreSniffer(conf.getInteger(pk_isniffer)).setIconIndex(37).setItemName("PCmoOreSnifferItem");

	/** Power Crystal block */
	public static Block powerCrystal = new PCmo_BlockPowerCrystal(conf.getInteger(pk_crystal), 49).setHardness(0.5F).setResistance(0.5F).setBlockName("PCmoPowerCrystal")
			.setStepSound(Block.soundGlassFootstep).setLightValue(conf.getInteger(pk_crystal_brightness) * 0.0625F);


	@Override
	public int addFuel(int i, int j) {
		return (i == powerDust.shiftedIndex) ? 2200 : 0;
	}

	public static int rendererCrystal = 0;


	public mod_PCmobile() {
	}


	@Override
	public void load() {

		// init names from a file
		((PCmo_ItemOreSniffer) oreSniffer).initNames();

		// preload textures
		Minecraft mc = ModLoader.getMinecraftInstance();

		mc.renderEngine.getTexture(getTerrainFile());
		mc.renderEngine.getTexture(getImgDir() + "gui_miner.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_base.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_overlay_1.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_overlay_2.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_overlay_3.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_overlay_4.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_overlay_5.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_overlay_6.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_overlay_7.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_overlay_8.png");
		mc.renderEngine.getTexture(getImgDir() + "miner_overlay_keyboard.png");

		mc.renderEngine.getTexture(getImgDir() + "fisher.png");

		activator.setIconIndex(ModLoader.addOverride("/gui/items.png", getImgDir() + "activator.png"));
		oreSniffer.setIconIndex(ModLoader.addOverride("/gui/items.png", getImgDir() + "sniffer.png"));

		rendererCrystal = ModLoader.getUniqueBlockModelID(this, true);

		ModLoader.setInGameHook(this, true, true);

		ModLoader.addName(activator, "Activation Crystal");
		ModLoader.addName(powerCrystal, "Power Crystal");
		ModLoader.addName(powerDust, "Power Dust");
		ModLoader.addName(oreSniffer, "Ore Sniffer");

		ModLoader.registerBlock(powerCrystal);
		Item.itemsList[powerCrystal.blockID] = null;
		Item.itemsList[powerCrystal.blockID] = (new PCmo_ItemBlockPowerCrystal(powerCrystal.blockID - 256)).setItemName("PCmoPowerCrystal");

		ModLoader.registerEntityID(net.minecraft.src.PCmo_EntityMiner.class, "PCmo_Miner", ModLoader.getUniqueEntityId());
		ModLoader.registerEntityID(net.minecraft.src.PCmo_EntityFishingMachine.class, "PCmo_FishingMachine", ModLoader.getUniqueEntityId());

		if (conf.getBoolean("RECIPES_EasyCrystals_Enabled")) {
			ModLoader.addSmelting(Item.diamond.shiftedIndex, new ItemStack(powerCrystal, 1));
			ModLoader.addShapelessRecipe(new ItemStack(powerCrystal, 1, 1), new Object[] { new ItemStack(powerCrystal, 1, 0) });
			ModLoader.addShapelessRecipe(new ItemStack(powerCrystal, 1, 2), new Object[] { new ItemStack(powerCrystal, 1, 1) });
			ModLoader.addShapelessRecipe(new ItemStack(powerCrystal, 1, 3), new Object[] { new ItemStack(powerCrystal, 1, 2) });
			ModLoader.addShapelessRecipe(new ItemStack(powerCrystal, 1, 4), new Object[] { new ItemStack(powerCrystal, 1, 3) });
			ModLoader.addShapelessRecipe(new ItemStack(powerCrystal, 1, 5), new Object[] { new ItemStack(powerCrystal, 1, 4) });
			ModLoader.addShapelessRecipe(new ItemStack(powerCrystal, 1, 6), new Object[] { new ItemStack(powerCrystal, 1, 5) });
			ModLoader.addShapelessRecipe(new ItemStack(powerCrystal, 1, 7), new Object[] { new ItemStack(powerCrystal, 1, 6) });
			ModLoader.addShapelessRecipe(new ItemStack(powerCrystal, 1, 0), new Object[] { new ItemStack(powerCrystal, 1, 7) });
			ModLoader.addShapelessRecipe(new ItemStack(powerDust, 48, 0), new Object[] { new ItemStack(powerCrystal, 1, -1), new ItemStack(powerCrystal, 1, -1) });
		} else {
			ModLoader.addShapelessRecipe(new ItemStack(powerDust, 24, 0), new Object[] { new ItemStack(powerCrystal, 1, -1) });
		}

		ModLoader.addRecipe(new ItemStack(oreSniffer, 1, 0),
				new Object[] { " G ", "GCG", " G ", Character.valueOf('C'), new ItemStack(powerCrystal, 1, -1), Character.valueOf('G'), Item.ingotGold });

		ModLoader.addRecipe(new ItemStack(activator, 1), new Object[] { "C", "I", Character.valueOf('C'), new ItemStack(powerCrystal, 1, -1), Character.valueOf('I'), Item.ingotIron });

		ModLoader.addLocalization("tile.PCmoPowerCrystal.color0.name", "\u03b1 Power Crystal");
		ModLoader.addLocalization("tile.PCmoPowerCrystal.color1.name", "\u03b2 Power Crystal");
		ModLoader.addLocalization("tile.PCmoPowerCrystal.color2.name", "\u03b3 Power Crystal");
		ModLoader.addLocalization("tile.PCmoPowerCrystal.color3.name", "\u03b4 Power Crystal");
		ModLoader.addLocalization("tile.PCmoPowerCrystal.color4.name", "\u03d1 Power Crystal");
		ModLoader.addLocalization("tile.PCmoPowerCrystal.color5.name", "\u03b6 Power Crystal");
		ModLoader.addLocalization("tile.PCmoPowerCrystal.color6.name", "\u03be Power Crystal");
		ModLoader.addLocalization("tile.PCmoPowerCrystal.color7.name", "\u03d7 Power Crystal");

		// TMI
		net.minecraft.src.PCco_Utils.TMI_rangeDamage(powerCrystal.blockID, 0, 7);
	}


	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public void addRenderer(Map map) {
		map.put(PCmo_EntityMiner.class, new PCmo_RenderMiner());
		map.put(PCmo_EntityFishingMachine.class, new PCmo_RenderFishingMachine());
	}


	@Override
	public boolean renderWorldBlock(RenderBlocks renderblocks, IBlockAccess iblockaccess, int i, int j, int k, Block block, int renderType) {
		RenderEngine renderengine = ModLoader.getMinecraftInstance().renderEngine;
		Tessellator tessellator = Tessellator.instance;
		if (renderType == rendererCrystal && block instanceof PCco_ISwapTerrain) {
			tessellator.draw();
			tessellator.startDrawingQuads();
			renderengine.bindTexture(renderengine.getTexture(((PCco_ISwapTerrain) block).getTerrainFile()));

			boolean gf = RenderBlocks.cfgGrassFix;
			RenderBlocks.cfgGrassFix = false;

			Random posRand = new Random(i + i * j * k + k + iblockaccess.getBlockMetadata(i, j, k));

			for (int q = 3 + posRand.nextInt(2); q > 0; q--) {
				float x, y, z, a, b, c;

				x = posRand.nextFloat() * 0.6F;
				y = (q == 2 ? 0.001F : posRand.nextFloat() * 0.6F);
				z = posRand.nextFloat() * 0.6F;

				a = x + 0.3F + posRand.nextFloat() * (0.7F - x);
				b = y + 0.3F + posRand.nextFloat() * (0.7F - y);
				c = z + 0.3F + posRand.nextFloat() * (0.7F - z);

				block.setBlockBounds(x, y, z, a, b, c);
				renderblocks.renderStandardBlock(block, i, j, k);
			}
			block.setBlockBounds(0, 0, 0, 1, 1, 1);

			RenderBlocks.cfgGrassFix = gf;

			tessellator.draw();
			tessellator.startDrawingQuads();
			renderengine.bindTexture(renderengine.getTexture("/terrain.png"));

			return true;
		}
		return false;
	}


	@Override
	public void renderInvBlock(RenderBlocks renderblocks, Block block, int i, int rtype) {
		RenderEngine renderengine = ModLoader.getMinecraftInstance().renderEngine;

		if (rtype == rendererCrystal) {
			renderengine.bindTexture(renderengine.getTexture(((PCco_ISwapTerrain) block).getTerrainFile()));

			Random posRand = new Random(i);

			for (int q = 3 + posRand.nextInt(3); q > 0; q--) {
				float x, y, z, a, b, c;
				x = 0.0F + posRand.nextFloat() * 0.6F;
				y = 0.0F + posRand.nextFloat() * 0.6F;
				z = 0.0F + posRand.nextFloat() * 0.6F;

				a = 0.2F + Math.max(posRand.nextFloat() * (0.7F - x), 0.3F);
				b = 0.2F + Math.max(posRand.nextFloat() * (0.7F - y), 0.3F);
				c = 0.2F + Math.max(posRand.nextFloat() * (0.7F - z), 0.3F);

				block.setBlockBounds(x, y, z, x + a, y + b, z + c);
				PCco_Renderer.renderInvBox(renderblocks, block, i);
			}
			block.setBlockBounds(0, 0, 0, 1, 1, 1);
			renderengine.bindTexture(renderengine.getTexture("/terrain.png"));

			return;
		}
	}


	@Override
	public void generateSurface(World world, Random random, int chunkX, int chunkZ) {
		if (!conf.getBoolean(pk_crystal_gen)) return;

		int posX;
		int posY;
		int posZ;

		for (int q = 0; q < 4; q++) {
			int maxBlocks = random.nextInt(3) + 2;

			posX = chunkX + random.nextInt(16);
			posY = random.nextInt(10) + 6;
			posZ = chunkZ + random.nextInt(16);

			new WorldGenMinable(powerCrystal.blockID, maxBlocks).generate(world, random, posX, posY, posZ);
		}
	}

	// Miner control stuff

	/** list of keyboard controlled miners */
	public static List<PCmo_EntityMiner> controlledMiners = new ArrayList<PCmo_EntityMiner>();

	private static World lastKCWorld = null;


	/**
	 * Add this Miner to list of keyboard-controlled
	 * 
	 * @param miner
	 *            the miner entity
	 * @param silent
	 *            don't show chat message
	 */
	public static void setMinerForKeyboardControl(PCmo_EntityMiner miner, boolean silent) {
		lastKCWorld = ModLoader.getMinecraftInstance().theWorld;
		if (!controlledMiners.contains(miner)) controlledMiners.add(miner);

		if (!silent) PCco_Utils.chatMsg("Miner " + miner.level + " connected to keyboard.", true);
	}


	/**
	 * Remove this Miner from list of keyboard-controlled
	 * 
	 * @param miner
	 *            the miner entity
	 * @param silent
	 *            don't show chat message
	 */
	public static void disconnectMinerFromKeyboardControl(PCmo_EntityMiner miner, boolean silent) {
		lastKCWorld = ModLoader.getMinecraftInstance().theWorld;
		if (controlledMiners.contains(miner)) controlledMiners.remove(miner);

		if (!silent) PCco_Utils.chatMsg("Miner " + miner.level + " disconnected from keyboard.", true);
	}

	/** cooldown timer for repeated keypresses */
	private static int[] keyPressTimer = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	/** number of ticks before the key is accepted again */
	private static final int CooldownTime = 8;


	@Override
	public boolean onTickInGame(float f, Minecraft minecraft) {
		if (lastKCWorld != ModLoader.getMinecraftInstance().theWorld) {
			controlledMiners.clear();
			lastKCWorld = ModLoader.getMinecraftInstance().theWorld;
		}

		if (ModLoader.getMinecraftInstance().currentScreen != null) return true;
		// keyboard control

		for (int i = 0; i <= 8; i++) {
			if (keyPressTimer[i] > 0) keyPressTimer[i]--;
		}

		if (ModLoader.getMinecraftInstance().theWorld != null && lastKCWorld == ModLoader.getMinecraftInstance().theWorld) {
			if (conf.isKeyDown(pk_mForward)) {
				if (keyPressTimer[0] == 0) {
					keyPressTimer[0] = CooldownTime;
					sendCommandToMiners(PCmo_Command.FORWARD);
				}
				return true;
			}
			if (conf.isKeyDown(pk_mLeft)) {
				if (keyPressTimer[1] == 0) {
					keyPressTimer[1] = CooldownTime;
					sendCommandToMiners(PCmo_Command.LEFT);
				}
				return true;
			}
			if (conf.isKeyDown(pk_mRight)) {
				if (keyPressTimer[2] == 0) {
					keyPressTimer[2] = CooldownTime;
					sendCommandToMiners(PCmo_Command.RIGHT);
				}
				return true;
			}
			if (conf.isKeyDown(pk_mAround)) {
				if (keyPressTimer[3] == 0) {
					keyPressTimer[3] = CooldownTime;
					sendSequenceToMiners("RR");
				}
				return true;
			}
			if (conf.isKeyDown(pk_mBackward)) {
				if (keyPressTimer[4] == 0) {
					keyPressTimer[4] = CooldownTime;
					sendCommandToMiners(PCmo_Command.BACKWARD);
				}
				return true;
			}

			if (conf.isKeyDown(pk_mDown)) {
				if (keyPressTimer[5] == 0) {
					keyPressTimer[5] = CooldownTime;
					sendCommandToMiners(PCmo_Command.DOWN);
				}
				return true;
			}
			if (conf.isKeyDown(pk_mUp)) {
				if (keyPressTimer[6] == 0) {
					keyPressTimer[6] = CooldownTime;
					sendCommandToMiners(PCmo_Command.UP);
				}
				return true;
			}

			if (conf.isKeyDown(pk_mBridgeOn)) {
				if (sendCommandToMiners(PCmo_Command.BRIDGE_ENABLE)) PCco_Utils.chatMsg("Bridge building enabled.", true);
				return true;
			}

			if (conf.isKeyDown(pk_mBridgeOff)) {
				if (sendCommandToMiners(PCmo_Command.BRIDGE_DISABLE)) PCco_Utils.chatMsg("Bridge building disabled.", true);
				return true;
			}

			if (conf.isKeyDown(pk_mDeposit)) {
				if (keyPressTimer[7] == 0) {
					keyPressTimer[7] = CooldownTime;
					sendCommandToMiners(PCmo_Command.DEPOSIT);
				}
				return true;
			}

			if (conf.isKeyDown(pk_mRun)) {
				if (keyPressTimer[8] == 0) {
					keyPressTimer[8] = CooldownTime;
					if (sendSafelyUrgentCommandToMiners(PCmo_Command.RUN_PROGRAM)) PCco_Utils.chatMsg("Miners launched and disconnected.", true);
				}
				return true;
			}

			if (conf.isKeyDown(pk_mToBlocks)) {
				sendUrgentCommandToMiners(PCmo_Command.DISASSEMBLY);
				return true;
			}

			if (conf.isKeyDown(pk_mMiningOn)) {
				if (sendCommandToMiners(PCmo_Command.MINING_ENABLE)) PCco_Utils.chatMsg("Mining enabled.", true);
				return true;
			}

			if (conf.isKeyDown(pk_mMiningOff)) {
				if (sendCommandToMiners(PCmo_Command.MINING_DISABLE)) PCco_Utils.chatMsg("Mining disabled.", true);
				return true;
			}

			if (conf.isKeyDown(pk_mCancel)) {
				if (sendUrgentCommandToMiners(PCmo_Command.RESET)) PCco_Utils.chatMsg("All operations cancelled.", true);
				return true;
			}
		}
		return true;
	}


	/**
	 * Send given command to all connected miners<br>
	 * Some miners may reject it.
	 * 
	 * @param cmd
	 *            command index
	 * @return true if at least one miner accepted it
	 */
	private boolean sendCommandToMiners(int cmd) {
		boolean flag = false;
		for (PCmo_EntityMiner miner : controlledMiners) {
			if (miner.readyForKeyboardCommand()) {
				flag = true;
				miner.sendKeyboardCommand(cmd);
			}
		}
		return flag;
	}


	/**
	 * Send urgent command to all connected miners.<br>
	 * Miners will do their best top accept it
	 * 
	 * @param cmd
	 *            command index
	 * @return true if at least one miner accepted it
	 */
	private boolean sendUrgentCommandToMiners(int cmd) {
		boolean flag = false;
		for (PCmo_EntityMiner miner : controlledMiners) {
			if (miner.readyForUrgentKeyboardCommand()) {
				flag = true;
				miner.sendKeyboardCommand(cmd);
			}
		}
		return flag;
	}


	/**
	 * Send urgent command to all connected miners.<br>
	 * This method works for commands that involve disconnecting from keyboard
	 * control.
	 * 
	 * @param cmd
	 *            command index
	 * @return true if at least one miner accepted it
	 */
	private boolean sendSafelyUrgentCommandToMiners(int cmd) {
		boolean flag = false;

		List<PCmo_EntityMiner> controlled2 = new ArrayList<PCmo_EntityMiner>();

		for (PCmo_EntityMiner miner : controlledMiners) {
			controlled2.add(miner);
		}

		for (PCmo_EntityMiner miner : controlled2) {
			if (miner.readyForUrgentKeyboardCommand()) {
				flag = true;
				miner.sendKeyboardCommand(cmd);
			}
		}
		return flag;
	}


	/**
	 * Send command sequence to all connected miners
	 * 
	 * @param seq
	 *            String with command characters
	 * @return true if at least one miner accepted it
	 */
	private boolean sendSequenceToMiners(String seq) {
		boolean flag = false;
		for (PCmo_EntityMiner miner : controlledMiners) {
			if (miner.readyForKeyboardCommand()) {
				flag = true;
				try {
					miner.appendCode(seq);
				} catch (PCmo_CommandException ce) {
					System.out.println("Error in keybd command!");
					return false;
				}
			}
		}
		return flag;
	}
}
