package client.renderer;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.lwjgl.opengl.GL11;

import common.block.Block;
import common.block.liquid.BlockLiquid;
import common.entity.Entity;
import common.entity.npc.EntityNPC;
import common.util.BlockPos;
import common.util.ExtMath;
import common.util.Vec3;
import common.world.State;
import common.world.World;

public class ActiveRenderInfo
{
    /** The current GL viewport */
    private static final IntBuffer VIEWPORT = ByteBuffer.allocateDirect(16 << 2).order(ByteOrder.nativeOrder()).asIntBuffer();

    /** The current GL modelview matrix */
    private static final FloatBuffer MODELVIEW = ByteBuffer.allocateDirect(16 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();

    /** The current GL projection matrix */
    private static final FloatBuffer PROJECTION = ByteBuffer.allocateDirect(16 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();

    /** The computed view object coordinates */
    private static final FloatBuffer OBJECTCOORDS = ByteBuffer.allocateDirect(3 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
    private static Vec3 position = new Vec3(0.0D, 0.0D, 0.0D);

    private static final FloatBuffer SCREENCOORDS = ByteBuffer.allocateDirect(3 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();

    /** The X component of the entity's yaw rotation */
    private static float rotationX;

    /** The combined X and Z components of the entity's pitch rotation */
    private static float rotationXZ;

    /** The Z component of the entity's yaw rotation */
    private static float rotationZ;

    /**
     * The Y component (scaled along the Z axis) of the entity's pitch rotation
     */
    private static float rotationYZ;

    /**
     * The Y component (scaled along the X axis) of the entity's pitch rotation
     */
    private static float rotationXY;

    /**
     * Updates the current render info and camera location based on entity look angles and 1st/3rd person view mode
     */
    public static void updateRenderInfo(EntityNPC entityplayerIn, boolean p_74583_1_)
    {
        GL11.glGetFloatv(2982, MODELVIEW);
        GL11.glGetFloatv(2983, PROJECTION);
        GL11.glGetIntegerv(GL11.GL_VIEWPORT, VIEWPORT);
        float f = (float)((VIEWPORT.get(0) + VIEWPORT.get(2)) / 2);
        float f1 = (float)((VIEWPORT.get(1) + VIEWPORT.get(3)) / 2);
        Project.gluUnProject(f, f1, 0.0F, MODELVIEW, PROJECTION, VIEWPORT, OBJECTCOORDS);
        position = new Vec3((double)OBJECTCOORDS.get(0), (double)OBJECTCOORDS.get(1), (double)OBJECTCOORDS.get(2));
        int i = p_74583_1_ ? 1 : 0;
        float f2 = entityplayerIn.rotPitch;
        float f3 = entityplayerIn.rotYaw;
        rotationX = ExtMath.cos(f3 * (float)Math.PI / 180.0F) * (float)(1 - i * 2);
        rotationZ = ExtMath.sin(f3 * (float)Math.PI / 180.0F) * (float)(1 - i * 2);
        rotationYZ = -rotationZ * ExtMath.sin(f2 * (float)Math.PI / 180.0F) * (float)(1 - i * 2);
        rotationXY = rotationX * ExtMath.sin(f2 * (float)Math.PI / 180.0F) * (float)(1 - i * 2);
        rotationXZ = ExtMath.cos(f2 * (float)Math.PI / 180.0F);
    }
    
    public static Vec3 getDisplayCoords(float x, float y, float z) {
        Project.gluProject(x, y, z, MODELVIEW, PROJECTION, VIEWPORT, SCREENCOORDS);
        return new Vec3((double)SCREENCOORDS.get(0), (double)SCREENCOORDS.get(1), (double)SCREENCOORDS.get(2));
    }

    public static Vec3 projectViewFromEntity(Entity p_178806_0_, double p_178806_1_)
    {
        double d0 = p_178806_0_.prevX + (p_178806_0_.posX - p_178806_0_.prevX) * p_178806_1_;
        double d1 = p_178806_0_.prevY + (p_178806_0_.posY - p_178806_0_.prevY) * p_178806_1_;
        double d2 = p_178806_0_.prevZ + (p_178806_0_.posZ - p_178806_0_.prevZ) * p_178806_1_;
        double d3 = d0 + position.xCoord;
        double d4 = d1 + position.yCoord;
        double d5 = d2 + position.zCoord;
        return new Vec3(d3, d4, d5);
    }

    public static Block getBlockAtEntityViewpoint(World worldIn, Entity p_180786_1_, float p_180786_2_)
    {
        Vec3 vec3 = projectViewFromEntity(p_180786_1_, (double)p_180786_2_);
        BlockPos blockpos = new BlockPos(vec3);
        State iblockstate = worldIn.getState(blockpos);
        Block block = iblockstate.getBlock();

        if (block.getMaterial().isLiquid())
        {
            float f = 0.0F;

            if (iblockstate.getBlock() instanceof BlockLiquid)
            {
                f = BlockLiquid.getLiquidHeightPercent(((Integer)iblockstate.getValue(BlockLiquid.LEVEL)).intValue()) - 0.11111111F;
            }

            float f1 = (float)(blockpos.getY() + 1) - f;

            if (vec3.yCoord >= (double)f1)
            {
                block = worldIn.getState(blockpos.up()).getBlock();
            }
        }

        return block;
    }

    public static Vec3 getPosition()
    {
        return position;
    }

    public static float getRotationX()
    {
        return rotationX;
    }

    public static float getRotationXZ()
    {
        return rotationXZ;
    }

    public static float getRotationZ()
    {
        return rotationZ;
    }

    public static float getRotationYZ()
    {
        return rotationYZ;
    }

    public static float getRotationXY()
    {
        return rotationXY;
    }
}
