using UnityEngine;

public class RockMeshGenerator : MonoBehaviour {

	public Vector2Int faceVertexNumberRange;
	public Vector2 faceRadiusRange;
	public float noiseValueScale;
	public Vector2 heightRange;

	void Awake()
	{
		GenerateMesh();
	}

	void OnGUI()
	{
		if(GUILayout.Button("Generate Mesh"))
		{
			GenerateMesh();
		}
	}

	void GenerateMesh()
	{
		var mesh = new Mesh();
		var faceVertexCount = faceVertexNumberRange.Random();
		var vertices = new Vector3[faceVertexCount * 2];
		var numberOfFaces = ((faceVertexCount - 2) * 2) + faceVertexCount * 2;
		var triangles = new int[numberOfFaces * 3];
		var baseRadius = Random.Range(faceRadiusRange.x, faceRadiusRange.y);
		var height = Random.Range(heightRange.x, heightRange.y);

		//Counters
		int vertexIndex = 0;
		int triangleIndex = 0;

		//Noise
		var perlin = new LibNoise.Generator.Perlin();
//		var noise = new LibNoise.Noise2D(32, 32, perlin);

		//Generate top vertices
		var angleOffset = Random.Range(0f, 360f);
		for(int i=0; i<faceVertexCount; i++)
		{
			var angle = (i / (float) faceVertexCount) * 360f;
			var workingAngle = (angle + angleOffset) % 360f;
			var direction = new Vector3(Mathf.Cos(workingAngle * Mathf.Deg2Rad), 0f, Mathf.Sin(workingAngle * Mathf.Deg2Rad));
			var noiseValue = (float) (perlin.GetValue(direction) * noiseValueScale);
			var position = direction * (baseRadius + noiseValue) + Vector3.up * height * 0.5f;
			vertices[vertexIndex++] = position;
		}

		//Generate bottom vertices
		for(int i=0; i<faceVertexCount; i++)
		{
			var angle = (i / (float) faceVertexCount) * 360f;
			var workingAngle = (angle + angleOffset) % 360f;
			var direction = new Vector3(Mathf.Cos(workingAngle * Mathf.Deg2Rad), 0f, Mathf.Sin(workingAngle * Mathf.Deg2Rad));
			var noiseValue = (float) (perlin.GetValue(direction) * noiseValueScale);
			var position = direction * (baseRadius + noiseValue) + Vector3.down * height * 0.5f;
			vertices[vertexIndex++] = position;
		}

		//Generate top triangles
		for(int i=0; i<faceVertexCount-2; i++)
		{
			triangles[triangleIndex++] = 0;
			triangles[triangleIndex++] = i+2;
			triangles[triangleIndex++] = i+1;
		}

		//Generate bottom triangles
		for(int i=0; i<faceVertexCount-2; i++)
		{
			triangles[triangleIndex++] = faceVertexCount;
			triangles[triangleIndex++] = faceVertexCount+i+1;
			triangles[triangleIndex++] = faceVertexCount+i+2;
		}

		//Generate side triangles
		for(int i=0; i<faceVertexCount; i++)
		{
			var last = i == faceVertexCount-1;
			triangles[triangleIndex++] = i;
			triangles[triangleIndex++] = last ? faceVertexCount : i+faceVertexCount+1;
			triangles[triangleIndex++] = i+faceVertexCount;

			triangles[triangleIndex++] = i;
			triangles[triangleIndex++] = last ? 0 : i+1;
			triangles[triangleIndex++] = last ? faceVertexCount : i+faceVertexCount+1;
		}

		mesh.vertices = vertices;
		mesh.triangles = triangles;
		mesh.RecalculateNormals();

		if(GetComponent<MeshFilter>())
		{
			GetComponent<MeshFilter>().sharedMesh = mesh;
		}
		if(GetComponent<MeshCollider>())
		{
			GetComponent<MeshCollider>().sharedMesh = mesh;
		}
	}

	void OnValidate()
	{
		if(faceVertexNumberRange.X < 3)
		{
			faceVertexNumberRange.X = 3;
		}

		if(faceVertexNumberRange.Y < 3)
		{
			faceVertexNumberRange.Y = 3;
		}
	}
}

[System.Serializable]
public struct Vector2Int
{
	public int X;
	public int Y;

	public Vector2Int (int X, int Y)
	{
		this.X = X;
		this.Y = Y;
	}

	public override bool Equals (object obj)
	{
		return obj is Vector2Int && ((Vector2Int) obj).X == X && ((Vector2Int) obj).Y == Y;
	}

	public override int GetHashCode ()
	{
		int hash = 17;
		hash = hash * 23 + X.GetHashCode();
		hash = hash * 23 + Y.GetHashCode();
		return hash;
	}

	public override string ToString ()
	{
		return string.Format ("{0},{1}", X, Y);
	}

	public int Random()
	{
		return UnityEngine.Random.Range(X, Y);
	}
}
