/*
 * 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.handler;

import java.util.Random;
import java.util.logging.Level;

import mceconomy.api.MCEconomyAPI;
import net.minecraft.block.Block;
import net.minecraft.block.BlockBed;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.passive.EntityBat;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.EnumStatus;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChunkCoordinates;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.sound.SoundLoadEvent;
import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.event.entity.EntityEvent.EntityConstructing;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.event.entity.player.PlayerEvent.BreakSpeed;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action;
import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent;
import net.minecraftforge.event.world.BlockEvent.HarvestDropsEvent;
import net.minecraftforge.event.world.WorldEvent;

import com.kegare.caveworld.block.CaveBlock;
import com.kegare.caveworld.core.CaveMiningPlayer;
import com.kegare.caveworld.core.Config;
import com.kegare.caveworld.plugin.mceconomy.MCEconomyPlugin;
import com.kegare.caveworld.util.CaveLog;
import com.kegare.caveworld.util.CaveUtils;
import com.kegare.caveworld.world.WorldProviderCaveworld;

import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

public class CaveEventHooks
{
	@SideOnly(Side.CLIENT)
	@ForgeSubscribe
	public void onSoundLoad(SoundLoadEvent event)
	{
		try
		{
			event.manager.addSound("caveworld:caveworld_portal.ogg");
			event.manager.addSound("caveworld:ambient/cave.ogg");
		}
		catch (Exception e)
		{
			CaveLog.log(Level.WARNING, e, "An error occurred trying to loading cave sounds");
		}
	}

	@SideOnly(Side.CLIENT)
	@ForgeSubscribe
	public void onRenderGameOverlay(RenderGameOverlayEvent.Text event)
	{
		Minecraft mc = FMLClientHandler.instance().getClient();

		if (mc.thePlayer != null && mc.thePlayer.dimension == Config.dimensionCaveworld)
		{
			if (mc.gameSettings.showDebugInfo)
			{
				event.left.add("dim: Caveworld");
			}
			else if ((mc.gameSettings.advancedItemTooltips || mc.thePlayer.isSneaking()) && CaveUtils.isItemPickaxe(mc.thePlayer.getHeldItem()))
			{
				CaveMiningPlayer data = CaveMiningPlayer.get(mc.thePlayer);
				int count = data.getMiningCount();

				if (count > 0)
				{
					int level = data.getMiningLevel();
					StringBuilder builder = new StringBuilder();

					builder.append(I18n.getString("caveworld.mining.count")).append(": ").append(count);

					if (level > 0)
					{
						builder.append(" (").append(level).append(')');
					}

					event.right.add(builder.toString());
				}
			}
		}
	}

	@ForgeSubscribe
	public void onHarvestDrops(HarvestDropsEvent event)
	{
		if (event.harvester != null && event.harvester instanceof EntityPlayerMP)
		{
			EntityPlayerMP player = (EntityPlayerMP)event.harvester;

			if (player.dimension == Config.dimensionCaveworld)
			{
				if (CaveUtils.isItemPickaxe(player.getCurrentEquippedItem()) && CaveUtils.isOreBlock(event.block, event.blockMetadata))
				{
					CaveMiningPlayer.get(player).addMiningCount(1);
				}
			}
		}
	}

	@ForgeSubscribe
	public void onBreakSpeed(BreakSpeed event)
	{
		EntityPlayer player = event.entityPlayer;

		if (player != null && player.dimension == Config.dimensionCaveworld && player.isSneaking())
		{
			if (CaveUtils.isItemPickaxe(player.getCurrentEquippedItem()) && CaveUtils.isOreBlock(event.block, event.metadata))
			{
				int level = CaveMiningPlayer.get(player).getMiningLevel();

				if (level > 0)
				{
					event.newSpeed *= Math.min(1.25F + 0.25F * level, 3.0F);
				}
			}
		}
	}

	@ForgeSubscribe
	public void onPlayerInteract(PlayerInteractEvent event)
	{
		if (event.entityPlayer instanceof EntityPlayerMP && event.action == Action.RIGHT_CLICK_BLOCK)
		{
			EntityPlayerMP player = (EntityPlayerMP)event.entityPlayer;
			ItemStack current = player.getCurrentEquippedItem();
			WorldServer world = player.getServerForPlayer();
			int x = event.x;
			int y = event.y;
			int z = event.z;
			int face = event.face;

			if (!player.isSneaking() && current != null && current.itemID == Block.enderChest.blockID)
			{
				if (face == 0)
				{
					--y;
				}
				else if (face == 1)
				{
					++y;
				}
				else if (face == 2)
				{
					--z;
				}
				else if (face == 3)
				{
					++z;
				}
				else if (face == 4)
				{
					--x;
				}
				else if (face == 5)
				{
					++x;
				}

				while (!world.doesBlockHaveSolidTopSurface(x, y - 1, z) && y > 0)
				{
					--y;
				}

				if (CaveBlock.portalCaveworld.tryToCreatePortal(world, x, y, z))
				{
					world.playSoundEffect(x + 0.5D, y + 0.5D, z + 0.5D, CaveBlock.portalCaveworld.stepSound.getPlaceSound(), 1.0F, 2.0F);

					event.setCanceled(true);
				}
			}
			else if (player.dimension == Config.dimensionCaveworld && world.getBlockId(x, y, z) == Block.bed.blockID)
			{
				int metadata = world.getBlockMetadata(x, y, z);

				if (!BlockBed.isBlockHeadOfBed(metadata))
				{
					int var1 = BlockBed.getDirection(metadata);
					x += BlockBed.footBlockToHeadBlockMap[var1][0];
					z += BlockBed.footBlockToHeadBlockMap[var1][1];

					if (world.getBlockId(x, y, z) != Block.bed.blockID)
					{
						return;
					}

					metadata = world.getBlockMetadata(x, y, z);
				}

				if (BlockBed.isBedOccupied(metadata))
				{
					for (Object obj : world.playerEntities)
					{
						EntityPlayer target = (EntityPlayer)obj;

						if (target.isPlayerSleeping())
						{
							ChunkCoordinates coord = target.playerLocation;

							if (coord.posX == x && coord.posY == y && coord.posZ == z)
							{
								player.addChatMessage("tile.bed.occupied");

								return;
							}
						}
					}

					BlockBed.setBedOccupied(world, x, y, z, false);
				}

				EnumStatus status = player.sleepInBedAt(x, y, z);

				if (status == EnumStatus.OK)
				{
					BlockBed.setBedOccupied(world, x, y, z, true);
				}
				else
				{
					if (status == EnumStatus.NOT_POSSIBLE_NOW)
					{
						player.addChatMessage("tile.bed.noSleep");
					}
					else if (status == EnumStatus.NOT_SAFE)
					{
						player.addChatMessage("tile.bed.notSafe");
					}
				}

				event.setCanceled(true);
			}
		}
	}

	@ForgeSubscribe
	public void onPlayerSleepInBed(PlayerSleepInBedEvent event)
	{
		if (event.entityPlayer instanceof EntityPlayerMP)
		{
			EntityPlayerMP player = (EntityPlayerMP)event.entityPlayer;
			WorldServer world = player.getServerForPlayer();

			if (player.dimension == Config.dimensionCaveworld && !player.capabilities.isCreativeMode)
			{
				NBTTagCompound data = player.getEntityData();
				ChunkCoordinates spawn = player.getBedLocation(player.dimension);

				if (data.getLong("Caveworld:LastSleepTime") + 6000L > world.getTotalWorldTime())
				{
					event.result = EnumStatus.OTHER_PROBLEM;
				}
				else if (spawn != null && player.getDistance(spawn.posX, spawn.posY, spawn.posZ) <= 32.0D)
				{
					event.result = EnumStatus.OTHER_PROBLEM;
				}

				if (event.result == null)
				{
					data.setLong("Caveworld:LastSleepTime", world.getTotalWorldTime());
				}
			}
		}
	}

	@ForgeSubscribe
	public void onEntityConstructing(EntityConstructing event)
	{
		if (event.entity instanceof EntityPlayer)
		{
			EntityPlayer player = (EntityPlayer)event.entity;

			if (CaveMiningPlayer.get(player) == null)
			{
				CaveMiningPlayer.register(player);
			}
		}
	}

	@ForgeSubscribe
	public void onEntityJoinWorld(EntityJoinWorldEvent event)
	{
		Entity entity = event.entity;
		World world = event.world;

		if (entity instanceof EntityPlayerMP)
		{
			CaveMiningPlayer.loadMiningData((EntityPlayerMP)entity);
		}

		if (entity.dimension == Config.dimensionCaveworld)
		{
			if (entity instanceof EntityBat)
			{
				entity.getEntityData().setBoolean("Caveworld:CaveBat", true);
			}

			if (entity instanceof EntityLiving)
			{
				if (entity.posY >= world.provider.getActualHeight() - 1)
				{
					event.setCanceled(true);
				}
			}
		}
	}

	@ForgeSubscribe
	public void onLivingUpdate(LivingUpdateEvent event)
	{
		EntityLivingBase living = event.entityLiving;

		if (living.dimension == Config.dimensionCaveworld && living.ticksExisted % 20 == 0)
		{
			if (living instanceof EntityPlayerMP)
			{
				EntityPlayerMP player = (EntityPlayerMP)living;

				if (player.isPlayerSleeping() && player.getSleepTimer() >= 80)
				{
					player.wakeUpPlayer(true, true, false);

					player.setSpawnChunk(player.playerLocation, true, player.dimension);
				}
			}
		}
	}

	@ForgeSubscribe
	public void onLivingDeathEvent(LivingDeathEvent event)
	{
		if (event.entityLiving instanceof EntityPlayerMP)
		{
			if (!Config.deathLoseMiningCount)
			{
				CaveMiningPlayer.saveMiningData((EntityPlayerMP)event.entityLiving);
			}
		}
	}

	@ForgeSubscribe
	public void onLivingDrops(LivingDropsEvent event)
	{
		EntityLivingBase living = event.entityLiving;
		Entity entity = event.source.getEntity();

		if (entity != null && entity instanceof EntityPlayerMP)
		{
			EntityPlayerMP player = (EntityPlayerMP)entity;
			Random random = living.getRNG();
			int looting = MathHelper.clamp_int(event.lootingLevel, 0, 3);

			if (MCEconomyPlugin.MCECONOMY && living.dimension == Config.dimensionCaveworld && living instanceof IMob)
			{
				MCEconomyAPI.addPlayerMP(player, random.nextInt(3) + Math.max(looting, 1));
			}

			if (living instanceof EntityBat && living.getEntityData().getBoolean("Caveworld:CaveBat"))
			{
				EntityItem item = new EntityItem(living.worldObj, living.posX, living.posY + 0.5D, living.posZ);
				item.delayBeforeCanPickup = 10;

				if (random.nextInt(4) <= looting)
				{
					item.setEntityItemStack(new ItemStack(Item.leather));
				}
				else
				{
					item.setEntityItemStack(new ItemStack(Item.coal, random.nextInt(3) + looting));
				}

				event.drops.add(item);
			}
		}
	}

	@ForgeSubscribe
	public void onWorldLoad(WorldEvent.Load event)
	{
		World world = event.world;

		if (!world.isRemote && world.provider.dimensionId == Config.dimensionCaveworld)
		{
			CaveBlock.portalCaveworld.inventory.loadInventoryFromNBT();
		}
	}

	@ForgeSubscribe
	public void onWorldUnload(WorldEvent.Unload event)
	{
		World world = event.world;

		if (!world.isRemote && world.provider.dimensionId == Config.dimensionCaveworld)
		{
			WorldProviderCaveworld.writeDimData();
			WorldProviderCaveworld.clearDimData();
		}
	}

	@ForgeSubscribe
	public void onWorldSave(WorldEvent.Save event)
	{
		World world = event.world;

		if (!world.isRemote && world.provider.dimensionId == Config.dimensionCaveworld)
		{
			CaveBlock.portalCaveworld.inventory.saveInventoryToNBT();
		}
	}
}