package client.renderer.model;

import client.renderer.RenderBuffer;
import common.util.Facing;
import common.util.Vec3;

public class ModelBox {
	private static Vec3[] getPoints(float x1, float y1, float z1, float x2, float y2, float z2, int dir) {
		switch(dir) {
			case 0: // X2 east
				return new Vec3[] {new Vec3(x2, y1, z2), new Vec3(x2, y1, z1), new Vec3(x2, y2, z1), new Vec3(x2, y2, z2)};
			case 1: // X1 west
				return new Vec3[] {new Vec3(x1, y1, z1), new Vec3(x1, y1, z2), new Vec3(x1, y2, z2), new Vec3(x1, y2, z1)};
			case 2: // Y1 down
				return new Vec3[] {new Vec3(x2, y1, z2), new Vec3(x1, y1, z2), new Vec3(x1, y1, z1), new Vec3(x2, y1, z1)};
			case 3: // Y2 up
				return new Vec3[] {new Vec3(x2, y2, z1), new Vec3(x1, y2, z1), new Vec3(x1, y2, z2), new Vec3(x2, y2, z2)};
			case 4: // Z1 north
				return new Vec3[] {new Vec3(x2, y1, z1), new Vec3(x1, y1, z1), new Vec3(x1, y2, z1), new Vec3(x2, y2, z1)};
			case 5: // Z2 south
				return new Vec3[] {new Vec3(x1, y1, z2), new Vec3(x2, y1, z2), new Vec3(x2, y2, z2), new Vec3(x1, y2, z2)};
			default:
				return null;
		}
	}
	
	private static int[] getUvs(int xs, int ys, int zs, int tx, int ty, int dir) {
		switch(dir) {
			case 0:
				return new int[] {tx + zs + xs, ty + zs, tx + zs + xs + zs, ty + zs + ys};
			case 1:
				return new int[] {tx, ty + zs, tx + zs, ty + zs + ys};
			case 2:
				return new int[] {tx + zs, ty, tx + zs + xs, ty + zs};
			case 3:
				return new int[] {tx + zs + xs, ty + zs, tx + zs + xs + xs, ty};
			case 4:
				return new int[] {tx + zs, ty + zs, tx + zs + xs, ty + zs + ys};
			case 5:
				return new int[] {tx + zs + xs + zs, ty + zs, tx + zs + xs + zs + xs, ty + zs + ys};
			default:
				return null;
		}
	}
	
	private static int[] getShiftedUvs(int xs, int ys, int zs, int xt, int yt, int zt, int tx, int ty, int dir) {
		boolean flip = xt < 0;
		xt = xt < 0 ? -xt : xt;
		if(ys != yt || zs != zt || xt < xs)
			throw new IllegalArgumentException("ys != yt || zs != zt || xt < xs");
		int sh = xt - xs;
		if(flip) {
			switch(dir) {
				case 0: // #5
					return new int[] {tx + zs + xs + sh, ty + zs, tx + zs + xs + zs + sh, ty + zs + ys};
				case 1: // #3
					return new int[] {tx, ty + zs, tx + zs, ty + zs + ys};
				case 2: // #1
					return new int[] {tx + zs, ty, tx + zs + xs, ty + zs};
				case 3: // #2
					return new int[] {tx + zs + xs + sh, ty + zs, tx + zs + xs + xs + sh, ty};
				case 4: // #4
					return new int[] {tx + zs, ty + zs, tx + zs + xs, ty + zs + ys};
				case 5: // #6
					return new int[] {tx + zs + xs + zs + sh + sh, ty + zs, tx + zs + xs + zs + xs + sh + sh, ty + zs + ys};
				default:
					return null;
			}
		}
		else {
			switch(dir) {
				case 0: // #5
					return new int[] {tx + zs + xs + sh, ty + zs, tx + zs + xs + zs + sh, ty + zs + ys};
				case 1: // #3
					return new int[] {tx, ty + zs, tx + zs, ty + zs + ys};
				case 2: // #1
					return new int[] {tx + zs + sh, ty, tx + zs + xs + sh, ty + zs};
				case 3: // #2
					return new int[] {tx + zs + xs + sh + sh, ty + zs, tx + zs + xs + xs + sh + sh, ty};
				case 4: // #4
					return new int[] {tx + zs + sh, ty + zs, tx + zs + xs + sh, ty + zs + ys};
				case 5: // #6
					return new int[] {tx + zs + xs + zs + sh, ty + zs, tx + zs + xs + zs + xs + sh, ty + zs + ys};
				default:
					return null;
			}
		}
	}
	
	private TexturedQuad[] quads;
	public final float posX1;
	public final float posY1;
	public final float posZ1;
	public final float posX2;
	public final float posY2;
	public final float posZ2;
//	public String boxName;

	public ModelBox(int tw, int th, float u1, float v1, float u2, float v2, float x1, float y1, float z1, float x2, float y2, float z2, Facing dir) {
		this.posX1 = x1;
		this.posY1 = y1;
		this.posZ1 = z1;
		this.posX2 = x2;
		this.posY2 = y2;
		this.posZ2 = z2;
		this.quads = new TexturedQuad[1];
		this.quads[0] = new TexturedQuad(getPoints(x1, y1, z1, x2, y2, z2, dir.getQIndex()), u1, v1, u2, v2, tw, th);
	}

	public ModelBox(ModelRenderer renderer, int tx, int ty, float x, float y, float z, int xs, int ys, int zs, float add) {
		this(renderer, tx, ty, x, y, z, xs, ys, zs, add, renderer.mirror);
	}

	public ModelBox(ModelRenderer renderer, int tx, int ty, float x1, float y1, float z1, int xs, int ys, int zs, float add, boolean mirror) {
		this.posX1 = x1;
		this.posY1 = y1;
		this.posZ1 = z1;
		this.posX2 = x1 + (float)xs;
		this.posY2 = y1 + (float)ys;
		this.posZ2 = z1 + (float)zs;
//		this.vertices = new Vec3[8];
		this.quads = new TexturedQuad[Facing.values().length];
		float x2 = x1 + (float)xs;
		float y2 = y1 + (float)ys;
		float z2 = z1 + (float)zs;
		x1 = x1 - add;
		y1 = y1 - add;
		z1 = z1 - add;
		x2 = x2 + add;
		y2 = y2 + add;
		z2 = z2 + add;
		if(mirror) {
			float x = x2;
			x2 = x1;
			x1 = x;
		}
//		Vec3 v = new Vec3(x1, y1, z1);
//		Vec3 vx = new Vec3(x2, y1, z1);
//		Vec3 vxy = new Vec3(x2, y2, z1);
//		Vec3 vy = new Vec3(x1, y2, z1);
//		Vec3 vz = new Vec3(x1, y1, z2);
//		Vec3 vxz = new Vec3(x2, y1, z2);
//		Vec3 w = new Vec3(x2, y2, z2);
//		Vec3 vyz = new Vec3(x1, y2, z2);
//		this.vertices[0] = v;
//		this.vertices[1] = vx;
//		this.vertices[2] = vxy;
//		this.vertices[3] = vy;
//		this.vertices[4] = vz;
//		this.vertices[5] = vxz;
//		this.vertices[6] = w;
//		this.vertices[7] = vyz;
//		this.quads[0] = new TexturedQuad(vxz, vx, vxy, w, tx + zs + xs, ty + zs, tx + zs + xs + zs, ty + zs + ys,
//				renderer.textureWidth, renderer.textureHeight);
//		this.quads[1] = new TexturedQuad(v, vz, vyz, vy, tx, ty + zs, tx + zs, ty + zs + ys, 
//				renderer.textureWidth, renderer.textureHeight);
//		this.quads[2] = new TexturedQuad(vxz, vz, v, vx, tx + zs, ty, tx + zs + xs, ty + zs, 
//				renderer.textureWidth, renderer.textureHeight);
//		this.quads[3] = new TexturedQuad(vxy, vy, vyz, w, tx + zs + xs, ty + zs, tx + zs + xs + xs, ty,
//				renderer.textureWidth, renderer.textureHeight);
//		this.quads[4] = new TexturedQuad(vx, v, vy, vxy, tx + zs, ty + zs, tx + zs + xs, ty + zs + ys,
//				renderer.textureWidth, renderer.textureHeight);
//		this.quads[5] = new TexturedQuad(vz, vxz, w, vyz, tx + zs + xs + zs, ty + zs, tx + zs + xs + zs + xs, ty + zs + ys, 
//				renderer.textureWidth, renderer.textureHeight);
		for(int n = 0; n < this.quads.length; n++) {
			this.quads[n] = new TexturedQuad(getPoints(x1, y1, z1, x2, y2, z2, n), getUvs(xs, ys, zs, tx, ty, n), renderer.textureWidth, renderer.textureHeight);
		}
		if(mirror) {
			for(int i = 0; i < this.quads.length; ++i) {
				this.quads[i].flipFace();
			}
		}
	}

	public ModelBox(ModelRenderer renderer, int tx, int ty, float x, float y, float z, int xs, int ys, int zs, int rx, int ry, int rz, float add) {
		this(renderer, tx, ty, x, y, z, xs, ys, zs, rx, ry, rz, add, renderer.mirror);
	}

	public ModelBox(ModelRenderer renderer, int tx, int ty, float x1, float y1, float z1, int xs, int ys, int zs, int xt, int yt, int zt, float add, boolean mirror) {
		this.posX1 = x1;
		this.posY1 = y1;
		this.posZ1 = z1;
		this.posX2 = x1 + (float)xs;
		this.posY2 = y1 + (float)ys;
		this.posZ2 = z1 + (float)zs;
		this.quads = new TexturedQuad[Facing.values().length];
		float x2 = x1 + (float)xs;
		float y2 = y1 + (float)ys;
		float z2 = z1 + (float)zs;
		x1 = x1 - add;
		y1 = y1 - add;
		z1 = z1 - add;
		x2 = x2 + add;
		y2 = y2 + add;
		z2 = z2 + add;
		if(mirror) {
			float x = x2;
			x2 = x1;
			x1 = x;
		}
		for(int n = 0; n < this.quads.length; n++) {
			this.quads[n] = new TexturedQuad(getPoints(x1, y1, z1, x2, y2, z2, n), getShiftedUvs(xs, ys, zs, xt, yt, zt, tx, ty, n), 
					renderer.textureWidth, renderer.textureHeight);
		}
		if(mirror) {
			for(int i = 0; i < this.quads.length; ++i) {
				this.quads[i].flipFace();
			}
		}
	}

	public ModelBox(ModelRenderer renderer, int tx, int ty, float x, float y, float z, int xs, int ys) {
		this(renderer, tx, ty, x, y, z, xs, ys, renderer.mirror);
	}

	public ModelBox(ModelRenderer renderer, int tx, int ty, float x1, float y1, float z, int xs, int ys, boolean mirror) {
		this.posX1 = x1;
		this.posY1 = y1;
		this.posZ1 = z;
		this.posX2 = x1 + (float)xs;
		this.posY2 = y1 + (float)ys;
		this.posZ2 = z;
		this.quads = new TexturedQuad[1];
		float x2 = x1 + (float)xs;
		float y2 = y1 + (float)ys;
		if(mirror) {
			float x = x2;
			x2 = x1;
			x1 = x;
		}
		this.quads[0] = new TexturedQuad(getPoints(x1, y1, z, x2, y2, z, Facing.SOUTH.getQIndex()),
				new int[] {tx, ty, tx + xs, ty + ys}, renderer.textureWidth, renderer.textureHeight);
		if(mirror) {
			this.quads[0].flipFace();
		}
	}

	public void makeList(RenderBuffer renderer, float scale) {
		for(int i = 0; i < this.quads.length; ++i) {
			this.quads[i].addTo(renderer, scale);
		}
	}

//	public ModelBox setBoxName(String name) {
//		this.boxName = name;
//		return this;
//	}
}
