﻿
using UnityEngine;

[ExecuteInEditMode]
public class MegaPathFollow : MonoBehaviour
{
	public	float	tangentDist = 0.01f;	// how far it looks ahead or behind to calc rotation
	public	float	alpha	= 0.0f;		// how far along curve as a percent
	public	float	speed	= 0.0f;		// how fast it moves
	public	bool	rot		= false;	// check if you want to change rotation
	public	float	time	= 0.0f;		// how long to take to travel whole shape (system checks UseDistance then time then speed for which method it chooses, set non used to 0)
	public	float	ctime	= 0.0f;		// current time for time animation
	public	int		curve	= 0;		// curve to use in shape
	public	MegaShape target;			// Shape to follow
	public	float	distance = 0.0f;	// distance along shape
	public	bool	animate = false;	// automatically moves the object
	public	bool	UseDistance = true;	// use distance method
	public	bool	addtwist = false;
	public Vector3	offset = Vector3.zero;
	public Vector3	rotate = Vector3.zero;

	public MegaRepeatMode	loopmode = MegaRepeatMode.Loop;

	public void SetPos(float a)
	{
		if ( target != null )
		{
			float twist = 0.0f;

			switch ( loopmode )
			{
				case MegaRepeatMode.Clamp:		a = Mathf.Clamp01(a);	break;
				case MegaRepeatMode.Loop:		a = Mathf.Repeat(a, 1.0f);	break;
				case MegaRepeatMode.PingPong:	a = Mathf.PingPong(a, 1.0f);	break;
			}

			Vector3 off = Vector3.zero;
			Vector3	pos = target.InterpCurve3D(curve, a, target.normalizedInterp, ref twist);

			if ( rot )
			{
				float ta = tangentDist / target.GetCurveLength(curve);
				Vector3 pos1 = target.InterpCurve3D(curve, a + ta, target.normalizedInterp);

				Vector3 rt = rotate;

				Quaternion tq = Quaternion.Euler(0.0f, 0.0f, twist);
				Quaternion er = Quaternion.Euler(rt);

				if ( addtwist )
					er = tq * er;

				Vector3 dir = pos1 - pos;
				Quaternion r = Quaternion.LookRotation(dir);	//pos1 - pos);	//transform.LookAt(target.transform.TransformPoint(target.InterpCurve3D(curve, a + ta, target.normalizedInterp)));
				// Calc offset vector
				Matrix4x4 tm = Matrix4x4.TRS(Vector3.zero, r * er, Vector3.one);
				off = tm.MultiplyPoint3x4(offset);

				transform.localRotation = r * er;
			}

			transform.position = target.transform.TransformPoint(pos - off);	// + offset;
		}
	}

	public void SetPosFomDist(float dist)
	{
		if ( target != null )
		{
			//float a = Mathf.Repeat(dist / target.GetCurveLength(curve), 1.0f);
			float a = dist / target.GetCurveLength(curve);
			float twist = 0.0f;

			switch ( loopmode )
			{
				case MegaRepeatMode.Clamp: a = Mathf.Clamp01(a); break;
				case MegaRepeatMode.Loop: a = Mathf.Repeat(a, 1.0f); break;
				case MegaRepeatMode.PingPong: a = Mathf.PingPong(a, 1.0f); break;
			}

			Vector3 off = Vector3.zero;
			Vector3 pos = target.InterpCurve3D(curve, a, target.normalizedInterp, ref twist);

			if ( rot )
			{
				float ta = tangentDist / target.GetCurveLength(curve);

				Vector3 pos1 = target.InterpCurve3D(curve, a + ta, target.normalizedInterp);
				Vector3 rt = rotate;

				Quaternion tq = Quaternion.Euler(0.0f, 0.0f, twist);
				Quaternion er = Quaternion.Euler(rt);	//otate);

				if ( addtwist )
					er = tq * er;

				Vector3 dir = pos1 - pos;
				Quaternion r = Quaternion.LookRotation(dir);	//pos1 - pos);	//transform.LookAt(target.transform.TransformPoint(target.InterpCurve3D(curve, a + ta, target.normalizedInterp)));

				// Calc offset vector
				Matrix4x4 tm = Matrix4x4.TRS(Vector3.zero, r * er, Vector3.one);

				off = tm.MultiplyPoint3x4(offset);

				transform.localRotation = r * er;
			}

			transform.position = target.transform.TransformPoint(pos - off);	// + offset;
		}
	}

	public void Start()
	{
		ctime = 0.0f;
		curve = 0;
	}

	void Update()
	{
		if ( animate )
		{
			if ( UseDistance )
				distance += speed * Time.deltaTime;
			else
			{
				if ( time > 0.0f )
				{
					ctime += Time.deltaTime;

					if ( ctime > time )
						ctime = 0.0f;

					alpha = (ctime / time) * 100.0f;
				}
				else
				{
					if ( speed != 0.0f )
					{
						alpha += speed * Time.deltaTime;

						if ( alpha > 100.0f )
							alpha = 0.0f;
						else
						{
							if ( alpha < 0.0f )
								alpha = 100.0f;
						}
					}
				}
			}
		}

		if ( UseDistance )
			SetPosFomDist(distance);
		else
			SetPos(alpha * 0.01f);
	}
}
