using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using AForge.Video;
using AForge.Video.DirectShow;
using OpenCvSharp;
using OpenCvSharp.CPlusPlus;

namespace YSoft.Rqamfp.Camera
{
    public partial class CameraSettingsControl : Form
    {
        private static VideoCaptureDevice _video;
        private static Mat _image;
        private static int _actualFrame = 1;
        public CameraSettingsControl()
        {
            InitializeComponent();
        }

        private void OnLoad(object sender, EventArgs e)
        {
            GetAllCameras();
            selectedCamera.SelectedIndex = Camera.CameraIndex;
        }

        private void GetAllCameras()
        {
            var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            for (int i = 0; i < videoDevices.Count; i++)
            {
                selectedCamera.Items.Add(i + ". " + videoDevices[i].Name);
            }
        }

        private void SetVideo()
        {
            var capture = CvCapture.FromCamera(CaptureDevice.Any, selectedCamera.SelectedIndex);
            capture.Exposure = (double)exposure.Value;
            capture.Brightness = (double)brightness.Value;
            capture.AutoExposure = 0;
            Cv2.WaitKey(2000);
            var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            _video = new VideoCaptureDevice(videoDevices[selectedCamera.SelectedIndex].MonikerString);
            var camera = _video.VideoCapabilities.Select((Value, Index) => new { Value, Index })
                 .SingleOrDefault(o => o.Value.FrameSize.Height == 1080 && o.Value.FrameSize.Width == 1920);
            if (camera == null)
            {
                MessageBox.Show("Selected camera does not support full HD snapping, select another camera");
                return;
            }
            _video.VideoResolution = _video.VideoCapabilities[camera.Index];
            _video.SetCameraProperty(CameraControlProperty.Focus, (int)focus.Value, CameraControlFlags.Manual);
            capture.Dispose();
        }

        private void StartVideo()
        {
            _video.NewFrame += (VideoOnNewFrame);
            _video.Start();
            _video.WaitForStop();
            _video.NewFrame -= (VideoOnNewFrame);
            _video.Stop();
            _video = null;
            Cv2.ImShow("Image", _image);
        }

        private void VideoOnNewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            if (_actualFrame == 5)
            {
                using (Bitmap bitmap = (Bitmap) eventArgs.Frame.Clone()) {
                    using (MemoryStream m = new MemoryStream()) {
                        bitmap.Save(m, ImageFormat.Png);
                        _image = Mat.FromStream(m, LoadMode.GrayScale);
                        _video.SignalToStop();
                    }
                    _actualFrame = 1;
                }
            }
            else
                _actualFrame++;
        }

        private void EndOnClick(object sender, EventArgs e)
        {
            _image?.Dispose();
            Cv2.DestroyAllWindows();
            Close();
        }

        private void RefreshOnClick(object sender, EventArgs e)
        {
            if (selectedCamera.SelectedIndex == -1)
            {
                MessageBox.Show("Choose camera");
                return;
            }
            SetVideo();
            StartVideo();
        }
    }
}
