#if HWTEST
using System;

namespace TIASshot {

    /// <summary>実機テストで使うカメラの機種（HWTEST 限定）</summary>
    internal enum HwTestCameraKind {
        /// <summary>Lumenera（Lucam）</summary>
        Lucam,
        /// <summary>ImagingSource（IScam）</summary>
        IScam,
    }

    /// <summary>
    /// 実機テスト（--hwtest）の引数（HWTEST 限定．SDK・UI に依存しない純粋な解析）．
    /// <code>TIASshot.exe --hwtest --camera &lt;lucam|iscam&gt; [--hwtest-out &lt;path&gt;] [--with-chart] [--hwtest-keep]</code>
    /// </summary>
    internal sealed class HwTestOptions {

        public const string FlagHwTest = "--hwtest";
        public const string FlagCamera = "--camera";
        public const string FlagOut = "--hwtest-out";
        public const string FlagWithChart = "--with-chart";
        public const string FlagKeep = "--hwtest-keep";

        /// <summary>検査するカメラの機種</summary>
        public HwTestCameraKind Camera { get; private set; }

        /// <summary>結果ファイルの出力先（省略時は null．呼び出し側が既定のパスを決める）</summary>
        public string OutPath { get; private set; }

        /// <summary>チャートが必要な検査（calibrate・shot・close-saving・close-calibrating．PLAN_06 フェーズ 2）を行うか．指定するとチャート不要の検査は行わない（connect・cleanup は共通）</summary>
        public bool WithChart { get; private set; }

        /// <summary>合格時も作業フォルダ（一時設定・保存物）を削除しないか</summary>
        public bool Keep { get; private set; }

        /// <summary>実機テストが要求されているか（--hwtest があるか）</summary>
        public static bool IsRequested(string[] args) {
            if (args == null) return false;
            foreach (var a in args) {
                if (Is(a, FlagHwTest)) return true;
            }
            return false;
        }

        /// <summary>
        /// 引数を解析する．先頭要素が実行ファイルのパス（Environment.GetCommandLineArgs の形）でもよい．
        /// 知らないフラグ（"--" 始まり）・値の欠落・--camera の指定漏れや不正値は誤りとする（打ち間違いで別の検査が走らないため）．
        /// </summary>
        /// <param name="args">コマンドライン引数</param>
        /// <param name="error">誤りがあればその理由（日本語），無ければ null</param>
        /// <returns>解析結果．誤りがあれば null</returns>
        public static HwTestOptions Parse(string[] args, out string error) {
            error = null;
            if (args == null) {
                error = "引数がありません";
                return null;
            }
            var options = new HwTestOptions();
            string camera = null;
            for (var i = 0; i < args.Length; i++) {
                var a = args[i];
                if (a == null || !a.StartsWith("--", StringComparison.Ordinal)) {
                    // 実行ファイルのパス（先頭）以外の値は，直前のフラグの値として読み終えているはず
                    if (i == 0) continue;
                    error = $"不明な引数です: {a}";
                    return null;
                }
                if (Is(a, FlagHwTest)) continue;
                if (Is(a, FlagWithChart)) { options.WithChart = true; continue; }
                if (Is(a, FlagKeep)) { options.Keep = true; continue; }
                if (Is(a, FlagCamera) || Is(a, FlagOut)) {
                    var value = i + 1 < args.Length ? args[i + 1] : null;
                    if (string.IsNullOrWhiteSpace(value) || value.StartsWith("--", StringComparison.Ordinal)) {
                        error = $"{a} の値がありません";
                        return null;
                    }
                    i++;
                    if (Is(a, FlagCamera)) {
                        if (camera != null) {
                            error = $"{FlagCamera} が複数回指定されています";
                            return null;
                        }
                        camera = value;
                    } else {
                        if (options.OutPath != null) {
                            error = $"{FlagOut} が複数回指定されています";
                            return null;
                        }
                        options.OutPath = value;
                    }
                    continue;
                }
                error = $"不明なフラグです: {a}";
                return null;
            }

            if (camera == null) {
                error = $"{FlagCamera} lucam または {FlagCamera} iscam を指定してください";
                return null;
            }
            HwTestCameraKind kind;
            if (!TryParseCamera(camera, out kind)) {
                error = $"{FlagCamera} の値が不正です: {camera}（lucam または iscam）";
                return null;
            }
            options.Camera = kind;
            return options;
        }

        /// <summary>機種名（lucam / iscam．大文字小文字は区別しない）を解析する</summary>
        public static bool TryParseCamera(string value, out HwTestCameraKind kind) {
            if (string.Equals(value, "lucam", StringComparison.OrdinalIgnoreCase)) {
                kind = HwTestCameraKind.Lucam;
                return true;
            }
            if (string.Equals(value, "iscam", StringComparison.OrdinalIgnoreCase)) {
                kind = HwTestCameraKind.IScam;
                return true;
            }
            kind = HwTestCameraKind.Lucam;
            return false;
        }

        private static bool Is(string arg, string flag) {
            return string.Equals(arg, flag, StringComparison.OrdinalIgnoreCase);
        }
    }
}
#endif
