package erogenousbeef.bigreactors.client.renderer;

import net.minecraft.block.Block;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.IIcon;
import net.minecraft.world.IBlockAccess;

import org.lwjgl.opengl.GL11;

import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
import erogenousbeef.bigreactors.api.data.ReactantData;
import erogenousbeef.bigreactors.api.registry.Reactants;
import erogenousbeef.bigreactors.common.BigReactors;
import erogenousbeef.bigreactors.common.data.StandardReactants;
import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor;
import erogenousbeef.bigreactors.common.multiblock.block.BlockFuelRod;
import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorFuelRod;

public class SimpleRendererFuelRod implements ISimpleBlockRenderingHandler {

	private static final float FLUID_RENDER_OFFSET_MAX = 0.05f;
	private static final float FLUID_RENDER_OFFSET_MIN = 0.45f;
	
	public SimpleRendererFuelRod() {
	}

	@Override
	public void renderInventoryBlock(Block block, int metadata, int modelID,
			RenderBlocks renderer) {
		Tessellator tessellator = Tessellator.instance;
        GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
        tessellator.startDrawingQuads();
        tessellator.setNormal(0.0F, -1.0F, 0.0F);
        renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 0, metadata));
        tessellator.draw();
        tessellator.startDrawingQuads();
        tessellator.setNormal(0.0F, 1.0F, 0.0F);
        renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 1, metadata));
        tessellator.draw();
        tessellator.startDrawingQuads();
        tessellator.setNormal(0.0F, 0.0F, -1.0F);
        renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 2, metadata));
        tessellator.draw();
        tessellator.startDrawingQuads();
        tessellator.setNormal(0.0F, 0.0F, 1.0F);
        renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 3, metadata));
        tessellator.draw();
        tessellator.startDrawingQuads();
        tessellator.setNormal(-1.0F, 0.0F, 0.0F);
        renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 4, metadata));
        tessellator.draw();
        tessellator.startDrawingQuads();
        tessellator.setNormal(1.0F, 0.0F, 0.0F);
        renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 5, metadata));
        tessellator.draw();
        GL11.glTranslatef(0.5F, 0.5F, 0.5F);
	}

	@Override
	public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z,
			Block block, int modelId, RenderBlocks renderer) {
		if(!(block instanceof BlockFuelRod)) { return false; }

        Tessellator tessellator = Tessellator.instance;

        boolean renderTop = block.shouldSideBeRendered(world, x, y + 1, z, 0);
        boolean renderBottom = block.shouldSideBeRendered(world, x, y - 1, z, 0);
        boolean renderedFuelOnTop = false;
        boolean renderedFuelOnBottom = false;
        
        boolean[] renderSides = new boolean[]
        {
            block.shouldSideBeRendered(world, x, y, z - 1, 2), 
            block.shouldSideBeRendered(world, x, y, z + 1, 3),
            block.shouldSideBeRendered(world, x - 1, y, z, 4), 
            block.shouldSideBeRendered(world, x + 1, y, z, 5)
        };

        if (!renderTop && !renderBottom && !renderSides[0] && !renderSides[1] && !renderSides[2] && !renderSides[3])
        {
            return false;
        }

        boolean rendered = false;
        int blockMetadata = world.getBlockMetadata(x, y, z);
        
        // Render internal bits, if we can
        TileEntity te;
        te = world.getTileEntity(x, y, z);
        if(te instanceof TileEntityReactorFuelRod) {
        	TileEntityReactorFuelRod fuelRod = (TileEntityReactorFuelRod)te;
        	if(fuelRod.isConnected()) {
        		MultiblockReactor reactor = (MultiblockReactor)fuelRod.getMultiblockController();
        		int fuelAmount = reactor.getFuelAmount();
        		int wasteAmount = reactor.getWasteAmount();
        		int totalFluid = fuelAmount + wasteAmount;
        		int capacity = reactor.getCapacity();
        		if(capacity > 0 && totalFluid > 0) {
        			// Okay, we're connected and have some kind of fluid inside. Let's do this.
        	        float fluidColumnOffsetFromCenter = -1f;
        	        float red, green, blue;
        	        IIcon iconSide, iconBottom;
        	        iconSide = iconBottom = null;
        	        red = green = blue = 1f;

    	    		iconSide = BigReactors.fluidFuelColumn.getFlowingIcon();
    	    		iconBottom = BigReactors.fluidFuelColumn.getStillIcon();

    	    		ReactantData fuelData = Reactants.getReactant(reactor.getFuelType());
    	    		ReactantData wasteData = Reactants.getReactant(reactor.getWasteType());
        	        
    	    		int fuelColor = fuelData != null ? fuelData.getColor() : StandardReactants.colorYellorium;
    	    		int wasteColor = wasteData != null ? wasteData.getColor() : StandardReactants.colorCyanite;
    	    		
        	    	if(fuelAmount == 0) {
        	        	red = unpackR(wasteColor);
        	        	green = unpackG(wasteColor);
        	        	blue = unpackB(wasteColor);
        	    	}
        	    	else if(fuelAmount >= totalFluid) {
        	        	red = unpackR(fuelColor);
        	        	green = unpackG(fuelColor);
        	        	blue = unpackB(fuelColor);
        	    	}
        	    	else {
        	        	// Blend the colors
        	        	float proportion = (float)fuelAmount / (float)totalFluid;
        	        	float fuelR, fuelG, fuelB;
        	        	float wasteR, wasteG, wasteB;

        	        	fuelR = unpackR(fuelColor);
        	        	fuelG = unpackG(fuelColor);
        	        	fuelB = unpackB(fuelColor);
        	        	wasteR = unpackR(wasteColor);
        	        	wasteG = unpackG(wasteColor);
        	        	wasteB = unpackB(wasteColor);

        	        	red = lerp(wasteR, fuelR, proportion);
        	        	green = lerp(wasteG, fuelG, proportion);
        	        	blue = lerp(wasteB, fuelB, proportion);
        	    	}

    	    		float pctFilled = Math.min(1f, Math.max(0f, (float)totalFluid / (float)capacity));
    	    		fluidColumnOffsetFromCenter = lerp(FLUID_RENDER_OFFSET_MIN, FLUID_RENDER_OFFSET_MAX, pctFilled);
        	    	
    	    		if(iconSide != null && iconBottom != null) {
    	    			// We've got fuel data! Let's do this thang.
    	    			
	    	            tessellator.setColorRGBA_F(red, green, blue, 0.75f);
	    	            tessellator.setBrightness(world.getLightBrightnessForSkyBlocks(x, y, z, 15));

    	    			renderer.setOverrideBlockTexture(iconBottom);
	    	            float xzMin = fluidColumnOffsetFromCenter;
	    	            float xzMax = 1f - fluidColumnOffsetFromCenter;
	    				renderer.setRenderBounds(xzMin, 0.01f, xzMin, xzMax, 0.99f, xzMax);
	    	            
    	    			if(renderer.renderAllFaces || renderBottom) {
    	    				rendered = true;
    	    				renderer.renderFaceYNeg(block, x, y, z, iconBottom);
    	    			}
    	    			
    	    			if(renderer.renderAllFaces || renderTop) {
    	    				rendered = true;
    	    				renderer.renderFaceYPos(block, x, y, z, iconBottom);
    	    			}
    	    			
    	    			renderer.setOverrideBlockTexture(iconSide);
	    				renderer.setRenderBounds(xzMin, 0f, xzMin, xzMax, 1f, xzMax);
	    				
	    				if(renderer.renderAllFaces || renderSides[0]) {
    	    				rendered = true;
	    		            renderer.renderFaceZNeg(block, x, y, z, iconSide);
	    				}
	    				if(renderer.renderAllFaces || renderSides[1]) {
    	    				rendered = true;
	    		            renderer.renderFaceZPos(block, x, y, z, iconSide);
	    				}
	    				if(renderer.renderAllFaces || renderSides[2]) {
    	    				rendered = true;
	    		            renderer.renderFaceXNeg(block, x, y, z, iconSide);
	    				}
	    				if(renderer.renderAllFaces || renderSides[3]) {
    	    				rendered = true;
	    		            renderer.renderFaceXPos(block, x, y, z, iconSide);
	    				}
    	    		}
        		}
        	}
        }
        
        // Then render external housing
        tessellator.setColorRGBA(255, 255, 255, 255);
        renderer.setRenderBoundsFromBlock(block);
        renderer.setOverrideBlockTexture(null);

        // First, render the regular block
        if(!renderedFuelOnBottom && (renderer.renderAllFaces || renderBottom)) {
        	rendered = true;
            tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z));
            renderer.renderFaceYNeg(block, x, y, z, block.getIcon(0, blockMetadata));
        }
        if(renderer.renderAllFaces || renderTop) {
        	rendered = true;
            tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z));
            renderer.renderFaceYPos(block, x, y, z, block.getIcon(1, blockMetadata));
        }
        if(renderer.renderAllFaces || renderSides[0]) {
        	rendered = true;
            tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z));
            renderer.renderFaceZNeg(block, x, y, z, block.getIcon(2, blockMetadata));
        }
        if(renderer.renderAllFaces || renderSides[1]) {
        	rendered = true;
            tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z));
            renderer.renderFaceZPos(block, x, y, z, block.getIcon(3, blockMetadata));
        }
        if(renderer.renderAllFaces || renderSides[2]) {
        	rendered = true;
            tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z));
            renderer.renderFaceXNeg(block, x, y, z, block.getIcon(4, blockMetadata));
        }
        if(renderer.renderAllFaces || renderSides[3]) {
        	rendered = true;
            tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z));
            renderer.renderFaceXPos(block, x, y, z, block.getIcon(5, blockMetadata));
        }
        
		return rendered;
	}

	@Override
	public boolean shouldRender3DInInventory(int modelID) {
		return true;
	}

	@Override
	public int getRenderId() {
		return BlockFuelRod.renderId;
	}

	/// HELPERS ///
	protected static float unpackR(int rgb) {
		return (float)(rgb >> 16 & 255) / 255.0F;
	}
	
	protected static float unpackG(int rgb) {
		return (float)(rgb >> 8 & 255) / 255.0F;
	}
	
	protected static float unpackB(int rgb) {
		return (float)(rgb & 255) / 255.0F;
	}	
	protected static float lerp(float min, float max, float value) {
		return min + (max-min)*value;
	}
}
