package net.minecraft.network.play.server;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

import com.google.common.collect.Lists;

import net.hoosiertransfer.Alfheim.ILightingEngineProvider;
import net.lax1dude.eaglercraft.v1_8.netty.ByteBuf;
import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.INetHandlerPlayClient;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockPos;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;

/**
 * +
 * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code.
 * 
 * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!"
 * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team
 * 
 * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, hoosiertransfer,
 * ayunami2000. All Rights Reserved.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 */
public class S21PacketChunkData implements Packet<INetHandlerPlayClient> {
	private int chunkX;
	private int chunkZ;
	private int availableSections;
	private byte[] buffer;
	private List<NBTTagCompound> field_189557_e;
	private boolean loadChunk;

	public S21PacketChunkData() {
	}

	public S21PacketChunkData(Chunk p_i47124_1_, int p_i47124_2_) {
		this.chunkX = p_i47124_1_.xPosition;
		this.chunkZ = p_i47124_1_.zPosition;
		this.loadChunk = p_i47124_2_ == 65535;
		boolean flag = !p_i47124_1_.getWorld().provider.getHasNoSky();
		this.buffer = new byte[this.func_189556_a(p_i47124_1_, flag, p_i47124_2_)];
		this.availableSections = this.func_189555_a(new PacketBuffer(this.getWriteBuffer()), p_i47124_1_, flag,
				p_i47124_2_);
		this.field_189557_e = Lists.<NBTTagCompound>newArrayList();

		for (Entry<BlockPos, TileEntity> entry : p_i47124_1_.getTileEntityMap().entrySet()) {
			BlockPos blockpos = (BlockPos) entry.getKey();
			TileEntity tileentity = (TileEntity) entry.getValue();
			int i = blockpos.getY() >> 4;

			if (this.doChunkLoad() || (p_i47124_2_ & 1 << i) != 0) {
				NBTTagCompound nbttagcompound = tileentity.func_189517_E_();
				this.field_189557_e.add(nbttagcompound);
			}
		}
	}

	public void readPacketData(PacketBuffer buf) throws IOException {
		this.chunkX = buf.readInt();
		this.chunkZ = buf.readInt();
		this.loadChunk = buf.readBoolean();
		this.availableSections = buf.readVarIntFromBuffer();
		int i = buf.readVarIntFromBuffer();

		if (i > 2097152) {
			throw new RuntimeException("Chunk Packet trying to allocate too much memory on read.");
		} else {
			this.buffer = new byte[i];
			buf.readBytes(this.buffer);
			int j = buf.readVarIntFromBuffer();
			this.field_189557_e = Lists.<NBTTagCompound>newArrayList();

			for (int k = 0; k < j; ++k) {
				this.field_189557_e.add(buf.readNBTTagCompoundFromBuffer());
			}
		}
	}

	public void writePacketData(PacketBuffer buf) throws IOException {
		buf.writeInt(this.chunkX);
		buf.writeInt(this.chunkZ);
		buf.writeBoolean(this.loadChunk);
		buf.writeVarIntToBuffer(this.availableSections);
		buf.writeVarIntToBuffer(this.buffer.length);
		buf.writeBytes(this.buffer);
		buf.writeVarIntToBuffer(this.field_189557_e.size());

		for (NBTTagCompound nbttagcompound : this.field_189557_e) {
			buf.writeNBTTagCompoundToBuffer(nbttagcompound);
		}
	}

	public void processPacket(INetHandlerPlayClient handler) {
		handler.handleChunkData(this);
	}

	public PacketBuffer getReadBuffer() {
		return new PacketBuffer(Unpooled.buffer(this.buffer.length).writeBytes(this.buffer));
	}

	private ByteBuf getWriteBuffer() {
		ByteBuf bytebuf = Unpooled.wrappedBuffer(this.buffer);
		bytebuf.writerIndex(0);
		return bytebuf;
	}

	public int func_189555_a(PacketBuffer p_189555_1_, Chunk p_189555_2_, boolean p_189555_3_, int p_189555_4_) {
		int i = 0;
		ExtendedBlockStorage[] aextendedblockstorage = p_189555_2_.getBlockStorageArray();
		int j = 0;

		for (int k = aextendedblockstorage.length; j < k; ++j) {
			ExtendedBlockStorage extendedblockstorage = aextendedblockstorage[j];

			if (extendedblockstorage != Chunk.NULL_BLOCK_STORAGE
					&& (!this.doChunkLoad() || !extendedblockstorage.isEmpty()) && (p_189555_4_ & 1 << j) != 0) {
				i |= 1 << j;
				extendedblockstorage.getData().write(p_189555_1_);
				p_189555_1_.writeBytes(extendedblockstorage.getBlocklightArray().getData());

				if (p_189555_3_) {
					p_189555_1_.writeBytes(extendedblockstorage.getSkylightArray().getData());
				}
			}
		}

		if (this.doChunkLoad()) {
			p_189555_1_.writeBytes(p_189555_2_.getBiomeArray());
		}

		return i;
	}

	protected int func_189556_a(Chunk p_189556_1_, boolean p_189556_2_, int p_189556_3_) {
		int i = 0;
		ExtendedBlockStorage[] aextendedblockstorage = p_189556_1_.getBlockStorageArray();
		int j = 0;

		for (int k = aextendedblockstorage.length; j < k; ++j) {
			ExtendedBlockStorage extendedblockstorage = aextendedblockstorage[j];

			if (extendedblockstorage != Chunk.NULL_BLOCK_STORAGE
					&& (!this.doChunkLoad() || !extendedblockstorage.isEmpty()) && (p_189556_3_ & 1 << j) != 0) {
				i = i + extendedblockstorage.getData().getSerializedSize();
				i = i + extendedblockstorage.getBlocklightArray().getData().length;

				if (p_189556_2_) {
					i += extendedblockstorage.getSkylightArray().getData().length;
				}
			}
		}

		if (this.doChunkLoad()) {
			i += p_189556_1_.getBiomeArray().length;
		}

		return i;
	}

	public int getChunkX() {
		return this.chunkX;
	}

	public int getChunkZ() {
		return this.chunkZ;
	}

	public int getExtractedSize() {
		return this.availableSections;
	}

	public boolean doChunkLoad() {
		return this.loadChunk;
	}

	public List<NBTTagCompound> func_189554_f() {
		return this.field_189557_e;
	}
}