#if SELFTEST
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;

namespace TIASshot {

    /// <summary>
    /// UI スレッドのメッセージを回しながら待つ処理（SELFTEST 限定）．
    /// SelfTestRunner と TIASshot.Tests の共通ハーネス（層②）の両方から使う．
    /// ワーカースレッドからの Control.Invoke（ShowMessage / EnableShots 等）やタイマーの Tick は
    /// UI スレッドがメッセージを処理しないと実行されないため，Join や Sleep だけで待つと相互待機でハングする．
    /// 必ずフォームを生成したスレッド（STA）から呼ぶこと．
    /// </summary>
    internal static class SelfTestPump {

        // 1 回のメッセージ処理ごとの休止(ms)（CPU を占有しないため．応答性を損なわない短さにする）
        private const int SleepMs = 2;

        /// <summary>
        /// 条件が成立するまでメッセージを処理して待つ．
        /// </summary>
        /// <param name="condition">成立を待つ条件（UI スレッドで評価する）</param>
        /// <param name="timeout">待機の上限</param>
        /// <param name="afterEachPump">メッセージ処理ごとに呼ぶ処理（null 可．UI 例外の再送出等に使う）</param>
        /// <returns>上限内に成立したら true，タイムアウトしたら false</returns>
        public static bool PumpUntil(Func<bool> condition, TimeSpan timeout, Action afterEachPump = null) {
            var sw = Stopwatch.StartNew();
            while (!condition()) {
                if (sw.Elapsed > timeout) return false;
                Application.DoEvents();
                afterEachPump?.Invoke();
                Thread.Sleep(SleepMs);
            }
            return true;
        }

        /// <summary>
        /// 指定時間だけメッセージを処理し続ける（タイマー駆動の表示更新等を反映させるため）．
        /// </summary>
        /// <param name="duration">処理し続ける時間</param>
        /// <param name="afterEachPump">メッセージ処理ごとに呼ぶ処理（null 可）</param>
        public static void PumpFor(TimeSpan duration, Action afterEachPump = null) {
            var sw = Stopwatch.StartNew();
            while (sw.Elapsed < duration) {
                Application.DoEvents();
                afterEachPump?.Invoke();
                Thread.Sleep(SleepMs);
            }
        }
    }
}
#endif
