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

public class Sphere extends Primitive {
	public static final int BODY = 0;
	static final int MID_REZ_DIV = 16;
	
	private float radius;
	int divisions;

	private Shape3D bodyShape = null;

	public Sphere(float r, Appearance ap){
		divisions = MID_REZ_DIV;

		radius = r;
		// 各面のジオメトリを作成
		IndexedTriangleArray bodyGeom = new IndexedTriangleArray(divisions * (divisions / 2 - 1) + 2,
				IndexedTriangleArray.COORDINATES | IndexedTriangleArray.NORMALS | IndexedTriangleArray.TEXTURE_COORDINATE_2,
				divisions * ((divisions - 2) * 6 + 2 * 3));

		// 頂点座標と法線の設定
		float coordinates[][] = new float[divisions * (divisions / 2 - 1) + 2][3];
		for (int i = 0; i <= divisions / 2; i++) {	// 緯度方向のループ(北極から南極に向かって)
			if (i == 0) {
				// 北極の場合
				coordinates[0][0] = 0.0f;
				coordinates[0][1] = radius;
				coordinates[0][2] = 0.0f;
				bodyGeom.setNormal(0, new float[]{0.0f, 1.0f, 0.0f});
			} else if (i == divisions / 2) {
				// 南極の場合
				coordinates[divisions * (divisions / 2 - 1) + 1][0] = 0.0f;
				coordinates[divisions * (divisions / 2 - 1) + 1][1] = -radius;
				coordinates[divisions * (divisions / 2 - 1) + 1][2] = 0.0f;
				bodyGeom.setNormal(divisions * (divisions / 2 - 1) + 1, new float[]{0.0f, -1.0f, 0.0f});
			} else {
				float y = r * (float) Math.cos(2 * Math.PI * ((double) i / divisions));
				float r2 = r * (float) Math.sin(2 * Math.PI * ((double) i / divisions));
				for (int j = 0; j < divisions; j++) {	// 経度方向のループ
					float x = r2 * (float) Math.cos(2 * Math.PI * ((double) j / divisions));
					float z = -r2 * (float) Math.sin(2 * Math.PI * ((double) j / divisions));
					coordinates[(i - 1) * divisions + j + 1][0] = x;
					coordinates[(i - 1) * divisions + j + 1][1] = y;
					coordinates[(i - 1) * divisions + j + 1][2] = z;
					bodyGeom.setNormal((i - 1) * divisions + j + 1, new float[]{x / r, y / r, z / r});
				}
			}
		}

		for (int i = 0; i < divisions * (divisions / 2 - 1) + 2; i++) {
			bodyGeom.setCoordinate(i    , coordinates[i]);
		}

		int coordinateIndices[] = new int[divisions * ((divisions - 2) * 6 + 2 * 3)];
		int index = 0;
		for (int i = 0; i < divisions / 2; i++) {
			for (int j = 0; j < divisions; j++) {
				if (i == 0) {
					// 北極付近
					coordinateIndices[index] = 0;		// 北極
					coordinateIndices[index + 1] = j + 1;
					coordinateIndices[index + 2] = (j + 1) % divisions + 1;
					index += 3;
				} else if (i == divisions / 2 - 1) {
					// 南極付近
					coordinateIndices[index] = (i - 1) * divisions + j + 1;
					coordinateIndices[index + 1] = divisions * (divisions / 2 - 1) + 1;		// 南極
					coordinateIndices[index + 2] = (i - 1) * divisions + (j + 1) % divisions + 1;
					index += 3;
				} else {
					coordinateIndices[index] = (i - 1) * divisions + j + 1;
					coordinateIndices[index + 1] = i * divisions + j + 1;
					coordinateIndices[index + 2] = i * divisions + (j + 1) % divisions + 1;
					coordinateIndices[index + 3] = (i - 1) * divisions + j + 1;
					coordinateIndices[index + 4] = i * divisions + (j + 1) % divisions + 1;
					coordinateIndices[index + 5] = (i - 1) * divisions + (j + 1) % divisions + 1;
					index += 6;
				}
			}
		}

		bodyGeom.setCoordinateIndices(0, coordinateIndices);

		float uv[] = { 0, 0, 1, 0, 1, 1, 0, 1, };
		bodyGeom.setTextureCoordinates(0, uv);	//

		// 表面属性の作成
		if (ap == null) {
			ap = new Appearance();
		}
		setAppearance(ap);

		bodyShape = new Shape3D(bodyGeom, ap);
	}

	public float getRadius() {
		return radius;
	}

	public void setRadius(float radius) {
		this.radius = radius;
	}

	@Override
	public Shape3D getShape(int partid) {
		switch (partid) {
			case BODY:
				return bodyShape;
		}
		return null;
	}

	@Override
	public Node cloneTree() {
		Appearance ap = getAppearance();
		if (ap != null) {
			ap = (Appearance)ap.cloneNodeComponent();
		}
		Sphere s = new Sphere(radius, ap);
		return s;
	}
}
