using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using com.deeperbeige.lib;

/*
 * Dynamic line through points
 */

public class SmoothLine
{
	public GameObject gameObject;
	
	private List<Vector3> points;
	private Mesh mesh;
	private Color32 colour;

	// Use this for initialization
	public SmoothLine(Color32 colour, GameObject parent, Material material)
	{
		mesh      = new Mesh();		
		mesh.name = "RibbonMesh";
		mesh.MarkDynamic();

		this.colour = colour;

		gameObject = new GameObject("SmoothLine");
		gameObject.transform.parent = parent.transform;
		gameObject.transform.localPosition = Vector3.zero;
		gameObject.AddComponent<MeshRenderer>();
		gameObject.AddComponent<MeshFilter>();
		gameObject.GetComponent<MeshFilter>().mesh = mesh;
		gameObject.GetComponent<MeshRenderer>().material = material;
		gameObject.GetComponent<MeshRenderer>().material.color = colour;

		points = new List<Vector3>();
	}
	
	// Add a new point into the line
	public void addPoint(Vector3 point)
	{
		// See if this point is significantly far from the previous one
		if (points.Count > 0 && (point - points[points.Count - 1]).sqrMagnitude < (0.01 * 0.01)) return;
		
		// Remember the new point
		points.Add(point);
		Vector3 pointDiff = Vector3.zero;
		Vector3 pointNorm = Vector3.zero;
		if (points.Count > 1)
		{
			pointDiff = points[points.Count - 1] - points[points.Count - 2];
			pointNorm = new Vector3(-pointDiff.z, 0, pointDiff.x);
		}

		// Grow the arrays by one element
		Vector3[] vertices  = new Vector3[4 * points.Count];
		Vector2[] uv        = new Vector2[vertices.Length];
		Color32[] colours   = new Color32[vertices.Length];
		int[]     triangles = new int[(points.Count - 1) * 12];
		
		System.Array.Copy(mesh.vertices,  vertices,  mesh.vertices.Length);
		System.Array.Copy(mesh.uv,        uv,        mesh.uv.Length);
		System.Array.Copy(mesh.colors32,  colours,   mesh.colors32.Length);
		System.Array.Copy(mesh.triangles, triangles, mesh.triangles.Length);
		
		mesh.Clear(false);
		
		// Forward faces
		vertices[vertices.Length - 4] = points[points.Count - 1];
		vertices[vertices.Length - 3] = points[points.Count - 1];
		
		// Adjust points
		pointNorm.Normalize();
		vertices[vertices.Length - 4] = vertices[vertices.Length - 4] - 0.4f * pointNorm;
		vertices[vertices.Length - 3] = vertices[vertices.Length - 4] + 0.4f * pointNorm;
			
		// Copy to second half of array for reversed faces
		vertices[vertices.Length - 2] = vertices[vertices.Length - 4];
		vertices[vertices.Length - 1] = vertices[vertices.Length - 3];
			
		// UVs for forward faces
		uv[uv.Length - 4] = new Vector2((points.Count + 0) % 2, 0);
		uv[uv.Length - 3] = new Vector2((points.Count + 1) % 2, 1);
			
		// UVs for reversed faces
		uv[uv.Length - 2] = uv[uv.Length - 4];
		uv[uv.Length - 1] = uv[uv.Length - 3];
			
		// Colours
		colours[colours.Length - 4] = colour;
		colours[colours.Length - 3] = colour;
		colours[colours.Length - 2] = colour;
		colours[colours.Length - 1] = colour;
		
		if (triangles.Length > 0)
		{
			triangles[triangles.Length - 12] = vertices.Length - 8;
			triangles[triangles.Length - 11] = vertices.Length - 7;
			triangles[triangles.Length - 10] = vertices.Length - 4;
			
			triangles[triangles.Length -  9] = vertices.Length - 7;
			triangles[triangles.Length -  8] = vertices.Length - 3;
			triangles[triangles.Length -  7] = vertices.Length - 4;
			
			triangles[triangles.Length -  6] = vertices.Length - 2;
			triangles[triangles.Length -  5] = vertices.Length - 5;
			triangles[triangles.Length -  4] = vertices.Length - 6;
			
			triangles[triangles.Length -  3] = vertices.Length - 1;
			triangles[triangles.Length -  2] = vertices.Length - 5;
			triangles[triangles.Length -  1] = vertices.Length - 2;
		}
		
		// Assign new geometry
		mesh.vertices  = vertices;
		mesh.uv        = uv;
		mesh.triangles = triangles;
		mesh.colors32  = colours;
		mesh.RecalculateNormals();
		
		//if (points.Count < 2) return;
		gameObject.GetComponent<MeshFilter>().mesh = mesh;
	}
	
	// Wipes this line's gameobject
	public void dispose()
	{
		MonoBehaviour.Destroy(gameObject);
		
		points     = null;
		mesh       = null;
		gameObject = null;
	}
}
