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

import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SoundPoolEntry;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.Packet250CustomPayload;
import net.minecraftforge.client.event.sound.PlaySoundEffectEvent;
import net.minecraftforge.client.event.sound.SoundEvent;

import org.apache.commons.lang3.StringUtils;

import paulscode.sound.SoundSystem;

import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.kegare.caveworld.core.CaveBiomeManager;
import com.kegare.caveworld.core.CaveBiomeManager.CaveBiome;
import com.kegare.caveworld.core.CaveMiningPlayer;
import com.kegare.caveworld.core.CaveOreManager;
import com.kegare.caveworld.core.CaveOreManager.CaveOre;
import com.kegare.caveworld.core.Config;
import com.kegare.caveworld.util.CaveLog;
import com.kegare.caveworld.world.WorldProviderCaveworld;

import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.common.network.IPacketHandler;
import cpw.mods.fml.common.network.Player;

public class CavePacketHandler implements IPacketHandler
{
	@Override
	public void onPacketData(INetworkManager manager, Packet250CustomPayload packet, Player player)
	{
		ByteArrayDataInput buffer = ByteStreams.newDataInput(packet.data);

		if ("cw:config.sync".equals(packet.channel))
		{
			Config.hardcoreEnabled = buffer.readBoolean();
			Config.deathLoseMiningCount = buffer.readBoolean();
			Config.dimensionCaveworld = buffer.readInt();
			Config.subsurfaceHeight = buffer.readInt();
			Config.generateCaves = buffer.readBoolean();
			Config.generateRavine = buffer.readBoolean();
			Config.generateMineshaft = buffer.readBoolean();
			Config.generateStronghold = buffer.readBoolean();
			Config.generateLakes = buffer.readBoolean();
			Config.generateDungeons = buffer.readBoolean();
			Config.decorateVines = buffer.readBoolean();
		}
		else if ("cw:dim.sync".equals(packet.channel))
		{
			WorldProviderCaveworld.dimensionSeed = Optional.of(buffer.readLong());
			WorldProviderCaveworld.subsurfaceHeight = Optional.of(buffer.readInt());
		}
		else if ("cw:biome.sync".equals(packet.channel))
		{
			String data = buffer.readUTF();

			if (!Strings.isNullOrEmpty(data))
			{
				CaveBiomeManager.clearCaveBiomes();

				try
				{
					if (CaveBiomeManager.loadCaveBiomesFromString(data))
					{
						CaveLog.info("Loaded %d cave biomes from server", CaveBiomeManager.getActiveBiomeCount());
					}
				}
				catch (Exception e)
				{
					CaveLog.log(Level.WARNING, e, "An error occurred trying to loading cave biomes from server");
				}
			}
		}
		else if ("cw:ore.sync".equals(packet.channel))
		{
			String data = buffer.readUTF();

			if (!Strings.isNullOrEmpty(data))
			{
				CaveOreManager.clearCaveOres();

				try
				{
					if (CaveOreManager.loadCaveOresFromString(data))
					{
						CaveLog.info("Loaded %d cave ores from server", CaveOreManager.getCaveOres().size());
					}
				}
				catch (Exception e)
				{
					CaveLog.log(Level.WARNING, e, "An error occurred trying to loading cave ores from server");
				}
			}
		}
		else if ("cw:mining.sync".equals(packet.channel))
		{
			CaveMiningPlayer data = CaveMiningPlayer.get((EntityPlayer)player);

			if (data != null)
			{
				data.setMiningCount(buffer.readInt());
				data.setMiningLevel(buffer.readInt());
			}
		}
		else if ("cw:cavemusic".equals(packet.channel))
		{
			Minecraft mc = FMLClientHandler.instance().getClient();
			String name = buffer.readUTF();

			if (mc != null && !Strings.isNullOrEmpty(name))
			{
				SoundSystem snd = mc.sndManager.sndSystem;
				float master = mc.gameSettings.musicVolume;

				if (master <= 0.0F || name.equalsIgnoreCase("stop"))
				{
					if (snd.playing("CaveMusic"))
					{
						snd.stop("CaveMusic");
					}

					return;
				}

				if (!snd.playing("CaveMusic"))
				{
					float volume = Math.min(0.75F, master);
					SoundPoolEntry entry = mc.sndManager.soundPoolSounds.getRandomSoundFromSoundPool(name);
					entry = SoundEvent.getResult(new PlaySoundEffectEvent(mc.sndManager, entry, name, volume, 1.0F));

					if (entry != null)
					{
						if (snd.playing("BgMusic"))
						{
							snd.stop("BgMusic");
						}

						snd.newSource(true, "CaveMusic", entry.getSoundUrl(), entry.getSoundName(), false, 0.0F, 0.0F, 0.0F, 0, 0.0F);
						snd.setVolume("CaveMusic", volume);
						snd.play("CaveMusic");
					}
				}
			}
		}
	}

	public static Packet getPacketConfigSync()
	{
		ByteArrayDataOutput buffer = ByteStreams.newDataOutput();
		buffer.writeBoolean(Config.hardcoreEnabled);
		buffer.writeBoolean(Config.deathLoseMiningCount);
		buffer.writeInt(Config.dimensionCaveworld);
		buffer.writeInt(Config.subsurfaceHeight);
		buffer.writeBoolean(Config.generateCaves);
		buffer.writeBoolean(Config.generateRavine);
		buffer.writeBoolean(Config.generateMineshaft);
		buffer.writeBoolean(Config.generateStronghold);
		buffer.writeBoolean(Config.generateLakes);
		buffer.writeBoolean(Config.generateDungeons);
		buffer.writeBoolean(Config.decorateVines);

		return new Packet250CustomPayload("cw:config.sync", buffer.toByteArray());
	}

	public static Packet getPacketDimSync()
	{
		ByteArrayDataOutput buffer = ByteStreams.newDataOutput();
		buffer.writeLong(WorldProviderCaveworld.dimensionSeed.or(0L));
		buffer.writeInt(WorldProviderCaveworld.subsurfaceHeight.or(128));

		return new Packet250CustomPayload("cw:dim.sync", buffer.toByteArray());
	}

	public static Packet getPacketCaveBiomeSync()
	{
		ByteArrayDataOutput buffer = ByteStreams.newDataOutput();
		StringBuilder builder = new StringBuilder(1024);

		builder.append('{');

		for (CaveBiome biome : CaveBiomeManager.getCaveBiomes())
		{
			if (biome.itemWeight <= 0)
			{
				continue;
			}

			builder.append(biome).append(',');
		}

		builder.deleteCharAt(builder.lastIndexOf(",")).append('}');

		buffer.writeUTF(StringUtils.deleteWhitespace(builder.toString()));

		return new Packet250CustomPayload("cw:biome.sync", buffer.toByteArray());
	}

	public static Packet getPacketCaveOreSync()
	{
		ByteArrayDataOutput buffer = ByteStreams.newDataOutput();
		StringBuilder builder = new StringBuilder(1024);

		builder.append('[');

		for (CaveOre ore : CaveOreManager.getCaveOres())
		{
			builder.append(ore).append(',');
		}

		builder.deleteCharAt(builder.lastIndexOf(",")).append(']');

		buffer.writeUTF(StringUtils.deleteWhitespace(builder.toString()));

		return new Packet250CustomPayload("cw:ore.sync", buffer.toByteArray());
	}

	public static Packet getPacketMiningSync(int count, int level)
	{
		ByteArrayDataOutput buffer = ByteStreams.newDataOutput();
		buffer.writeInt(count);
		buffer.writeInt(level);

		return new Packet250CustomPayload("cw:mining.sync", buffer.toByteArray());
	}

	public static Packet getPacketCaveMusic(String name)
	{
		ByteArrayDataOutput buffer = ByteStreams.newDataOutput();
		buffer.writeUTF(name);

		return new Packet250CustomPayload("cw:cavemusic", buffer.toByteArray());
	}
}