package client.renderer.tileentity;

import java.util.Map;

import org.lwjgl.opengl.GL13;

import client.renderer.GlState;
import common.collect.Maps;
import common.entity.Entity;
import common.tileentity.TileEntity;
import common.tileentity.TileEntityDisplay;
import common.tileentity.TileEntityItemPipe;
import common.tileentity.TileEntitySign;
import common.util.BlockPos;
import common.world.World;

public class SpecialRenderer {
	public static SpecialRenderer instance = new SpecialRenderer();
	public static double entityX; // TODO: useless duplicate render view entity position?
	public static double entityY;
	public static double entityZ;

	private final Map<Class<? extends TileEntity>, ElementRenderer<? extends TileEntity>> renderers = Maps.<Class<? extends TileEntity>, ElementRenderer<? extends TileEntity>>newHashMap();

	private World world;
	private double posX;
	private double posY;
	private double posZ;

	private SpecialRenderer() {
		this.renderers.put(TileEntitySign.class, new SignRenderer());
		this.renderers.put(TileEntityDisplay.class, new DisplayRenderer());
		this.renderers.put(TileEntityItemPipe.class, new ItemPipeRenderer());
	}

	private <T extends TileEntity> ElementRenderer<T> getRenderer(Class<? extends TileEntity> clazz) {
		ElementRenderer<? extends TileEntity> renderer = (ElementRenderer)this.renderers.get(clazz);
		if(renderer == null && clazz != TileEntity.class) {
			renderer = this.<TileEntity>getRenderer((Class<? extends TileEntity>)clazz.getSuperclass());
			this.renderers.put(clazz, renderer);
		}
		return (ElementRenderer<T>)renderer;
	}

	public <T extends TileEntity> ElementRenderer<T> getRenderer(TileEntity tile) {
		return (ElementRenderer<T>)(tile == null ? null : this.getRenderer(tile.getClass()));
	}

	public void setPosition(World world, Entity entity, float partial) {
		this.world = world;
		this.posX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * (double)partial;
		this.posY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * (double)partial;
		this.posZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * (double)partial;
	}

	public void renderTile(TileEntity tile, float partial) {
		if(tile.getDistanceSq(this.posX, this.posY, this.posZ) < tile.getMaxRenderDistanceSquared()) {
			int light = this.world.getCombinedLight(tile.getPos(), 0);
			int block = light % 65536;
			int sky = light / 65536;
			GL13.glMultiTexCoord2f(GL13.GL_TEXTURE1, (float)block / 1.0F, (float)sky / 1.0F);
			GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
			BlockPos pos = tile.getPos();
			this.render(tile, (double)pos.getX() - entityX, (double)pos.getY() - entityY, (double)pos.getZ() - entityZ, partial);
		}
	}

	private void render(TileEntity tile, double x, double y, double z, float partial) {
		ElementRenderer<TileEntity> renderer = this.<TileEntity>getRenderer(tile);
		if(renderer != null)
			renderer.renderElements(tile, x, y, z, partial);
	}
}
