#if HWTEST
using System;
using Lumenera.USB;

namespace TIASshot {

    /// <summary>
    /// Lucam の実機テスト用の口（HWTEST 限定）．SDK を呼ぶだけの薄い処理に留める．
    /// 露光（ms）・ゲイン（倍率）は LucamGetProperty / LucamSetProperty の float の実数値そのもの（整数への丸めは無い）で読み書きするため，
    /// 最初に読んだ値をそのまま書き戻せば元の値に戻る（HwTestRunner.RestoreSettings が IScam と同じく相対誤差 1% で読み戻しを確かめる）．
    /// </summary>
    internal partial class Lucam : IHwTestAdjustable {

        /// <summary>接続されている Lumenera カメラの台数（SDK が無い・列挙に失敗した場合は例外）</summary>
        internal static int HwTestCountCameras() {
            return dll.LucamNumCameras();
        }

        public string HwTestExposureUnit => "ms（LucamProperty.EXPOSURE）";

        /// <summary>Lucam の露光（LucamProperty.EXPOSURE）は ms 単位の線形の量（検査では ×0.5 / ×2 で 1 段動かす）</summary>
        public HwTestValueScale HwTestExposureScale => HwTestValueScale.Linear;

        public string HwTestGainUnit => "倍率（LucamProperty.GAIN）";

        public HwTestSetting HwTestGetExposure() {
            return GetSetting(dll.LucamProperty.EXPOSURE);
        }

        public void HwTestSetExposure(double value) {
            var range = GetSetting(dll.LucamProperty.EXPOSURE);
            var v = (float)HwTestJudge.Clamp(value, range.Min, range.Max);
            // 以降の SetCameraParam（校正中のホワイトバランス反映）で元に戻されないよう，保持値も更新する
            _snap.Exposure = v;
            SetProperty(dll.LucamProperty.EXPOSURE, v);
        }

        public HwTestSetting HwTestGetGain() {
            return GetSetting(dll.LucamProperty.GAIN);
        }

        public void HwTestSetGain(double value) {
            var range = GetSetting(dll.LucamProperty.GAIN);
            var v = (float)HwTestJudge.Clamp(value, range.Min, range.Max);
            _snap.Gain = v;
            SetProperty(dll.LucamProperty.GAIN, v);
        }

        private HwTestSetting GetSetting(dll.LucamProperty property) {
            if (_hCam == IntPtr.Zero) throw new InvalidOperationException("Lucam が接続されていません");
            if (!dll.LucamGetProperty(_hCam, property, out float value, out dll.LucamPropertyFlag _)) {
                throw new InvalidOperationException($"LucamGetProperty({property}) に失敗しました（{dll.LucamGetLastErrorForCamera(_hCam)}）");
            }
            if (!dll.LucamPropertyRange(_hCam, property, out float min, out float max, out float _, out dll.LucamPropertyFlag _)) {
                throw new InvalidOperationException($"LucamPropertyRange({property}) に失敗しました（{dll.LucamGetLastErrorForCamera(_hCam)}）");
            }
            return new HwTestSetting(value, min, max);
        }

        private void SetProperty(dll.LucamProperty property, float value) {
            if (_hCam == IntPtr.Zero) throw new InvalidOperationException("Lucam が接続されていません");
            if (!dll.LucamSetProperty(_hCam, property, value, dll.LucamPropertyFlag.NONE)) {
                throw new InvalidOperationException($"LucamSetProperty({property}, {value}) に失敗しました（{dll.LucamGetLastErrorForCamera(_hCam)}）");
            }
        }
    }
}
#endif
