package com.hbm.render.tileentity;

import org.lwjgl.opengl.GL11;

import com.hbm.tileentity.network.TileEntityPylonBase;
import com.hbm.tileentity.network.TileEntityPylonBase.ConnectionType;

import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.MathHelper;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;

public abstract class RenderPylonBase extends TileEntitySpecialRenderer {
	
	//TODO: adapt this into a more generic form for multi wire pylons
	@Deprecated
	public void renderSingleLine(TileEntityPylonBase pyl, double x, double y, double z) {
		
		for(int i = 0; i < pyl.connected.size(); i++) {

			int[] wire = pyl.connected.get(i);
			TileEntity tile = pyl.getWorldObj().getTileEntity(wire[0], wire[1], wire[2]);
			
			if(tile instanceof TileEntityPylonBase) {
				TileEntityPylonBase pylon = (TileEntityPylonBase) tile;
				Vec3 myOffset = pyl.getMountPos()[0];
				Vec3 theirOffset = pylon.getMountPos()[0];

				double conX0 = pyl.xCoord + myOffset.xCoord;
				double conY0 = pyl.yCoord + myOffset.yCoord;
				double conZ0 = pyl.zCoord + myOffset.zCoord;
				double conX1 = pylon.xCoord + theirOffset.xCoord;
				double conY1 = pylon.yCoord + theirOffset.yCoord;
				double conZ1 = pylon.zCoord + theirOffset.zCoord;
				
				double wX = (conX1 - conX0) / 2D;
				double wY = (conY1 - conY0) / 2D;
				double wZ = (conZ1 - conZ0) / 2D;
				
				float count = 10;
				Vec3 delta = Vec3.createVectorHelper(conX1 - conX0, conY1 - conY0, conZ1 - conZ0);
				double hang = delta.lengthVector() / 15D;
				
				for(float j = 0; j < count; j++) {
					
					float k = j + 1;
					
					double ja = j + 0.5D;
					double ix = conX0 + delta.xCoord / (double)(count * 2) * ja;
					double iy = conY0 + delta.yCoord / (double)(count * 2) * ja - Math.sin(j / count * Math.PI * 0.5) * hang;
					double iz = conZ0 + delta.zCoord / (double)(count * 2) * ja;
					
					//pylon.getWorldObj().spawnParticle("reddust", ix, iy, iz, 0.01 + j * 0.1, 0, 0);
					
					int brightness = pyl.getWorldObj().getLightBrightnessForSkyBlocks(MathHelper.floor_double(ix), MathHelper.floor_double(iy), MathHelper.floor_double(iz), 0);
					int lX = brightness % 65536;
					int lY = brightness / 65536;
					OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)lX / 1.0F, (float)lY / 1.0F);
					
					drawLineSegment(
							x + myOffset.xCoord + (wX * j / count),
							y + myOffset.yCoord + (wY * j / count) - Math.sin(j / count * Math.PI * 0.5) * hang,
							z + myOffset.zCoord + (wZ * j / count),
							x + myOffset.xCoord + (wX * k / count),
							y + myOffset.yCoord + (wY * k / count) - Math.sin(k / count * Math.PI * 0.5) * hang,
							z + myOffset.zCoord + (wZ * k / count));
				}
			}
		}
	}
	
	/**
	 * The closest we have to a does-all solution. It will figure out if it needs to draw multiple lines,
	 * iterate through all the mounting points, try to find the matching mounting points and then draw the lines.
	 * @param pyl
	 * @param x
	 * @param y
	 * @param z
	 */
	public void renderLinesGeneric(TileEntityPylonBase pyl, double x, double y, double z) {
		
		for(int i = 0; i < pyl.connected.size(); i++) {

			int[] wire = pyl.connected.get(i);
			TileEntity tile = pyl.getWorldObj().getTileEntity(wire[0], wire[1], wire[2]);
			
			if(tile instanceof TileEntityPylonBase) {
				TileEntityPylonBase pylon = (TileEntityPylonBase) tile;
				
				Vec3[] m1 = pyl.getMountPos();
				Vec3[] m2 = pylon.getMountPos();
				
				int lineCount = Math.max(pyl.getConnectionType() == ConnectionType.QUAD ? 4 : 1, pylon.getConnectionType() == ConnectionType.QUAD ? 4 : 1);
				
				for(int line = 0; line < lineCount; line++) {

					Vec3 first = m1[line % m1.length];
					int secondIndex = line % m2.length;
					
					/*
					 * hacky hacky hack
					 * this will shift the mount point order by 2 to prevent wires from crossing
					 * when meta 12 and 15 pylons are connected. this isn't a great solution
					 * and there's still ways to cross the wires in an ugly way but for now
					 * it should be enough.
					 */
					if(lineCount == 4 && (
							(pyl.getBlockMetadata() - 10 == 5 && pylon.getBlockMetadata() - 10 == 2) ||
							(pyl.getBlockMetadata() - 10 == 2 && pylon.getBlockMetadata() - 10 == 5))) {
						
						secondIndex += 2;
						secondIndex %= m2.length;
					}
					
					Vec3 second = m2[secondIndex];
					
					double sX = second.xCoord + pylon.xCoord - pyl.xCoord;
					double sY = second.yCoord + pylon.yCoord - pyl.yCoord;
					double sZ = second.zCoord + pylon.zCoord - pyl.zCoord;
					
					renderLine(pyl.getWorldObj(), pyl, x, y, z,
							first.xCoord,
							first.yCoord,
							first.zCoord,
							first.xCoord + (sX - first.xCoord) * 0.5,
							first.yCoord + (sY - first.yCoord) * 0.5,
							first.zCoord + (sZ - first.zCoord) * 0.5);
				}
			}
		}
	}
	
	/**
	 * Renders half a line
	 * First coords: the relative render position
	 * Second coords: the pylon's mounting point
	 * Third coords: the midway point exactly between the mounting points. The "hang" doesn't need to be accounted for, it's calculated in here.
	 * @param world
	 * @param pyl
	 * @param x
	 * @param y
	 * @param z
	 * @param x0
	 * @param y0
	 * @param z0
	 * @param x1
	 * @param y1
	 * @param z1
	 */
	public void renderLine(World world, TileEntityPylonBase pyl, double x, double y, double z, double x0, double y0, double z0, double x1, double y1, double z1) {

		GL11.glPushMatrix();
		GL11.glTranslated(x, y, z);
		float count = 10;
		
		for(float j = 0; j < count; j++) {
			
			float k = j + 1;
			
			double deltaX = x1 - x0;
			double deltaY = y1 - y0;
			double deltaZ = z1 - z0;
			
			double ja = j + 0.5D;
			double ix = pyl.xCoord + x0 + deltaX / (double)(count * 2) * ja;
			double iy = pyl.yCoord + y0 + deltaY / (double)(count * 2) * ja - Math.sin(j / count * Math.PI * 0.5);
			double iz = pyl.zCoord + z0 + deltaZ / (double)(count * 2) * ja;
			
			int brightness = world.getLightBrightnessForSkyBlocks(MathHelper.floor_double(ix), MathHelper.floor_double(iy), MathHelper.floor_double(iz), 0);
			int lX = brightness % 65536;
			int lY = brightness / 65536;
			OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)lX / 1.0F, (float)lY / 1.0F);
			
			drawLineSegment(
					x0 + (deltaX * j / count),
					y0 + (deltaY * j / count) - Math.sin(j / count * Math.PI * 0.5),
					z0 + (deltaZ * j / count),
					x0 + (deltaX * k / count),
					y0 + (deltaY * k / count) - Math.sin(k / count * Math.PI * 0.5),
					z0 + (deltaZ * k / count));
		}
		GL11.glPopMatrix();
	}
	
	/**
	 * Draws a single segment from the first to the second 3D coordinate.
	 * Not fantastic but it looks good enough.
	 * Possible enhancement: remove the draw calls and put those around the drawLineSegment calls for better-er performance
	 * @param x
	 * @param y
	 * @param z
	 * @param a
	 * @param b
	 * @param c
	 */
	public void drawLineSegment(double x, double y, double z, double a, double b, double c) {
		
		double girth = 0.03125D;
		
		GL11.glDisable(GL11.GL_TEXTURE_2D);
		GL11.glDisable(GL11.GL_LIGHTING);
		GL11.glDisable(GL11.GL_CULL_FACE);
		Tessellator tessellator = Tessellator.instance;
		tessellator.startDrawing(5);
		tessellator.setColorOpaque_I(LINE_COLOR);
		tessellator.addVertex(x, y + girth, z);
		tessellator.addVertex(x, y - girth, z);
		tessellator.addVertex(a, b + girth, c);
		tessellator.addVertex(a, b - girth, c);
		tessellator.addVertex(x + girth, y, z);
		tessellator.addVertex(x - girth, y, z);
		tessellator.addVertex(a + girth, b, c);
		tessellator.addVertex(a - girth, b, c);
		tessellator.addVertex(x, y, z + girth);
		tessellator.addVertex(x, y, z - girth);
		tessellator.addVertex(a, b, c + girth);
		tessellator.addVertex(a, b, c - girth);
		tessellator.draw();
		GL11.glEnable(GL11.GL_LIGHTING);
		GL11.glEnable(GL11.GL_TEXTURE_2D);
		GL11.glEnable(GL11.GL_CULL_FACE);
	}
	
	public static final int LINE_COLOR = 0xBB3311;
}
