package client.renderer.entity;

import org.lwjgl.opengl.GL11;

import client.Client;
import client.renderer.DefaultVertexFormats;
import client.renderer.Drawing;
import client.renderer.Frustum;
import client.renderer.GlState;
import client.renderer.RenderBuffer;
import client.renderer.Tessellator;
import client.renderer.texture.TextureAtlasSprite;
import client.renderer.texture.TextureMap;
import common.block.Block;
import common.entity.Entity;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.world.World;

public abstract class Render<T extends Entity>
{
//	public static boolean drawNames = true;
//    private static final String shadowTextures = "textures/world/shadow.png";
    
    protected final RenderManager renderManager;
//    protected float shadowSize;
//
//    /**
//     * Determines the darkness of the object's shadow. Higher value makes a darker shadow.
//     */
//    protected float shadowOpaque = 1.0F;

    protected Render(RenderManager renderManager)
    {
        this.renderManager = renderManager;
    }

    public boolean shouldRender(T livingEntity, double camX, double camY, double camZ)
    {
        BoundingBox axisalignedbb = livingEntity.getEntityBoundingBox();

        if (axisalignedbb.hasNaN() || axisalignedbb.getAverageEdgeLength() == 0.0D)
        {
            axisalignedbb = new BoundingBox(livingEntity.posX - 2.0D, livingEntity.posY - 2.0D, livingEntity.posZ - 2.0D, livingEntity.posX + 2.0D, livingEntity.posY + 2.0D, livingEntity.posZ + 2.0D);
        }

        return livingEntity.isInRangeToRender3d(camX, camY, camZ) && (livingEntity.noFrustumCheck || Frustum.isInFrustum(axisalignedbb));
    }

    /**
     * Renders the desired {@code T} type Entity.
     */
    public void doRender(T entity, double x, double y, double z, float partialTicks)
    {
        this.renderName(entity, x, y, z);
    }

    protected void renderName(T entity, double x, double y, double z)
    {
    	String name = entity.getDisplayName();
    	if(name != null && !name.isEmpty())
    		this.renderLivingLabel(entity, name, x, y, z, 64);
    }

//    protected boolean canRenderName(T entity)
//    {
//        return entity.hasCustomName();
//    }

    /**
     * Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture.
     */
    protected abstract String getEntityTexture(T entity);

    public boolean bindEntityTexture(T entity)
    {
    	String resourcelocation = this.getEntityTexture(entity);

        if (resourcelocation == null)
        {
            return false;
        }
        else
        {
            this.bindTexture(resourcelocation);
            return true;
        }
    }

    public void bindTexture(String location)
    {
        this.renderManager.renderEngine.bindTexture(location);
    }

    /**
     * Renders fire on top of the entity. Args: entity, x, y, z, partialTickTime
     */
    private void renderEntityOnFire(Entity entity, double x, double y, double z, float partialTicks)
    {
        GlState.disableLighting();
        TextureMap texturemap = Client.CLIENT.getTextureMapBlocks();
        TextureAtlasSprite textureatlassprite = texturemap.getAtlasSprite("blocks/fire_layer_0");
        TextureAtlasSprite textureatlassprite1 = texturemap.getAtlasSprite("blocks/fire_layer_1");
        GL11.glPushMatrix();
        GL11.glTranslatef((float)x, (float)y, (float)z);
        float f = entity.width * 1.4F;
        GL11.glScalef(f, f, f);
//        Tessellator tessellator = Tessellator.getInstance();
        RenderBuffer worldrenderer = Tessellator.getBuffer();
        float f1 = 0.5F;
        float f2 = 0.0F;
        float f3 = entity.height / f;
        float f4 = (float)(entity.posY - entity.getEntityBoundingBox().minY);
        GL11.glRotatef(-this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
        GL11.glTranslatef(0.0F, 0.0F, -0.3F + (float)((int)f3) * 0.02F);
        GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
        float f5 = 0.0F;
        int i = 0;
        worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);

        while (f3 > 0.0F)
        {
            TextureAtlasSprite textureatlassprite2 = i % 2 == 0 ? textureatlassprite : textureatlassprite1;
            this.bindTexture(TextureMap.locationBlocksTexture);
            float f6 = textureatlassprite2.getMinU();
            float f7 = textureatlassprite2.getMinV();
            float f8 = textureatlassprite2.getMaxU();
            float f9 = textureatlassprite2.getMaxV();

            if (i / 2 % 2 == 0)
            {
                float f10 = f8;
                f8 = f6;
                f6 = f10;
            }

            worldrenderer.pos((double)(f1 - f2), (double)(0.0F - f4), (double)f5).tex((double)f8, (double)f9).endVertex();
            worldrenderer.pos((double)(-f1 - f2), (double)(0.0F - f4), (double)f5).tex((double)f6, (double)f9).endVertex();
            worldrenderer.pos((double)(-f1 - f2), (double)(1.4F - f4), (double)f5).tex((double)f6, (double)f7).endVertex();
            worldrenderer.pos((double)(f1 - f2), (double)(1.4F - f4), (double)f5).tex((double)f8, (double)f7).endVertex();
            f3 -= 0.45F;
            f4 -= 0.45F;
            f1 *= 0.9F;
            f5 += 0.03F;
            ++i;
        }

        Tessellator.draw();
        GL11.glPopMatrix();
        GlState.enableLighting();
    }

//    /**
//     * Renders the entity shadows at the position, shadow alpha and partialTickTime. Args: entity, x, y, z, shadowAlpha,
//     * partialTickTime
//     */
//    private void renderShadow(Entity entityIn, double x, double y, double z, float shadowAlpha, float partialTicks)
//    {
//        GlState.enableBlend();
//        GlState.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
//        this.renderManager.renderEngine.bindTexture(shadowTextures);
//        World world = this.getWorldFromRenderManager();
//        GlState.depthMask(false);
//        float f = this.shadowSize;
//
//        if (entityIn instanceof EntityLiving)
//        {
//            EntityLiving entityliving = (EntityLiving)entityIn;
//            f *= entityliving.getShadowSize();
//
//            if (entityliving.isChild())
//            {
//                f *= 0.5F;
//            }
//        }
//
//        double d5 = entityIn.lastTickPosX + (entityIn.posX - entityIn.lastTickPosX) * (double)partialTicks;
//        double d0 = entityIn.lastTickPosY + (entityIn.posY - entityIn.lastTickPosY) * (double)partialTicks;
//        double d1 = entityIn.lastTickPosZ + (entityIn.posZ - entityIn.lastTickPosZ) * (double)partialTicks;
//        int i = MathHelper.floor_double(d5 - (double)f);
//        int j = MathHelper.floor_double(d5 + (double)f);
//        int k = MathHelper.floor_double(d0 - (double)f);
//        int l = MathHelper.floor_double(d0);
//        int i1 = MathHelper.floor_double(d1 - (double)f);
//        int j1 = MathHelper.floor_double(d1 + (double)f);
//        double d2 = x - d5;
//        double d3 = y - d0;
//        double d4 = z - d1;
////        Tessellator tessellator = Tessellator.getInstance();
//        RenderBuffer worldrenderer = Tessellator.getBuffer();
//        worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
//
//        for (BlockPos blockpos : BlockPos.getAllInBoxMutable(new BlockPos(i, k, i1), new BlockPos(j, l, j1)))
//        {
//            Block block = world.getBlockState(blockpos.down()).getBlock();
//
//            if (block.getRenderType() != -1 && world.getLightFromNeighbors(blockpos) > 3)
//            {
//                this.renderShadowBlock(block, x, y, z, blockpos, shadowAlpha, f, d2, d3, d4);
//            }
//        }
//
//        Tessellator.draw();
//        GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
//        GlState.disableBlend();
//        GlState.depthMask(true);
//    }

    /**
     * Returns the render manager's world object
     */
    private World getWorldFromRenderManager()
    {
        return this.renderManager.worldObj;
    }

    private void renderShadowBlock(Block blockIn, double p_180549_2_, double p_180549_4_, double p_180549_6_, BlockPos pos, float p_180549_9_, float p_180549_10_, double p_180549_11_, double p_180549_13_, double p_180549_15_)
    {
        if (blockIn.isFullCube())
        {
//            Tessellator tessellator = Tessellator.getInstance();
            RenderBuffer worldrenderer = Tessellator.getBuffer();
            double d0 = ((double)p_180549_9_ - (p_180549_4_ - ((double)pos.getY() + p_180549_13_)) / 2.0D) * 0.5D * (double)this.getWorldFromRenderManager().getLightBrightness(pos);

            if (d0 >= 0.0D)
            {
                if (d0 > 1.0D)
                {
                    d0 = 1.0D;
                }

                double d1 = (double)pos.getX() + blockIn.getBlockBoundsMinX() + p_180549_11_;
                double d2 = (double)pos.getX() + blockIn.getBlockBoundsMaxX() + p_180549_11_;
                double d3 = (double)pos.getY() + blockIn.getBlockBoundsMinY() + p_180549_13_ + 0.015625D;
                double d4 = (double)pos.getZ() + blockIn.getBlockBoundsMinZ() + p_180549_15_;
                double d5 = (double)pos.getZ() + blockIn.getBlockBoundsMaxZ() + p_180549_15_;
                float f = (float)((p_180549_2_ - d1) / 2.0D / (double)p_180549_10_ + 0.5D);
                float f1 = (float)((p_180549_2_ - d2) / 2.0D / (double)p_180549_10_ + 0.5D);
                float f2 = (float)((p_180549_6_ - d4) / 2.0D / (double)p_180549_10_ + 0.5D);
                float f3 = (float)((p_180549_6_ - d5) / 2.0D / (double)p_180549_10_ + 0.5D);
                worldrenderer.pos(d1, d3, d4).tex((double)f, (double)f2).color(1.0F, 1.0F, 1.0F, (float)d0).endVertex();
                worldrenderer.pos(d1, d3, d5).tex((double)f, (double)f3).color(1.0F, 1.0F, 1.0F, (float)d0).endVertex();
                worldrenderer.pos(d2, d3, d5).tex((double)f1, (double)f3).color(1.0F, 1.0F, 1.0F, (float)d0).endVertex();
                worldrenderer.pos(d2, d3, d4).tex((double)f1, (double)f2).color(1.0F, 1.0F, 1.0F, (float)d0).endVertex();
            }
        }
    }

    /**
     * Renders a white box with the bounds of the AABB translated by the offset. Args: aabb, x, y, z
     */
    public static void renderOffsetAABB(BoundingBox boundingBox, double x, double y, double z)
    {
        GlState.disableTexture2D();
//        Tessellator tessellator = Tessellator.getInstance();
        RenderBuffer worldrenderer = Tessellator.getBuffer();
        GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
        worldrenderer.setTranslation(x, y, z);
        worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_NORMAL);
        worldrenderer.pos(boundingBox.minX, boundingBox.maxY, boundingBox.minZ).normal(0.0F, 0.0F, -1.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.minZ).normal(0.0F, 0.0F, -1.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.minY, boundingBox.minZ).normal(0.0F, 0.0F, -1.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.minY, boundingBox.minZ).normal(0.0F, 0.0F, -1.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.minY, boundingBox.maxZ).normal(0.0F, 0.0F, 1.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.minY, boundingBox.maxZ).normal(0.0F, 0.0F, 1.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ).normal(0.0F, 0.0F, 1.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.maxY, boundingBox.maxZ).normal(0.0F, 0.0F, 1.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.minY, boundingBox.minZ).normal(0.0F, -1.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.minY, boundingBox.minZ).normal(0.0F, -1.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.minY, boundingBox.maxZ).normal(0.0F, -1.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.minY, boundingBox.maxZ).normal(0.0F, -1.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.maxY, boundingBox.maxZ).normal(0.0F, 1.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ).normal(0.0F, 1.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.minZ).normal(0.0F, 1.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.maxY, boundingBox.minZ).normal(0.0F, 1.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.minY, boundingBox.maxZ).normal(-1.0F, 0.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.maxY, boundingBox.maxZ).normal(-1.0F, 0.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.maxY, boundingBox.minZ).normal(-1.0F, 0.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.minX, boundingBox.minY, boundingBox.minZ).normal(-1.0F, 0.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.minY, boundingBox.minZ).normal(1.0F, 0.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.minZ).normal(1.0F, 0.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ).normal(1.0F, 0.0F, 0.0F).endVertex();
        worldrenderer.pos(boundingBox.maxX, boundingBox.minY, boundingBox.maxZ).normal(1.0F, 0.0F, 0.0F).endVertex();
        Tessellator.draw();
        worldrenderer.setTranslation(0.0D, 0.0D, 0.0D);
        GlState.enableTexture2D();
    }
    
    public void doRenderShadowAndFire(Entity entityIn, double x, double y, double z, float partialTicks)
    {
        if (this.renderManager.gm != null)
        {
//            if (this.renderManager.options.entityShadows && this.shadowSize > 0.0F && !entityIn.isInvisible() && this.renderManager.isRenderShadow())
//            {
//                double d0 = this.renderManager.getDistanceToCamera(entityIn.posX, entityIn.posY, entityIn.posZ);
//                float f = (float)((1.0D - d0 / 256.0D) * (double)this.shadowOpaque);
//
//                if (f > 0.0F)
//                {
//                    this.renderShadow(entityIn, x, y, z, f, partialTicks);
//                }
//            }

            if (entityIn.canRenderOnFire()) // && (!(entityIn.isPlayer()) || !((EntityNPC)entityIn).isSpectator()))
            {
                this.renderEntityOnFire(entityIn, x, y, z, partialTicks);
            }
        }
    }
    
    protected void renderLivingLabel(T entityIn, String str, double x, double y, double z, int maxDistance) {
        double d0 = entityIn.getDistanceSqToEntity(this.renderManager.livingPlayer);
        if (d0 <= (double)(maxDistance * maxDistance) && this.renderManager.gm.canRenderHud()) {
//        	WCF.glPushMatrix();
//        	WCF.glTranslatef((float)x, (float)y + entityIn.height + 0.5f, (float)z);
//        	float f = 1.0f / 64.0f;
//        	WCF.glScalef(f, f, f);
//        	int w, h;
//    		Vec2i size = Drawing.txt_size(0, 0, 0, 0, 65536, 65536, Font.DEFAULT, str);
//    		int tx = - size.xpos / 2;
//    		int ty = - size.ypos;
//    		Drawing.txt_draw(tx, ty, tx, ty, tx + 440, ty + 260, 0xffffffff, 0x3f000000, Font.DEFAULT, str);
////            this.renderManager.addOverlay(x, y + (double)entityIn.height + 0.5, z, str);
//    		WCF.glPopMatrix();

//          FontRenderer fontrenderer = this.getFontRendererFromRenderManager();
          float f = 1.0f; // 1.6F;
          float f1 = 0.016666668F * f;
          GL11.glPushMatrix();
          GL11.glTranslatef((float)x + 0.0F, (float)y + entityIn.height + 0.5F, (float)z);
          GL11.glNormal3f(0.0F, 1.0F, 0.0F);
          GL11.glRotatef(-this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
          GL11.glRotatef(this.renderManager.playerViewX, 1.0F, 0.0F, 0.0F);
          GL11.glScalef(-f1, -f1, f1);
          GlState.disableLighting();
          GlState.depthMask(false);
//          GlState.disableDepth();
          GlState.enableBlend();
          GlState.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
//          Tessellator tessellator = Tessellator.getInstance();
          RenderBuffer worldrenderer = Tessellator.getBuffer();
//          int i = 0;

//          if (str.equals("deadmau5"))
//          {
//              i = -10;
//          }

//  		  Vec2i size = Drawing.txt_size(0, 0, 0, 0, 65536, 65536, str);
//          int j = size.xpos / 2;
//          GlState.disableTexture2D();
//          worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
//          worldrenderer.pos((double)(-j - 1), (double)(-1 + i), 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
//          worldrenderer.pos((double)(-j - 1), (double)(8 + i), 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
//          worldrenderer.pos((double)(j + 1), (double)(8 + i), 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
//          worldrenderer.pos((double)(j + 1), (double)(-1 + i), 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
//          Tessellator.draw();
//          GlState.enableTexture2D();
//          int tx = -size.xpos / 2; // j;
//          int ty = 0; // i;
//  		  Drawing.txt_draw(tx, ty, tx, ty, tx + 440, ty + 260, /* 0xffffffff */ 553648127, 0x3f000000, Font.DEFAULT, str);
//          FontRenderer.drawString(str, -FontRenderer.getStringWidth(str) / 2, i, 553648127);
//          GlState.enableDepth();
          GlState.depthMask(true);
  		  Drawing.drawTextboxCentered(str, 0, 0, 0x3f000000);
//          FontRenderer.drawString(str, -FontRenderer.getStringWidth(str) / 2, i, -1);
          GlState.enableLighting();
          GlState.disableBlend();
          GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
          GL11.glPopMatrix();
        }
    }

    public RenderManager getRenderManager()
    {
        return this.renderManager;
    }
}
