package client.world;

import java.util.List;
import java.util.function.Predicate;

import common.block.Block;
import common.block.natural.BlockFire;
import common.collect.Lists;
import common.entity.Entity;
import common.init.BlockRegistry;
import common.init.Blocks;
import common.tileentity.TileEntity;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.ExtMath;
import common.world.LightType;
import common.world.State;
import common.world.World;

public class ChunkEmpty extends ChunkClient {
	private static final List<State> STATES = Lists.<State>newArrayList();
	private static final int XSTRETCH;
	private static final int ZSTRETCH;
	
	private final boolean debug;
	private final int liquidY;
	private final State liquid;
	private final Block liquidBlock;
	private final State dummy;
	private final Block dummyBlock;
	
	static {
		for(Block block : BlockRegistry.blocks()) {
			if(block instanceof BlockFire)
				STATES.add(block.getState());
			else
				STATES.addAll(block.getValidStates());
		}
		XSTRETCH = ExtMath.ceilf(ExtMath.sqrtf((float)STATES.size()));
		ZSTRETCH = ExtMath.ceilf((float)STATES.size() / (float)XSTRETCH);
	}

	private static State getDebug(int x, int z) {
		State state = null;
		if(x > 0 && z > 0 && x % 2 != 0 && z % 2 != 0) {
			x = x / 2;
			z = z / 2;
			if(x <= XSTRETCH && z <= ZSTRETCH) {
				int idx = ExtMath.absi(x * XSTRETCH + z);
				if(idx < STATES.size()) {
					state = STATES.get(idx);
				}
			}
		}
		return state;
	}
	
	public ChunkEmpty(World world, boolean out, boolean debug) {
		super(world, out ? Integer.MAX_VALUE : 0, 0);
		this.debug = debug;
		this.liquidY = world.dimension.getSeaLevel() - 1;
		this.liquid = out || world.dimension.isExterminated() ? Blocks.air.getState() : world.dimension.getLiquid();
		this.liquidBlock = this.liquid.getBlock();
		this.dummyBlock = this.fillerBlock == Blocks.air ? Blocks.air : Blocks.bedrock;
		this.dummy = this.dummyBlock.getState();
	}

	public int getHeight(int x, int z) {
		return this.liquidY;
	}

	public Block getBlock(BlockPos pos) {
		return pos.getY() < this.liquidY ? this.dummyBlock : (pos.getY() == this.liquidY ? this.liquidBlock : Blocks.air);
	}

	public int getLight(LightType type, BlockPos pos) {
		return type.defValue;
	}

	public void setLight(LightType type, BlockPos pos, int value) {
	}

	public int getLightSub(BlockPos pos, int amount) {
		return 0;
	}

	public void addEntity(Entity entity) {
	}

	public void removeEntity(Entity entity) {
	}

	public boolean canSeeSky(BlockPos pos) {
		return pos.getY() > this.liquidY;
	}

	public TileEntity getTileEntity(BlockPos pos, TileEntity.CreateMode type) {
		return null;
	}

	public void addTileEntity(BlockPos pos, TileEntity tile) {
	}

	public void removeTileEntity(BlockPos pos) {
	}
	
	public void getEntities(Entity exclude, BoundingBox bb, List<Entity> list, Predicate<? super Entity> pred) {
	}

	public <T extends Entity> void getEntities(Class<? extends T> clazz, BoundingBox bb, List<T> list, Predicate<? super T> pred) {
	}

	public boolean isDummy() {
		return true;
	}

	public boolean isEmpty(int bottom, int top) {
		return top < 0 || bottom > this.liquidY;
	}

	public State getState(BlockPos pos) {
		if(this.debug) {
			State state = pos.getY() == 1 ? getDebug(pos.getX(), pos.getZ()) : null;
			return state == null ? Blocks.air.getState() : state;
		}
		return pos.getY() < this.liquidY ? this.dummy : (pos.getY() == this.liquidY ? this.liquid : Blocks.air.getState());
	}

	public State setState(BlockPos pos, State state) {
		return null;
	}
	
	public BlockPos getPrecipitation(BlockPos pos) {
		return new BlockPos(pos.getX(), this.liquidY + 1, pos.getZ());
	}

	public void update(boolean noGaps) {
	}
	
	public void onChunkUnload() {
	}

	public boolean isPopulated() {
		return true;
	}

	public void setData(byte[] data, int[] extend, boolean biomes) {
	}
	
	public float getTemperature(BlockPos pos) {
		return 0.0f;
	}
	
	public float getOffset(BlockPos pos) {
		return 0.0f;
	}

	public void resetRelight() {
	}

	public void enqueueRelight() {
	}

	public void checkLight() {
	}

	public boolean isLoaded() {
		return false;
	}

	public void setLoaded() {
	}

	public int getLowest() {
		return 0;
	}
}
