using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace ISCamRecorder {
    public partial class Setting : Form {

        readonly string SUBJECT_LIST_FILE = @"SubjectList.txt";
        public enum ACTION { movie, image}
        public string SaveDir { get; private set; }
        public string ImageType { get; private set; }   // 静止画保存 フォーム表示は大文字，変数は小文字で記録
        public string FrameType { get; private set; }   // フォーム表示は大文字，変数は小文字で記録
        public int MovieRate { get; private set; }
        public float RecodingLimit { get; private set; }
        public bool SWTrigger { get; private set; }
        public float SWTriggerFPS { get; private set; }
        public ACTION ButtonAction { get; private set; }
        public bool[] RecCameras { get; private set; }
        public bool[] SnapCameras { get; private set; }
        public List<string> Subjects { get; private set; }
        public int RBThreshold { get; private set; }    // 逆血検出信号変化閾値
        public int RBDetectSize { get; private set; }   // 直近信号検出ウインドウサイズ
        public int RBDetectCount { get; private set; }  // 直近信号検出数
        public string RBDetectCh { get; private set; }
        public bool SensorColorBG { get; private set; } // センサ色をグラフ背景に反映するかどうか

        public float[] ConsumedMemoryPerSecond { get; set; }


        /// <summary>
        /// コンストラクタ
        /// </summary>
        public Setting() {
            InitializeComponent();
            ConsumedMemoryPerSecond = new float[5];
            ImageType = "tif";
            FrameType = "jpg";
            SWTrigger = false;
            SWTriggerFPS = 40F;
            ButtonAction = ACTION.movie;
            SnapCameras = new bool[] { true, true, true, true, false };
            RBThreshold = 100;
            RBDetectSize = 10;
            RBDetectCount = 5;
            RBDetectCh = "Sat";
            SensorColorBG = true;
#if DEBUG
            SaveDir = @"D:\DataDBG";
            RecodingLimit = 10F;
            MovieRate = 1000;
            RecCameras = new bool[] { true, false, false, false, false };
#else
            SaveDir = @"D:\Data";
            RecodingLimit = 30F;
            MovieRate = 5000;
            RecCameras = new bool[] { true, true, true, true, true };
#endif
            if (File.Exists(SUBJECT_LIST_FILE)) {
                using (StreamReader sr = new StreamReader(SUBJECT_LIST_FILE)) {
                    var text = sr.ReadToEnd();
                    Subjects = text.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
                }
            }
        }

        /// <summary>
        /// ダイアログ表示時
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Setting_Shown(object sender, EventArgs e) {
            TxtOutputDir.Text = SaveDir;
            CboImageType.SelectedItem = ImageType.ToUpper();
            CboFrameType.SelectedItem = FrameType.ToUpper();
            TxtMovieRate.Text = MovieRate.ToString();
            TxtRecodingDulation.Text = RecodingLimit.ToString("0.0");
            ChkTrigger.Checked = SWTrigger;
            TxtTriggerFPS.Text = SWTriggerFPS.ToString("0.0");
            RadSwitchMovie.Checked = ButtonAction == ACTION.movie;
            RadSwitchImage.Checked = ButtonAction == ACTION.image;
            ChkRecTop.Checked = RecCameras[0];
            ChkRecLeft.Checked = RecCameras[1];
            ChkRecFront.Checked = RecCameras[2];
            ChkRecRight.Checked = RecCameras[3];
            ChkRecNear.Checked = RecCameras[4];
            ChkSnapTop.Checked = SnapCameras[0];
            ChkSnapLeft.Checked = SnapCameras[1];
            ChkSnapFront.Checked = SnapCameras[2];
            ChkSnapRight.Checked = SnapCameras[3];
            ChkSnapNear.Checked = SnapCameras[4];
            TxtSubjectList.Lines = Subjects.ToArray();
            TxtRBThreshold.Text = RBThreshold.ToString();
            TxtRBDetectSize.Text = RBDetectSize.ToString();
            TxtRBDetectCount.Text = RBDetectCount.ToString();
            CboRBDetectCh.SelectedItem = RBDetectCh;
            ChkSensorColorBG.Checked = SensorColorBG;
            this.UpdateMemoryInfo();
        }

        /// <summary>
        /// 適用時
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnApply_Click(object sender, EventArgs e) {
            // 検証
            var reccams = new bool[] { ChkRecTop.Checked, ChkRecLeft.Checked, ChkRecFront.Checked, ChkRecRight.Checked };
            if (reccams.All(s => !s)) {
                MessageBox.Show("録画カメラは上・左・前・右から最低１つ選択してください");
                return;
            }

            // 保存
            SaveDir = TxtOutputDir.Text;
            ImageType = CboImageType.Text.ToLower();
            FrameType = CboFrameType.Text.ToLower();
            MovieRate = int.Parse(TxtMovieRate.Text);
            RecodingLimit = float.Parse(TxtRecodingDulation.Text);
            SWTrigger = ChkTrigger.Checked;
            SWTriggerFPS = float.Parse(TxtTriggerFPS.Text);
            ButtonAction = RadSwitchMovie.Checked ? ACTION.movie : ACTION.image;
            RecCameras[0] = ChkRecTop.Checked;
            RecCameras[1] = ChkRecLeft.Checked;
            RecCameras[2] = ChkRecFront.Checked;
            RecCameras[3] = ChkRecRight.Checked;
            RecCameras[4] = ChkRecNear.Checked;
            SnapCameras[0] = ChkSnapTop.Checked;
            SnapCameras[1] = ChkSnapLeft.Checked;
            SnapCameras[2] = ChkSnapFront.Checked;
            SnapCameras[3] = ChkSnapRight.Checked;
            SnapCameras[4] = ChkSnapNear.Checked;
            Subjects = TxtSubjectList.Lines.Where(s => s.Trim().Length > 0).Select(s => s.Trim()).ToList();
            RBThreshold = int.Parse(TxtRBThreshold.Text);
            RBDetectSize = int.Parse(TxtRBDetectSize.Text);
            RBDetectCount = int.Parse(TxtRBDetectCount.Text);
            RBDetectCh = CboRBDetectCh.Text;
            SensorColorBG = ChkSensorColorBG.Checked;
            this.Close();
        }

        /// <summary>
        /// キャンセル時
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnCancel_Click(object sender, EventArgs e) {
            this.Close();
        }

        /// <summary>
        /// 次の非測定者名を返す
        /// </summary>
        /// <param name="current"></param>
        /// <returns></returns>
        public string Next(string current) {
            if (Subjects.Count < 1) return current;
            var idx = Subjects.FindIndex(s => s.Equals(current)) + 1;
            if (idx >= Subjects.Count - 1) idx = Subjects.Count - 1;
            return Subjects[idx];
        }

        /// <summary>
        /// 前の測定者名を返す
        /// </summary>
        /// <param name="current"></param>
        /// <returns></returns>
        public string Previous(string current) {
            if (Subjects.Count < 1) return current;
            var idx = Subjects.FindIndex(s => s.Equals(current)) - 1;
            if (idx < 0) idx = 0;
            return Subjects[idx];
        }

        /// <summary>
        /// テキストボックスで数値入力に限定する
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void NumberKeyOnly(object sender, KeyPressEventArgs e) {
            //バックスペースが押された時は有効（Deleteキーも有効）
            if (e.KeyChar == '\b' || e.KeyChar == '.') {
                return;
            }

            //数値0～9以外が押された時はイベントをキャンセルする
            if ((e.KeyChar < '0' || '9' < e.KeyChar)) {
                e.Handled = true;
            }
        }

        /// <summary>
        /// メモリー情報の更新
        /// </summary>
        private void UpdateMemoryInfo() {
            var info = new Microsoft.VisualBasic.Devices.ComputerInfo();
            ulong bcs = 1024 * 1024;
            var availableMemory = (int)(info.AvailablePhysicalMemory / bcs); //利用可能な物理メモリ
            LblAvailableMemory.Text = $"利用可能メモリー:{availableMemory.ToString("#,0").PadLeft(7)}MB";

            var totalConsumedMemoryPerSec = 0F;
            var useCameras = new bool[] {ChkRecTop.Checked, ChkRecLeft.Checked, ChkRecFront.Checked,
                ChkRecRight.Checked, ChkRecNear.Checked};
            for (int i = 0; i < useCameras.Length; i++) {
                totalConsumedMemoryPerSec += useCameras[i] ? ConsumedMemoryPerSecond[i] : 0;
            }
            var totalConsumedMemory = (int)(totalConsumedMemoryPerSec * float.Parse(TxtRecodingDulation.Text));
            LblRecodingMemory.Text = $"最大消費メモリー:{totalConsumedMemory.ToString("#,0").PadLeft(7)}MB";
            if (totalConsumedMemory > availableMemory) LblRecodingMemory.ForeColor = Color.Red;
            else LblRecodingMemory.ForeColor = Color.Black;
        }

        /// <summary>
        /// ソフトウェアトリガー設定変更時
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ChkTrigger_CheckedChanged(object sender, EventArgs e) {
            TxtTriggerFPS.Enabled = ChkTrigger.Checked;
        }

        /// <summary>
        /// 映像録画条件変更時
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RecodingParamChanged(object sender, EventArgs e) {
            this.UpdateMemoryInfo();
        }
    }
}
