package org.cocos2d.include;

import static javax.microedition.khronos.opengles.GL10.GL_ZERO;
import static javax.microedition.khronos.opengles.GL10.GL_ONE;

import org.cocos2d.cocoa.CCGeometry.CCPoint;
import org.cocos2d.cocoa.CCGeometry.CCSize;

public class ccTypes {
	
	/**
	 * RGB color composed of bytes 3 bytes
	 * 
	 * @since v0.8
	 */
	public static class ccColor3B {
		public static final int size = 3;

		//ccColor3B predefined colors
		//! White color (255,255,255)
		public static final ccColor3B ccWHITE	= ccc3(255, 255, 255);
		// ! Yellow color (255,255,0)
		public static final ccColor3B ccYELLOW	= ccc3(255, 255,   0);
		// ! Blue color (0,0,255)
		public static final ccColor3B ccBLUE	= ccc3(  0,   0, 255);
		// ! Green Color (0,255,0)
		public static final ccColor3B ccGREEN	= ccc3(  0, 255,   0);
		// ! Red Color (255,0,0,)
		public static final ccColor3B ccRED		= ccc3(255,   0,   0);
		// ! Magenta Color (255,0,255)
		public static final ccColor3B ccMAGENTA	= ccc3(255,   0, 255);
		// ! Black Color (0,0,0)
		public static final ccColor3B ccBLACK	= ccc3(  0,   0,   0);
		// ! Orange Color (255,127,0)
		public static final ccColor3B ccORANGE	= ccc3(255, 127,   0);
		//! Gray Color (166,166,166)
		public static final ccColor3B ccGRAY	= ccc3(166, 166, 166);

		public int r;
		public int g;
		public int b;

		public ccColor3B() {
			this.set(0, 0, 0);
		}

		public ccColor3B(int r, int g, int b) {
			this.set(r, g, b);
		}

		public ccColor3B(final ccColor3B c) {
			this.set(c);
		}

		public void set(final ccColor3B c) {
			this.set(c.r, c.g, c.b);
		}

		public void set(int r, int g, int b) {
			this.r = r;
			this.g = g;
			this.b = b;
		}

		//! helper macro that creates an ccColor3B type
		public static ccColor3B ccc3(int r, int g, int b) {
			return new ccColor3B(r, g, b);
		}

		public byte[] toByteArray() {
			return new byte[]{(byte) r, (byte) g, (byte) b};
		}

		public String toString() {
			return "< r=" + r + ", g=" + g + ", b=" + b + " >";
		}
	}

	/**
	 * RGBA color composed of 4 bytes
	 * 
	 * @since v0.8
	 */
	public static class ccColor4B {
		public static final int size = 4;

		public int r;
		public int g;
		public int b;
		public int a;

		public ccColor4B() {
			this.set(0, 0, 0, 0);
		}

		public ccColor4B(int r, int g, int b, int a) {
			this.set(r, g, b, a);
		}

		public ccColor4B(final ccColor4B c) {
			this.set(c);
		}

		public void set(int r, int g, int b, int a) {
			this.r = r;
			this.g = g;
			this.b = b;
			this.a = a;
		}

		public void set(final ccColor4B c) {
			this.set(c.r, c.g, c.b, c.a);
		}

		//! helper macro that creates an ccColor4B type
		public static ccColor4B ccc4(int r, int g, int b, int a) {
			return new ccColor4B(r, g, b, a);
		}

		public byte[] toByteArray() {
			return new byte[]{(byte) r, (byte) g, (byte) b, (byte) a};
		}

		public float[] toFloatArray() {
			return new float[] {r/255f, g/255f, b/255f, a/255f};
		}

		public static ccColor4B ccc4BFromccc4F(ccColor4F c) {
			return new ccColor4B((byte)(c.r*255), (byte)(c.g*255), (byte)(c.b*255), (byte)(c.a*255));
		}

		public String toString() {
			return "< r=" + r + ", g=" + g + ", b=" + b + ", a=" + a + " >";
		}
	}

	/**
	 * RGBA color composed of 4 floats
	 * 
	 * @since v0.8
	 */
	public static class ccColor4F {
		public float r;
		public float g;
		public float b;
		public float a;

		public ccColor4F() {
			this.set(1.0f, 1.0f, 1.0f, 1.0f);
		}

		public ccColor4F(float r, float g, float b, float a) {
			this.set(r, g, b, a);
		}

		public ccColor4F(final ccColor4F c) {
			this.set(c);
		}

		public ccColor4F(ccColor4B c) {
			this.set(c.r/0xFF, c.g/0xFF, c.b/0xFF, c.a/0xFF);
		}

		public ccColor4F(ccColor3B c) {
			this.set(c.r/0xFF, c.g/0xFF, c.b/0xFF, 1.0f);
		}

		public void set(final ccColor4F c) {
			this.set(c.r, c.g, c.b, c.a);
		}

		public void set(float r, float g, float b, float a) {
			this.r = r;
			this.g = g;
			this.b = b;
			this.a = a;
		}

		/**
		 * Returns a ccColor4F from a ccColor3B. Alpha will be 1.
		 * 
		 * @since v0.99.1
		 */
		public static ccColor4F ccc4FFromccc3B(ccColor3B c) {
			return new ccColor4F(c.r/255.f, c.g/255.f, c.b/255.f, 1.f);
		}

		//! helper that creates a ccColor4f type
		public static ccColor4F ccc4f(float r, float g, float b, float a) {
			return new ccColor4F(r, g, b, a);
		}

		/**
		 * Returns a ccColor4F from a ccColor4B.
		 * 
		 * @since v0.99.1
		 */
		public static ccColor4F ccc4FFromccc4B(ccColor4B c) {
			return new ccColor4F(c.r/255.f, c.g/255.f, c.b/255.f, c.a/255.f);
		}

		/**
		 * returns YES if both ccColor4F are equal. Otherwise it returns NO.
		 * 
		 * @since v0.99.1
		 */
		public static boolean ccc4FEqual(ccColor4F a, ccColor4F b) {
			return ((a.r == b.r) && (a.g == b.g) && (a.b == b.b) && (a.a == b.a));
		}

		public float[] toFloatArray() {
			return new float[]{r, g, b, a};
		}

		public String toString() {
			return "< r=" + r + ", g=" + g + ", b=" + b + ", a=" + a + " >";
		}
	}

	/**
	 * A vertex composed of 2 floats: x, y
	 * 
	 * @since v0.8
	 */
	public static class ccVertex2F {
		public float x;
		public float y;

		public ccVertex2F() {
			this.set(0.0f, 0.0f);
		}

		public ccVertex2F(float x, float y) {
			this.set(x, y);
		}

		public ccVertex2F(final ccVertex2F v) {
			this.set(v);
		}

		public void set(final ccVertex2F v) {
			this.set(v.x, v.y);
		}

		public void set(final float x, final float y) {
			this.x = x;
			this.y = y;
		}

		public static ccVertex2F vertex2(final float x, final float y) {
			return new ccVertex2F(x, y);
		}

		public void setCGPoint(final CCPoint p) {
			set(p.x, p.y);
		}
	}

	/**
	 * A vertex composed of 3 floats: x, y, z
	 * 
	 * @since v0.8
	 */
	public static class ccVertex3F {
		public float x;
		public float y;
		public float z;

		public static ccVertex3F vertex3(final float x, final float y, final float z) {
			return new ccVertex3F(x, y, z);
		}

		public ccVertex3F(float x, float y, float z) {
			set(x, y, z);
		}

		public ccVertex3F(final ccVertex3F v) {
			set(v.x, v.y, v.z);
		}

		public void set(float x, float y, float z) {
			this.x = x;
			this.y = y;
			this.z = z;
		}
	}

	/**
	 * A texcoord composed of 2 floats: u, y
	 * 
	 * @since v0.8
	 */
	public static class ccTex2F {
		public float u;
		public float v;

		public static ccTex2F tex2(final float u, final float v) {
			return new ccTex2F(u , v);
		}

		public ccTex2F(final float u, final float v) {
			set(u, v);
		}

		public ccTex2F(final ccTex2F t) {
			set(t.u, t.v);
		}

		public void set(final float u, final float v) {
			this.u = u;
			this.v = v;
		}

		public float[] toFloatArray() {
			return new float[] {u, v};
		}
	}

	//! Point Sprite component
	public static class ccPointSprite {
		public ccVertex2F pos = new ccVertex2F();		// 8 bytes
		public ccColor4B color = new ccColor4B();		// 4 bytes
		public float size;								// 4 bytes

		public static final int spriteSize = 16;
	}

	//!	A 2D Quad. 4 * 2 floats
	public static class ccQuad2 {
		public static final int size = 4 * 2;

		public ccVertex2F tl;
		public ccVertex2F tr;
		public ccVertex2F bl;
		public ccVertex2F br;

		public ccQuad2() {
			tl = ccVertex2F.vertex2(0.0f, 0.0f);
			tr = ccVertex2F.vertex2(0.0f, 0.0f);
			bl = ccVertex2F.vertex2(0.0f, 0.0f);
			br = ccVertex2F.vertex2(0.0f, 0.0f);
		}

		public ccQuad2(float a, float b, float c, float d, float e, float f, float g, float h) {
			tl = ccVertex2F.vertex2(a, b);
			tr = ccVertex2F.vertex2(c, d);
			bl = ccVertex2F.vertex2(e, f);
			br = ccVertex2F.vertex2(g, h);
		}

		public ccQuad2(float[] f) {
			tl = ccVertex2F.vertex2(f[0], f[1]);
			tr = ccVertex2F.vertex2(f[2], f[3]);
			bl = ccVertex2F.vertex2(f[4], f[5]);
			br = ccVertex2F.vertex2(f[6], f[7]);
		}

		public float[] toFloatArray() {
			return new float[]{	tl.x, tl.y,
								tr.x, tr.y,
								bl.x, bl.y,
								br.x, br.y};
		}

		public String toString() {
			return "CCQuad2: (	" + tl.x + ", " + tl.y + " " +
									tr.x + ", " + tr.y + " " +
									bl.x + ", " + bl.y + " " +
									br.x + ", " + br.y + " )";
		}
	}

	//!	A 3D Quad. 4 * 3 floats
	public static class ccQuad3 {
		public static final int size = 4 * 3;

		public ccVertex3F bl;
		public ccVertex3F br;
		public ccVertex3F tl;
		public ccVertex3F tr;

		public ccQuad3() {
			bl = ccVertex3F.vertex3(0.0f, 0.0f, 0.0f);
			br = ccVertex3F.vertex3(0.0f, 0.0f, 0.0f);
			tl = ccVertex3F.vertex3(0.0f, 0.0f, 0.0f);
			tr = ccVertex3F.vertex3(0.0f, 0.0f, 0.0f);
		}

		public ccQuad3(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l) {
			bl = ccVertex3F.vertex3(a, b, c);
			br = ccVertex3F.vertex3(d, e, f);
			tl = ccVertex3F.vertex3(g, h, i);
			tr = ccVertex3F.vertex3(j, k, l);
		}

		public ccQuad3(float[] f) {
			bl = ccVertex3F.vertex3(f[0], f[1], f[2]);
			br = ccVertex3F.vertex3(f[3], f[4], f[5]);
			tl = ccVertex3F.vertex3(f[6], f[7], f[8]);
			tr = ccVertex3F.vertex3(f[9], f[10], f[11]);
		}

		public float[] toFloatArray() {
			return new float[] {	bl.x, bl.y, bl.z,
									br.x, br.y, br.z,
									tl.x, tl.y, tl.z,
									tr.x, tr.y, tr.z};
		}

		public String toString() {
			return "CCQuad3: (	" + tl.x + ", " + tl.y + ", " + tl.z + " " +
									tr.x + ", " + tr.y + ", " + tl.z + " " +
									bl.x + ", " + bl.y + ", " + tl.z + " " +
									br.x + ", " + br.y + ", " + tl.z + " )";
		}
	}

	//! a Point with a vertex point, a tex coord point and a color 4B
	public static class ccV2F_C4B_T2F {
		//! vertices (2F)
		public ccVertex2F vertices;
		//! colors (4B)
		public ccColor4B colors;
		//! tex coords (2F)
		public ccTex2F texCoords;
	}

	//! a Point with a vertex point, a tex coord point and a color 4F
	public static class ccV2F_C4F_T2F {
		//! vertices (2F)
		public ccVertex2F vertices;
		//! colors (4F)
		public ccColor4F colors;
		//! tex coords (2F)
		public ccTex2F texCoords;

		public ccV2F_C4F_T2F() {
			vertices = new ccVertex2F(0.0f, 0.0f);
			colors = new ccColor4F();
			texCoords = new ccTex2F(0, 0);
		}
	}

	//! a Point with a vertex point, a tex coord point and a color 4B
	public static class ccV3F_C4B_T2F {
		//! vertices (3F)
		public ccVertex3F vertices;				// 12 bytes
		//	char __padding__[4];

		//! colors (4B)
		public ccColor4B colors;				// 4 bytes
		//	char __padding2__[4];

		// tex coords (2F)
		public ccTex2F texCoords;				// 8 byts
	}

	//! A Triangle of ccV2F_C4B_T2F
	public static class ccV2F_C4B_T2F_Triangle {
		//! Point A
		public ccV2F_C4B_T2F a;
		//! Point B
		public ccV2F_C4B_T2F b;
		//! Point B
		public ccV2F_C4B_T2F c;
	}

	//! A Quad of ccV2F_C4B_T2F
	public static class ccV2F_C4B_T2F_Quad {
		//! bottom left
		public ccV2F_C4B_T2F bl;
		//! bottom right
		public ccV2F_C4B_T2F br;
		//! top left
		public ccV2F_C4B_T2F tl;
		//! top right
		public ccV2F_C4B_T2F tr;
	}

	//! 4 ccVertex3FTex2FColor4B
	public static class ccV3F_C4B_T2F_Quad {
		//! top left
		public ccV3F_C4B_T2F tl;
		//! bottom left
		public ccV3F_C4B_T2F bl;
		//! top right
		public ccV3F_C4B_T2F tr;
		//! bottom right
		public ccV3F_C4B_T2F br;
	}

	//! 4 ccVertex2FTex2FColor4F Quad
	public static class ccV2F_C4F_T2F_Quad {
		//! bottom left
		public ccV2F_C4F_T2F bl;
		//! bottom right
		public ccV2F_C4F_T2F br;
		//! top left
		public ccV2F_C4F_T2F tl;
		//! top right
		public ccV2F_C4F_T2F tr;
	}

	//! Blend Function used for textures
	public static class ccBlendFunc {
		public static final ccBlendFunc kCCBlendFuncDisable = new ccBlendFunc(GL_ONE, GL_ZERO);

		//! source blend function
		public int src;
		//! destination blend function
		public int dst;

		public ccBlendFunc() {
			this.src = GL_ONE;
			this.dst = GL_ZERO;
		}

		public ccBlendFunc(int src, int dst) {
			this.set(src, dst);
		}

		public ccBlendFunc(final ccBlendFunc blendFunc) {
			this.set(blendFunc);
		}

		public void set(final ccBlendFunc blendFunc) {
			this.set(blendFunc.src, blendFunc.dst);
		}

		public void set(int src, int dst) {
			this.src = src;
			this.dst = dst;
		}

		public void setSrc(int s) {
			src = s;
		}

		public int getSrc() {
			return src;
		}

		public void setDst(int d) {
			dst = d;
		}

		public int getDst() {
			return dst;
		}

		public String toString() {
			return "< src=" + src + ", dst=" + dst + " >";
		}
	}

	// XXX: If any of these enums are edited and/or reordered, update CCTexture2D.m
	//! Vertical text alignment type
	public enum CCVerticalTextAlignment {
		kCCVerticalTextAlignmentTop,
		kCCVerticalTextAlignmentCenter,
		kCCVerticalTextAlignmentBottom,
	}

	// XXX: If any of these enums are edited and/or reordered, update CCTexture2D.m
	//! Horizontal text alignment type
	public enum CCTextAlignment {
		kCCTextAlignmentLeft,
		kCCTextAlignmentCenter,
		kCCTextAlignmentRight,
	}

	// types for animation in particle systems

	// texture coordinates for a quad
	public static class ccT2F_Quad {
		//! bottom left
		ccTex2F    bl;
		//! bottom right
		ccTex2F    br;
		//! top left
		ccTex2F    tl;
		//! top right
		ccTex2F    tr;
	}

	// struct that holds the size in pixels, texture coordinates and delays for animated CCParticleSystemQuad
	public static class ccAnimationFrameData {
		ccT2F_Quad texCoords;
		float delay;
		CCSize size; 
	}
}
