using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace com.deeperbeige.lib.curves
{
    public class CubicBezier
    {
		public Vector3 startPoint, endPoint, controlPoint1, controlPoint2;
		
		public CubicBezier() : this(Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero) {  }
		public CubicBezier(Vector3 start, Vector3 end, Vector3 control1, Vector3 control2)
		{
			this.startPoint    = start;
			this.endPoint      = end;
			this.controlPoint1 = control1;
			this.controlPoint2 = control2;
		}
		
		public Vector3 Interpolate(float t)
		{
			float  d = 1f - t;
			return d * d * d * startPoint + 3f * d * d * t * controlPoint1 + 3f * d * t * t * controlPoint2 + t * t * t * endPoint;
		}
		
		public Vector3 Velocity(float t)
		{
			return (-3f * startPoint +  9f * controlPoint1 - 9f * controlPoint2  + 3f * endPoint) * t * t
				+  ( 6f * startPoint - 12f * controlPoint1 + 6f * controlPoint2) * t
				-    3f * startPoint +  3f * controlPoint1;
		}
		
		// Interpolate the bezier into a series of points
		public Vector3[] LinePoints(int pointCount)
		{
			Vector3[] output = new Vector3[pointCount];
			
			for (int j = 0; j < pointCount; j++)
			{
				float frac = (float)j / (float)(pointCount - 1);
				output[j] = Interpolate(frac);
			}
			
			return output;
		}
		
		// Interpolate the bezier into a line segments and apply them to
		// a supplied line-renderer component to present them in the world
		// Optionally supply fromFrac and toFrac between 0 and 1 to draw
		// just a sub-segment of the line
		public void ApplyToLineRenderer(LineRenderer line, int pointCount) { ApplyToLineRenderer(line, pointCount, 0, 1); }
		public void ApplyToLineRenderer(LineRenderer line, int pointCount, float fromFrac, float toFrac)
		{
			line.SetVertexCount(pointCount);
			
			for (int j = 0; j < pointCount; j++)
			{
				float frac = Mathf.Lerp(fromFrac, toFrac, (float)j / (float)(pointCount - 1));
				line.SetPosition(j, Interpolate(frac));
			}
		}
	}
}