using System;
using System.Diagnostics;
using UnityEditor;
namespace EnhancedHierarchy {
    /// Utility class for running async tasks within the main thread.
    public static class After {
        /// Wait for a condition to become true, then executes the callback.
        /// Function that will be called every frame that returns whether to invoke the callback or not.
        /// The callback to be called when the condition becomes true.
        /// Maximum time to wait in milliseconds before cancelling the callback.
        public static void Condition(Func condition, Action callback, double timeoutMs = 0d) {
            var update = new EditorApplication.CallbackFunction(() => { });
            var timeoutsAt = EditorApplication.timeSinceStartup + (timeoutMs / 1000d);
            var stack = new StackFrame(1, true);
            update = () => {
                if (timeoutMs > 0d && EditorApplication.timeSinceStartup >= timeoutsAt) {
                    EditorApplication.update -= update;
                    UnityEngine.Debug.LogErrorFormat("Condition timedout at {0}:{1}", stack.GetFileName(), stack.GetFileLineNumber());
                    return;
                }
                if (condition()) {
                    EditorApplication.update -= update;
                    callback();
                }
            };
            EditorApplication.update += update;
        }
        /// Wait for the given amount of editor frames, then executes the callback.
        /// The number of frames to wait for.
        /// The callback to be called after the specified frames.
        public static void Frames(int frames, Action callback) {
            var f = 0;
            Condition(() => f++ >= frames, callback);
        }
        /// Wait for the given time, then executes the callback.
        /// How long to wait until calling the callback, in milliseconds.
        /// The callback to be called after the specified time.
        public static void Milliseconds(double milliseconds, Action callback) {
            var end = EditorApplication.timeSinceStartup + (milliseconds / 1000f);
            Condition(() => EditorApplication.timeSinceStartup >= end, callback);
        }
    }
}