package com.google.ar.core.examples.java.common.java3d;

public class Cylinder extends Primitive {
	public static final int BODY = 0;
	public static final int TOP = 1;
	public static final int BOTTOM = 2;

	static final int MID_REZ_DIV_X = 16;
	static final int MID_REZ_DIV_Y = 1;

	float radius;
	float height;
	int xdivisions;
	int ydivisions;

	private Shape3D bodyShape = null;
	private Shape3D topShape = null;
	private Shape3D bottomShape = null;

	public Cylinder() {
		this(0.5f, 1.0f, null);
	}
	
	public Cylinder(float r, float h) {
		this(r, h, null);
	}

	public Cylinder(float r, float h, Appearance ap) {
		xdivisions = MID_REZ_DIV_X;
		ydivisions = MID_REZ_DIV_Y;
		
		float coordinates[][] = new float[xdivisions * 2][3];

		float coordinates_center[][] = new float[2][3];//上面と底面の中心の座標
		coordinates_center[0][0] = 0;
		coordinates_center[0][1] = h / 2;
		coordinates_center[0][2] = 0;
		coordinates_center[1][0] = 0;
		coordinates_center[1][1] = -h / 2;
		coordinates_center[1][2] = 0;
		
		for (int i = 0; i < xdivisions; i++) { // TOP(上面)側の点の(x,y,z)座標
			coordinates[i][0] = r * (float) Math.cos(2 * Math.PI * ((double)i / xdivisions));
			coordinates[i][1] = h / 2;
			coordinates[i][2] = r * (float) Math.sin(2 * Math.PI * ((double)i / xdivisions));
		}
		for (int i = 0; i < xdivisions; i++) { // BOTTOM(底面)の点の(x,y,z)座標
			coordinates[i + xdivisions][0] = r * (float) Math.cos(2 * Math.PI * ((double)i / xdivisions));
			coordinates[i + xdivisions][1] = -h / 2;
			coordinates[i + xdivisions][2] = r * (float) Math.sin(2 * Math.PI * ((double)i / xdivisions));
		}

		float uv[] = { 0, 0, 1, 0, 1, 1, 0, 1, };

		// 各面のジオメトリを作成
		IndexedTriangleStripArray bodyGeom = new IndexedTriangleStripArray(xdivisions * 2,
				IndexedTriangleStripArray.COORDINATES | IndexedTriangleStripArray.NORMALS | IndexedTriangleStripArray.TEXTURE_COORDINATE_2,
				xdivisions * 2 + 2,
				new int[] { xdivisions * 2 + 2 });
		TriangleFanArray topGeom = new TriangleFanArray(xdivisions + 2,
				TriangleFanArray.COORDINATES | TriangleFanArray.NORMALS | TriangleFanArray.TEXTURE_COORDINATE_2,
				new int[] { xdivisions + 2 });
		TriangleFanArray bottomGeom = new TriangleFanArray(xdivisions + 2,
				TriangleFanArray.COORDINATES | TriangleFanArray.NORMALS | TriangleFanArray.TEXTURE_COORDINATE_2,
				new int[] { xdivisions + 2 });

		// 頂点座標の設定
			//側面
		for (int i = 0; i < xdivisions; i++) {	//上面から底面へ垂直に降りて、底面から上面へ斜めに上る順に座標を設定
			bodyGeom.setCoordinate(2 * i    , coordinates[i]);
			bodyGeom.setCoordinate(2 * i + 1, coordinates[i + xdivisions]);
		}

		int coordinateIndices[] = new int[xdivisions * 2 + 2];
		for (int i = 0; i < xdivisions * 2; i++) {
				coordinateIndices[i] = i;
		}
		coordinateIndices[xdivisions * 2] = 0;
		coordinateIndices[xdivisions * 2 + 1] = 1;		
		
		bodyGeom.setCoordinateIndices(0, coordinateIndices);
		
			//上面
		topGeom.setCoordinate(0,coordinates_center[0]);
		for(int i = 0; i < xdivisions; i++){
			topGeom.setCoordinate(i + 1, coordinates[i]);					//上から見て反時計回りの順
		}
		topGeom.setCoordinate(xdivisions + 1, coordinates[0]);

			//底面
		bottomGeom.setCoordinate(0,coordinates_center[1]);
		bottomGeom.setCoordinate(1, coordinates[xdivisions]);
		for(int i = 0; i < xdivisions; i++){	
			bottomGeom.setCoordinate(i + 2, coordinates[2 * xdivisions - i - 1]);	//上から見て時計回りの順
		}

		 // テクスチャ座標の設定
		 bodyGeom.setTextureCoordinates(0, uv);	//
		 topGeom.setTextureCoordinates(0, uv);
		 bottomGeom.setTextureCoordinates(0, uv);
		
		 // 法線の設定
		 
		for (int i = 0; i < xdivisions * 2; i++) {
			 float[] bodyNorm = new float[]{(float) Math.cos(Math.PI * ((double)i / xdivisions)),0.0f,(float) Math.sin(Math.PI * ((double)i / xdivisions))};
			 bodyGeom.setNormal(i, bodyNorm);
		}
		
		float[] topNorm = new float[]{0.0f, 1.0f, 0.0f};
		for (int i = 0; i < xdivisions + 2; i++) {
			 topGeom.setNormal(i, topNorm);
		}
		
		float[] bottomNorm = new float[]{0.0f, -1.0f, 0.0f};
		for (int i = 0; i < xdivisions + 2; i++) {
			 bottomGeom.setNormal(i, bottomNorm);
		}
		
		// 表面属性の作成
		if (ap == null) {
			ap = new Appearance();
		}
		setAppearance(ap);
//		Appearance ap1 = new Appearance();
//		Appearance ap2 = new Appearance();
//		Appearance ap3 = new Appearance();
		// Appearance ap4 = new Appearance();
		// Appearance ap5 = new Appearance();
		// Appearance ap6 = new Appearance();
//		Texture tex = ap.getTexture();
//		if (tex != null && tex instanceof TextureCubeMap) {
		// GL10 では GL_TEXTURE_CUBE_MAP が使えないので、TextureCubeMap の場合は Texture2D
		// に分解する
//		ImageComponent ic1 = tex.getImage(TextureCubeMap.POSITIVE_Z);
//		Texture2D tex1 = new Texture2D(Texture2D.BASE_LEVEL, Texture2D.RGB,
//		ic1.width, ic1.height);
//		tex1.setImage(0, ic1);
//		ap1.setTexture(tex1);
//		ImageComponent ic2 = tex.getImage(TextureCubeMap.NEGATIVE_Z);
//		Texture2D tex2 = new Texture2D(Texture2D.BASE_LEVEL, Texture2D.RGB,
//		ic2.width, ic2.height);
//		tex2.setImage(0, ic2);
//		ap2.setTexture(tex2);
//		ImageComponent ic3 = tex.getImage(TextureCubeMap.POSITIVE_X);
//		Texture2D tex3 = new Texture2D(Texture2D.BASE_LEVEL, Texture2D.RGB,
//		ic3.width, ic3.height);
//		tex3.setImage(0, ic3);
		// ap3.setTexture(tex3);
		// ImageComponent ic4 = tex.getImage(TextureCubeMap.NEGATIVE_X);
		// Texture2D tex4 = new Texture2D(Texture2D.BASE_LEVEL, Texture2D.RGB,
		// ic4.width, ic4.height);
		// tex4.setImage(0, ic4);
		// ap4.setTexture(tex4);
		// ImageComponent ic5 = tex.getImage(TextureCubeMap.POSITIVE_Y);
		// Texture2D tex5 = new Texture2D(Texture2D.BASE_LEVEL, Texture2D.RGB,
		// ic5.width, ic5.height);
		// tex5.setImage(0, ic5);
		// ap5.setTexture(tex5);
		// ImageComponent ic6 = tex.getImage(TextureCubeMap.NEGATIVE_Y);
		// Texture2D tex6 = new Texture2D(Texture2D.BASE_LEVEL, Texture2D.RGB,
		// ic6.width, ic6.height);
		// tex6.setImage(0, ic6);
		// ap6.setTexture(tex6);
//		}
		// 各面の作成			//全て同じテクスチャー(ap)を貼り付ける
		bodyShape = new Shape3D(bodyGeom, ap);
		topShape = new Shape3D(topGeom, ap);
		bottomShape = new Shape3D(bottomGeom, ap);
		//
		radius = r;
		height = h;
	}
	
	public double getRadius() {
		return radius;
	}
	public double getHeight() {
		return height;
	}


	@Override
	public Shape3D getShape(int partid) {
		switch (partid) {
		case BODY:
			return bodyShape;
		case TOP:
			return topShape;
		case BOTTOM:
			return bottomShape;
		}
		return null;
	}
	
	public Node cloneTree() {
		Appearance ap = getAppearance();
		if (ap != null) {
			ap = (Appearance)ap.cloneNodeComponent();
		}		
		Cylinder c = new Cylinder(radius, height, ap);
	    return c;
	}
}