package protocolsupport.protocol.legacyremapper.chunk;

import java.util.Arrays;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import protocolsupport.api.ProtocolVersion;
import protocolsupport.protocol.serializer.VarNumberSerializer;
import protocolsupport.utils.Utils;

public abstract class ChunkTransformer {

	public static enum BlockFormat {
		VARIES, //format for 1.9+
		SHORT, //format for 1.8
		BYTE, //format for 1.7-
	}

	public static ChunkTransformer create(BlockFormat format) {
		switch (format) {
			case VARIES: {
				return new ChunkTransformerVaries();
			}
			case SHORT: {
				return new ChunkTransformerShort();
			}
			case BYTE: {
				return new ChunkTransformerByte();
			}
			default: {
				throw new IllegalArgumentException();
			}
		}
	}

	protected byte[] data;
	protected int bitmap;

	protected int columnsCount;
	protected boolean hasSkyLight;
	protected boolean hasBiomeData;
	protected final ChunkSection[] sections = new ChunkSection[16];
	protected final byte[] biomeData = new byte[256];

	public void loadData(byte[] data, int bitmap, boolean hasSkyLight, boolean hasBiomeData) {
		try {
			this.data = data;
			this.bitmap = bitmap;
			this.columnsCount = Integer.bitCount(bitmap);
			this.hasSkyLight = hasSkyLight;
			this.hasBiomeData = hasBiomeData;
			ByteBuf chunkdata = Unpooled.wrappedBuffer(data);
			for (int i = 0; i < this.columnsCount; i++) {
				sections[i] = new ChunkSection(chunkdata, hasSkyLight);
			}
			if (hasBiomeData) {
				chunkdata.readBytes(biomeData);
			}
		} catch (Throwable e) {
			throw new ChunkDataParseException(data, bitmap, hasSkyLight, hasBiomeData, e);
		}
	}

	public byte[] toLegacyData(ProtocolVersion version) {
		try {
			return toLegacyData0(version);
		} catch (Throwable t) {
			throw new ChunkDataParseException(data, bitmap, hasSkyLight, hasBiomeData, t);
		}
	}

	protected abstract byte[] toLegacyData0(ProtocolVersion version);

	protected static final int blocksInSection = 16 * 16 * 16;

	protected static class ChunkSection {

		private static final int[] globalpalette = new int[Short.MAX_VALUE * 2];
		static {
			for (int i = 0; i < globalpalette.length; i++) {
				globalpalette[i] = i;
			}
		}

		protected final BlockStorageReader blockdata;
		protected final byte[] blocklight = new byte[2048];
		protected final byte[] skylight = new byte[2048];

		public ChunkSection(ByteBuf datastream, boolean hasSkyLight) {
			byte bitsPerBlock = datastream.readByte();
			int[] palette = globalpalette;
			int palettelength = VarNumberSerializer.readVarInt(datastream);
			if (palettelength != 0) {
				palette = new int[palettelength];
				for (int i = 0; i < palette.length; i++) {
					palette[i] = VarNumberSerializer.readVarInt(datastream);
				}
			}
			this.blockdata = new BlockStorageReader(palette, bitsPerBlock, VarNumberSerializer.readVarInt(datastream));
			this.blockdata.readFromStream(datastream);
			datastream.readBytes(blocklight);
			if (hasSkyLight) {
				datastream.readBytes(skylight);
			}
		}

	}

	public static final class ChunkDataParseException extends RuntimeException {
		private static final long serialVersionUID = 1L;

		public ChunkDataParseException(byte[] data, int bitmap, boolean hasSkyLight, boolean hasBiomeData, Throwable e) {
			super(Utils.exceptionMessage(
				"Failed to parse chunk data",
				String.format("Column bitmap: %s (Column count: %d)", Integer.toBinaryString(bitmap), Integer.bitCount(bitmap)),
				String.format("Has sky light: %b", hasSkyLight),
				String.format("Has biome data: %b", hasBiomeData),
				String.format("Chunk data: %s", Arrays.toString(data))
			), e);
		}
	}

}

@@ -53,34 +53,8 @@
 k;%0A%0A
-import java.util.Arrays;%0A%0A
 impo
@@ -225,44 +225,8 @@
 zer;
-%0Aimport protocolsupport.utils.Utils;
 %0A%0Apu
@@ -723,56 +723,8 @@
 %09%7D%0A%0A
-%09protected byte%5B%5D data;%0A%09protected int bitmap;%0A%0A
 %09pro
@@ -1026,63 +1026,8 @@
 ) %7B%0A
-%09%09try %7B%0A%09%09%09this.data = data;%0A%09%09%09this.bitmap = bitmap;%0A%09
 %09%09th
@@ -1068,25 +1068,24 @@
 (bitmap);%0A%09%09
-%09
 this.hasSkyL
@@ -1104,17 +1104,16 @@
 yLight;%0A
-%09
 %09%09this.h
@@ -1142,17 +1142,16 @@
 Data;%0A%09%09
-%09
 ByteBuf 
@@ -1194,17 +1194,16 @@
 ata);%0A%09%09
-%09
 for (int
@@ -1240,17 +1240,16 @@
  i++) %7B%0A
-%09
 %09%09%09secti
@@ -1301,20 +1301,18 @@
 ght);%0A%09%09
-%09
 %7D%0A
-%09
 %09%09if (ha
@@ -1328,17 +1328,16 @@
 a) %7B%0A%09%09%09
-%09
 chunkdat
@@ -1364,121 +1364,8 @@
 a);%0A
-%09%09%09%7D%0A%09%09%7D catch (Throwable e) %7B%0A%09%09%09throw new ChunkDataParseException(data, bitmap, hasSkyLight, hasBiomeData, e);%0A
 %09%09%7D%0A
@@ -1427,17 +1427,8 @@
 ) %7B%0A
-%09%09try %7B%0A%09
 %09%09re
@@ -1460,120 +1460,8 @@
 n);%0A
-%09%09%7D catch (Throwable t) %7B%0A%09%09%09throw new ChunkDataParseException(data, bitmap, hasSkyLight, hasBiomeData, t);%0A%09%09%7D%0A
 %09%7D%0A%0A
@@ -2627,621 +2627,6 @@
 %09%7D%0A%0A
-%09public static final class ChunkDataParseException extends RuntimeException %7B%0A%09%09private static final long serialVersionUID = 1L;%0A%0A%09%09public ChunkDataParseException(byte%5B%5D data, int bitmap, boolean hasSkyLight, boolean hasBiomeData, Throwable e) %7B%0A%09%09%09super(Utils.exceptionMessage(%0A%09%09%09%09%22Failed to parse chunk data%22,%0A%09%09%09%09String.format(%22Column bitmap: %25s (Column count: %25d)%22, Integer.toBinaryString(bitmap), Integer.bitCount(bitmap)),%0A%09%09%09%09String.format(%22Has sky light: %25b%22, hasSkyLight),%0A%09%09%09%09String.format(%22Has biome data: %25b%22, hasBiomeData),%0A%09%09%09%09String.format(%22Chunk data: %25s%22, Arrays.toString(data))%0A%09%09%09), e);%0A%09%09%7D%0A%09%7D%0A%0A
 %7D%0A

Remove no longer needed exception, packet contents is printed now instead