package org.ultramine.mods.hawkeye.listeners;

import com.mojang.authlib.GameProfile;
import org.ultramine.mods.hawkeye.DataType;
import org.ultramine.mods.hawkeye.HawkEye;
import org.ultramine.mods.hawkeye.database.DataManager;
import org.ultramine.mods.hawkeye.entry.BlockChangeEntry;
import org.ultramine.mods.hawkeye.entry.BlockBreakEntry;
import org.ultramine.mods.hawkeye.util.HawkNameUtil;
import org.ultramine.server.event.SetBlockEvent;
import org.ultramine.server.event.WorldUpdateObjectType;

import cpw.mods.fml.common.eventhandler.EventPriority;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraft.block.Block;
import net.minecraft.entity.item.EntityFallingBlock;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.BlockSnapshot;
import net.minecraftforge.fluids.FluidRegistry;

/**
 * Block listener class for HawkEye
 * 
 * @author oliverw92
 */
public class MonitorBlockListener
{
	public MonitorBlockListener()
	{

	}
	
	@SubscribeEvent(priority = EventPriority.LOWEST)
	public void onBlockSet(SetBlockEvent e)
	{
		Block newBlock = e.newBlock;
		Block oldBlock = e.world.getBlock(e.x, e.y, e.z);
		int oldMeta = e.world.getBlockMetadata(e.x, e.y, e.z);
		if(newBlock == oldBlock && oldMeta == e.newMeta)
			return;
		if(newBlock == Blocks.air) //break
		{
			if(HawkEye.instance.isBlockFiltered(oldBlock, oldMeta))
				return;
			DataType type = DataType.BLOCK_BREAK;
			String who = HawkNameUtil.ENVIRONMENT;
			switch(e.initiator.getType())
			{
			case BLOCK_EVENT:
			{
				type = DataType.MACHINE_BREAK;
				GameProfile profile = e.initiator.getOwner();
				who = profile != null ? profile.getName().toLowerCase() : HawkNameUtil.getBlockOwnerName(e.initiator.getBlock());
				break;
			}
			case TILEE_ENTITY:
				type = DataType.MACHINE_BREAK;
				who = HawkNameUtil.getTileEntityOwnerOrName(e.initiator.getTileEntity());
				break;
			case BLOCK_RANDOM:
			case BLOCK_PENDING:
			{
				if(oldBlock.isLeaves(e.world, e.x, e.y, e.z))
					type = DataType.LEAF_DECAY;
				if(e.initiator.getBlock() == Blocks.fire)
					type = DataType.BLOCK_BURN;
				GameProfile profile = e.initiator.getOwner();
				if(profile != null)
					who = profile.getName().toLowerCase();
				break;
			}
			case ENTITY:
				type = DataType.ENTITY_BREAK;
				who = HawkNameUtil.getEntityOwnerOrName(e.initiator.getEntity());
				break;
			case PLAYER:
				who = ((EntityPlayerMP)e.initiator.getEntity()).getGameProfile().getName().toLowerCase();
				break;
			case ENTITY_WEATHER:
			case WEATHER:
				break;
			case UNKNOWN:
				type = DataType.UNKNOWN_BREAK;
				who = HawkNameUtil.UNKNOWN;
				break;
			}
			
			if(e.isNeighborChangeItself)
				type = DataType.BLOCK_FADE;
			
			DataManager.addEntry(new BlockBreakEntry(who, type, e.world, e.x, e.y, e.z, oldBlock, oldMeta));
		}
		else //place
		{
			if(HawkEye.instance.isBlockFiltered(newBlock, e.newMeta))
				return;
			DataType type = DataType.BLOCK_PLACE;
			String who = HawkNameUtil.ENVIRONMENT;
			switch(e.initiator.getType())
			{
			case BLOCK_EVENT:
			{
				type = DataType.MACHINE_PLACE;
				GameProfile profile = e.initiator.getOwner();
				who = profile != null ? profile.getName().toLowerCase() : HawkNameUtil.getBlockOwnerName(e.initiator.getBlock());
				break;
			}
			case TILEE_ENTITY:
				type = DataType.MACHINE_PLACE;
				who = HawkNameUtil.getTileEntityOwnerOrName(e.initiator.getTileEntity());
				break;
			case BLOCK_RANDOM:
				type = DataType.BLOCK_FORM;
			case BLOCK_PENDING:
			{
				GameProfile profile = e.initiator.getOwner();
				if(profile != null)
					who = profile.getName().toLowerCase();
				Block next = Block.getBlockById(Block.getIdFromBlock(newBlock) + 1);
				if(e.initiator.getBlock() == Blocks.sapling)
					type = DataType.GROW;
				else if(e.initiator.getBlock() == Blocks.fire)
					type = DataType.BLOCK_BURN;
				else if(FluidRegistry.lookupFluidForBlock(newBlock) != null || FluidRegistry.lookupFluidForBlock(next) != null)
				{
					type = DataType.LIQUID_FLOW;
					if(oldBlock != Blocks.air && !HawkEye.instance.config.isLogged(DataType.LIQUID_FLOW))
					{
						DataManager.addEntry(new BlockChangeEntry(HawkNameUtil.ENVIRONMENT, DataType.BLOCK_PLACE, e.world, e.x, e.y, e.z,
								new BlockSnapshot(e.world, e.x, e.y, e.z, oldBlock, oldMeta, null), new BlockSnapshot(e.world, e.x, e.y, e.z, e.newBlock, e.newMeta, null)));
						return;
					}
				}
				else if(e.initiator.getType() == WorldUpdateObjectType.BLOCK_PENDING)
				{
					TileEntity te = e.world.getTileEntity(e.initiator.getX(), e.initiator.getY(), e.initiator.getZ());
					if(te != null)
					{
						type = DataType.MACHINE_PLACE;
						if(profile == null)
							who = HawkNameUtil.getTileEntityOwnerOrName(te);
					}
				}
				break;
			}
			case ENTITY:
				type = DataType.ENTITY_PLACE;
				who = HawkNameUtil.getEntityOwnerOrName(e.initiator.getEntity());
				break;
			case PLAYER:
				who = ((EntityPlayerMP)e.initiator.getEntity()).getGameProfile().getName().toLowerCase();
				if(e.initiator.isInteracting())
				{
					ItemStack stack = e.initiator.getInteractStack();
					if(stack != null && stack.getItem() == Items.dye && stack.getItemDamage() == 15)
						type = DataType.PLAYER_GROW;
				}
				break;
			case ENTITY_WEATHER:
			case WEATHER:
				type = DataType.BLOCK_FORM;
				break;
			case UNKNOWN:
				type = DataType.UNKNOWN_PLACE;
				who = HawkNameUtil.UNKNOWN;
				break;
			}
			
			BlockSnapshot from = new BlockSnapshot(e.world, e.x, e.y, e.z, oldBlock, oldMeta, null);
			BlockSnapshot to = new BlockSnapshot(e.world, e.x, e.y, e.z, e.newBlock, e.newMeta, null);
			DataManager.addEntry(new BlockChangeEntry(who, type, e.world, e.x, e.y, e.z, from, to));
		}
	}

//	//@HawkEvent(dataType = DataType.BLOCK_BREAK)
//	@SubscribeEvent(priority = EventPriority.LOWEST)
//	public void onBlockBreak(SetBlockEvent event)
//	{
//		/*
//		Block block = event.getBlock();
//		if (block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)
//			DataManager.addEntry(new SignEntry(event.getPlayer(), DataType.SIGN_BREAK, event.getBlock()));
//		else
//			DataManager.addEntry(new BlockEntry(event.getPlayer(), DataType.BLOCK_BREAK, block));
//		*/
//
//		DataType type = null;
//		String who = ConstantNames.ENVIRONMENT;
//
//		switch(event.reason)
//		{
//		case Entity:
//			type = DataType.ENDERMAN_PICKUP;
//			break;
//		case Player:
//			type = DataType.BLOCK_BREAK;
//			break;
//		case Environment:
//			type = DataType.BLOCK_BREAK;
//			break;
//		case Machine:
//			type = DataType.BLOCK_BREAK;
//			who = "Machine";
//			break;
//		case Unknown:
//			type = DataType.BLOCK_BREAK;
//			who = "Unknown";
//			break;
//		case IllgalStay:
//			type = DataType.BLOCK_FADE;
//			break;
//		case LeafDecay:
//			type = DataType.LEAF_DECAY;
//			break;
//		}
//
//		if(type != null)
//		{
//			if(type == DataType.BLOCK_BREAK && event.getActionerAsPlayer() != null)
//				who = event.getActionerAsPlayer().username;
//
//			if(event.block == Block.signWall.blockID || event.block == Block.signPost.blockID)
//			{
//				DataManager.addEntry(new SignEntry(who, DataType.SIGN_BREAK, event.world, event.x, event.y, event.z, event.block, event.metadata));
//			}
//			else
//			{
//				DataManager.addEntry(new BlockEntry(who, type, event.world, event.x, event.y, event.z, event.block, event.metadata));
//			}
//		}
//	}
//
//	//@HawkEvent(dataType = DataType.BLOCK_PLACE)
//	@ForgeSubscribe(priority = EventPriority.LOWEST)
//	public void onBlockPlace(BlockPlaceEvent event)
//	{
//		/*
//		Block block = event.getBlock();
//		if (block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST) return;
//		DataManager.addEntry(new BlockChangeEntry(event.getPlayer(), DataType.BLOCK_PLACE, block.getLocation(), event.getBlockReplacedState(), block.getState()));
//		*/
//
//		if(event.reason == Reason.FlowingReplace && !Config.isLogged(DataType.WATER_FLOW))
//		{
//			DataManager.addEntry(new BlockChangeEntry(ConstantNames.ENVIRONMENT, DataType.BLOCK_PLACE, event.world, event.x, event.y, event.z, BlockState.from(event.world, event.x, event.y,
//					event.z), new BlockState(event.world, event.x, event.y, event.z, event.block, event.metadata)));
//
//			return;
//		}
//		if(event.block == Block.signWall.blockID || event.block == Block.signPost.blockID)
//			return;
//
//		DataType type = null;
//		String who = ConstantNames.ENVIRONMENT;
//
//		switch(event.reason)
//		{
//		case Entity:
//			type = DataType.ENDERMAN_PLACE;
//			break;
//		case Player:
//			type = event.block == Block.fire.blockID ? DataType.FLINT_AND_STEEL : DataType.BLOCK_PLACE;
//			break;
//		case Environment:
//			type = DataType.BLOCK_FORM;
//			break;
//		case Plant:
//			type = event.getActionerAsPlayer() != null ? DataType.PLAYER_GROW : DataType.BLOCK_FORM;
//			break;
//		case Machine:
//			type = DataType.BLOCK_PLACE;
//			who = "Machine";
//			break;
//
//		case Flowing:
//		case FlowingReplace:
//			if(event.block == Block.lavaMoving.blockID)
//				type = DataType.LAVA_FLOW;
//			else
//				type = DataType.WATER_FLOW;
//			break;
//
//		case TreeGrow:
//			type = DataType.TREE_GROW;
//			break;
//		case Unknown:
//			type = DataType.BLOCK_PLACE;
//			who = "Unknown";
//			break;
//		}
//
//		if(type != null)
//		{
//			if(event.getActionerAsPlayer() != null)
//				who = event.getActionerAsPlayer().username;
//
//			BlockState from = BlockState.from(event.world, event.x, event.y, event.z);
//			BlockState to = new BlockState(event.world, event.x, event.y, event.z, event.block, event.metadata);
//			DataManager.addEntry(new BlockChangeEntry(who, type, event.world, event.x, event.y, event.z, from, to));
//		}
//	}
//
//	@ForgeSubscribe(priority = EventPriority.LOWEST)
//	public void onSignPlace(SignChangeEvent event)
//	{
//		int id = event.world.getBlockId(event.x, event.y, event.z);
//		int data = event.world.getBlockMetadata(event.x, event.y, event.z);
//		DataManager.addEntry(new SignEntry(event.placer, DataType.SIGN_PLACE, event.world, event.x, event.y, event.z, id, data));
//	}
//
//	@ForgeSubscribe(priority = EventPriority.LOWEST)
//	public void onBlockBurn(BlockBurnEvent event)
//	{
//		DataManager.addEntry(new BlockEntry(ConstantNames.ENVIRONMENT, DataType.BLOCK_BURN, event.world, event.x, event.y, event.z, event.block, event.metadata));
//	}
//
//	@ForgeSubscribe(priority = EventPriority.LOWEST)
//	public void onEntityExplode(EntityExplodeEvent event)
//	{
//		String who = ConstantNames.ENVIRONMENT;
//		if(event.player != null)
//		{
//			who = event.player;
//		}
//		else if(event.entity instanceof EntityCreeper)
//		{
//			who = "Creeper";
//			EntityLiving to = ((EntityCreeper) event.entity).getAttackTarget();
//			if(to != null && to.isEntityPlayerMP())
//			{
//				who = ((EntityPlayer) to).username;
//			}
//			else
//			{
//				to = ((EntityCreeper) event.entity).getAITarget();
//				if(to != null && to.isEntityPlayerMP())
//				{
//					who = ((EntityPlayer) to).username;
//				}
//			}
//		}
//		else if(event.entity instanceof EntityTNTPrimed)
//		{
//			who = "TNT";
//		}
//
//		for(ChunkPosition b : event.blocks)
//			DataManager.addEntry(new BlockEntry(who, DataType.EXPLOSION, event.world, b.x, b.y, b.z, event.world.getBlockId(b.x, b.y, b.z), event.world.getBlockMetadata(b.x, b.y,
//					b.z)));
//	}

	/*

	//@HawkEvent(dataType = DataType.SIGN_PLACE)
	public void onSignChange(SignChangeEvent event) {
		DataManager.addEntry(new SignEntry(event.getPlayer(), DataType.SIGN_PLACE, event.getBlock(), event.getLines()));
	}

	//@HawkEvent(dataType = DataType.BLOCK_FORM)
	public void onBlockForm(BlockFormEvent event) {
		DataManager.addEntry(new BlockChangeEntry(ConstantNames.ENVIRONMENT, DataType.BLOCK_FORM, event.getBlock().getLocation(), event.getBlock().getState(), event.getNewState()));
	}

	//@HawkEvent(dataType = DataType.BLOCK_FADE)
	public void onBlockFade(BlockFadeEvent event) {
		DataManager.addEntry(new BlockChangeEntry(ConstantNames.ENVIRONMENT, DataType.BLOCK_FADE, event.getBlock().getLocation(), event.getBlock().getState(), event.getNewState()));
	}

	//@HawkEvent(dataType = DataType.BLOCK_BURN)
	public void onBlockBurn(BlockBurnEvent event) {
		DataManager.addEntry(new BlockEntry(ConstantNames.ENVIRONMENT, DataType.BLOCK_BURN, event.getBlock()));
	}

	//@HawkEvent(dataType = DataType.LEAF_DECAY)
	public void onLeavesDecay(LeavesDecayEvent event) {
		DataManager.addEntry(new SimpleRollbackEntry(ConstantNames.ENVIRONMENT, DataType.LEAF_DECAY, event.getBlock().getLocation(), ""));
	}

	//@HawkEvent(dataType = {DataType.LAVA_FLOW, DataType.WATER_FLOW})
	public void onBlockFromTo(BlockFromToEvent event) {
		List<Integer> fluidBlocks = Arrays.asList(0, 27, 28, 31, 32, 37, 38, 39, 40, 50, 51, 55, 59, 66, 69, 70, 75, 76, 78, 93, 94);

		//Only interested in liquids flowing
		if (!event.getBlock().isLiquid()) return;

		Location loc = event.getToBlock().getLocation();
		BlockState from = event.getBlock().getState();
		BlockState to = event.getToBlock().getState();
		MaterialData data = from.getData();

		//Lava
		if (from.getTypeId() == 10 || from.getTypeId() == 11) {

			//Flowing into a normal block
			if (fluidBlocks.contains(to.getTypeId())) {
				data.setData((byte)(from.getRawData() + 1));
				from.setData(data);
			}

			//Flowing into water
			else if (to.getTypeId() == 8 || to.getTypeId() == 9) {
				from.setTypeId(event.getFace() == BlockFace.DOWN?10:4);
				data.setData((byte)0);
				from.setData(data);
			}
			DataManager.addEntry(new BlockChangeEntry(ConstantNames.ENVIRONMENT, DataType.LAVA_FLOW, loc, to, from));

		}

		//Water
		else if (from.getTypeId() == 8 || from.getTypeId() == 9) {

			//Normal block
			if (fluidBlocks.contains(to.getTypeId())) {
				data.setData((byte)(from.getRawData() + 1));
				from.setData(data);
				DataManager.addEntry(new BlockChangeEntry(ConstantNames.ENVIRONMENT, DataType.WATER_FLOW, loc, to, from));
			}

			//If we are flowing over lava, cobble or obsidian will form
			BlockState lower = event.getToBlock().getRelative(BlockFace.DOWN).getState();
			if (lower.getTypeId() == 10 || lower.getTypeId() == 11) {
				from.setTypeId(lower.getData().getData() == 0?49:4);
				loc.setY(loc.getY() - 1);
				DataManager.addEntry(new BlockChangeEntry(ConstantNames.ENVIRONMENT, DataType.WATER_FLOW, loc, lower, from));
			}

		}

	}
	*/

}
