using UnityEngine;
using System.Collections;

public class Utils
{
    public static IEnumerator MoveItems(Transform[] items, Vector3[] targets, float duration, System.Action onEnd = null, bool smooth = false)
    {
        float t = Time.time;
        float dt = 0;

        Vector3[] starts = new Vector3[items.Length];
        for (int i = 0; i < items.Length; i++)
        {
            starts[i] = items[i].position;
        }

        if (smooth)
        {
            for (; dt < duration; dt = Time.time - t)
            {
                for (int i = 0; i < items.Length; i++)
                {
                    items[i].position = Vector3.Lerp(starts[i], targets[i], Mathf.Sqrt(dt / duration));
                }
                yield return new WaitForEndOfFrame();
            }
        }
        else
        {
            for (; dt < duration; dt = Time.time - t)
            {
                for (int i = 0; i < items.Length; i++)
                {
                    items[i].position = Vector3.Lerp(starts[i], targets[i], (dt / duration));
                }
                yield return new WaitForEndOfFrame();
            }
        }

        for (int i = 0; i < items.Length; i++)
        {
            items[i].position = targets[i];
        }

        if (onEnd != null)
            onEnd();
    }

    public static IEnumerator MoveItem(Transform item, Vector3 target, float duration, System.Action onEnd = null, bool smooth = false)
    {
        float t = Time.time;
        float dt = 0;

        Vector3 start = item.position;

        if (smooth)
        {
            for (; dt < duration; dt = Time.time - t)
            {
                item.position = Vector3.Lerp(start, target, Mathf.Sqrt(dt / duration));
                yield return new WaitForEndOfFrame();
            }
        }
        else
        {
            for (; dt < duration; dt = Time.time - t)
            {
                item.position = Vector3.Lerp(start, target, (dt / duration));
                yield return new WaitForEndOfFrame();
            }
        }

        item.position = target;

        if (onEnd != null)
            onEnd();
    }

    public static IEnumerator MoveAndRotateItem(Transform item, Vector3 target, Quaternion targetRotation, float duration, System.Action onEnd = null, bool smooth = false)
    {
        float t = Time.time;
        float dt = 0;

        Vector3 start = item.position;
        Quaternion startRot = item.rotation;
        if (smooth)
        {
            for (; dt < duration; dt = Time.time - t)
            {
                item.position = Vector3.Lerp(start, target, Mathf.Sqrt(dt / duration));
                item.rotation = Quaternion.Lerp(startRot, targetRotation, Mathf.Sqrt(dt / duration));
                yield return new WaitForEndOfFrame();
            }
        }
        else
        {
            for (; dt < duration; dt = Time.time - t)
            {
                item.position = Vector3.Lerp(start, target, (dt / duration));
                item.rotation = Quaternion.Lerp(startRot, targetRotation, (dt / duration));
                yield return new WaitForEndOfFrame();
            }
        }

        item.position = target;
        item.rotation = targetRotation;

        if (onEnd != null)
            onEnd();
    }

    public static IEnumerator DoDelayed(float delay, System.Action action)
    {
        yield return new WaitForSecondsRealtime(delay);
        action();
    }

    public static IEnumerator ScaleItem(Transform item, Vector3 targetScale, float duration, System.Action onEnd = null, bool smooth = false)
    {
        float t = Time.time;
        float dt = 0;

        Vector3 start = item.localScale;
        if (smooth)
        {
            for (; dt < duration; dt = Time.time - t)
            {
                item.localScale = Vector3.Lerp(start, targetScale, Mathf.Sqrt(dt / duration));
                yield return new WaitForEndOfFrame();
            }
        }
        else
        {
            for (; dt < duration; dt = Time.time - t)
            {
                item.localScale = Vector3.Lerp(start, targetScale, (dt / duration));
                yield return new WaitForEndOfFrame();
            }
        }

        item.localScale = targetScale;

        if (onEnd != null)
            onEnd();
    }

    public static IEnumerator DoOverTime(float duration, System.Action<float> onChange, System.Action onEnd = null, bool smooth = false)
    {
        float t = Time.time;
        float dt = 0;

        if (smooth)
        {
            for (; dt < duration; dt = Time.time - t)
            {
                if (onChange != null)
                    onChange(dt / duration);
                yield return new WaitForEndOfFrame();
            }
        }
        else
        {
            for (; dt < duration; dt = Time.time - t)
            {
                if (onChange != null)
                    onChange(dt / duration);
                yield return new WaitForEndOfFrame();
            }
        }

        if (onEnd != null)
            onEnd();

    }

    public static IEnumerator DoOverUnscaledTime(float duration, System.Action<float> onChange, System.Action onEnd = null, bool smooth = false)
    {
        float t = Time.unscaledTime;
        float dt = 0;

        if (smooth)
        {
            for (; dt < duration; dt = Time.unscaledTime - t)
            {
                if (onChange != null)
                    onChange(dt / duration);
                yield return new WaitForEndOfFrame();
            }
        }
        else
        {
            for (; dt < duration; dt = Time.unscaledTime - t)
            {
                if (onChange != null)
                    onChange(dt / duration);
                yield return new WaitForEndOfFrame();
            }
        }

        if (onEnd != null)
            onEnd();

    }

    public static IEnumerator WaitForSecondsUnscaled(float duration)
    {
        float t = Time.unscaledTime;
        while (Time.unscaledTime - t < duration)
            yield return null;
    }

    public static IEnumerator DoAfterCondition(System.Action action, System.Func<bool> condition)
    {
        while (!condition())
            yield return null;
        action();
    }

    public static IEnumerator CrossFade(Color a, Color b, float duration, System.Action<Color> onColorChange, System.Action onEnd = null)
    {
        float t = Time.time;
        float dt = 0;

        for (; dt < duration; dt = Time.time - t)
        {
            if (onColorChange != null)
                onColorChange(Color.Lerp(a, b, dt / duration));
            yield return new WaitForEndOfFrame();
        }
        onColorChange(b);
        if (onEnd != null)
            onEnd();
    }
}