using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using NZSDK_CSharpSample.Properties;
using System.Runtime.InteropServices;
using System.IO;

namespace NZSDK_CSharpSample
{
    public partial class PageNZSdkPlayback : UserControl
    {
        #region Constraints

        protected enum ExportKind : int
        {
            Video = 0,
            Image
        }

        #endregion

        #region Fields

        NZSDK sdk;
        Thread streamDispatcher;
        bool exitStreamDispatcher = false;
        object objDispatcher = new object();
        uint videoWidth;
        uint videoHeight;
        NZSDK.CodecKinds videoCodec;
        DateTime playTime;
        NZSDK.ExportMessageHandler exportHandler;

        #endregion

        #region Constructors

        public PageNZSdkPlayback()
        {
            InitializeComponent();
        }

        #endregion

        #region Properties

        public NZSDK SDK
        {
            get { return sdk; }
            set
            {
                sdk = value;
                if (sdk == null)
                    return;
                txtDeviceID.Text = Settings.Default.NZSDK_NvrPlaybackLastDeviceId;
                txtNrsID.Text = Settings.Default.NZSDK_NvrPlaybackLastNrsId;
            }
        }

        protected int DeviceID
        {
            get
            {
                return Int32.Parse(txtDeviceID.Text);
            }
        }

        protected int NrsID
        {
            get
            {
                return Int32.Parse(txtNrsID.Text);
            }
        }

        protected int PlaybackSpeed
        {
            get
            {
                return Int32.Parse(txtPlaybackSpeed.Text);
            }
        }

        protected bool PlaybackRefresh
        {
            get
            {
                return chkPlaybackRefresh.Checked;
            }
        }

        protected DateTime PlaybackTime
        {
            get
            {
                return dtpPlaybackTime.Value;
            }
            set
            {
                dtpPlaybackTime.Value = value;
            }
        }

        protected ExportKind SelectedExportKind
        {
            get
            {
                GenericItem item = cboExportKind.SelectedItem as GenericItem;
                return (ExportKind)item.ItemValue;
            }
        }

        #endregion

        #region Private / Protected Methods

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            dtpPlaybackTime.Value = DateTime.Now - TimeSpan.FromMinutes(10);

            cboExportKind.Items.Add(new GenericItem("Video", ExportKind.Video));
            cboExportKind.Items.Add(new GenericItem("Image", ExportKind.Image));
            cboExportKind.SelectedIndex = 0;

            txtExportPath.Text = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

            dtpStartDateTime.Value = DateTime.Now - TimeSpan.FromHours(1);
            dtpEndDateTime.Value = dtpStartDateTime.Value + TimeSpan.FromMinutes(10);

            tabControl1.Enabled = false;
        }

        private void OnStreamHandler(object obj)
        {
            IntPtr ptrStream = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NZSDK.Stream)));

            while (!exitStreamDispatcher)
            {
                bool dispatched = sdk.GetStream(NZSDK.SessionTypes.Playback, (int)obj, ptrStream);

                if (dispatched)
                {
                    NZSDK.Stream stream = (NZSDK.Stream)Marshal.PtrToStructure(ptrStream, typeof(NZSDK.Stream));
                    switch (stream.Type)
                    {
                        case NZSDK.StreamTypes.Video:
                            if (stream.Data.Video.Codec == NZSDK.CodecKinds.YUV420P)
                            {
                                if ((playTime.Year != stream.SystemTime.Year) ||
                                    (playTime.Month != stream.SystemTime.Month) ||
                                    (playTime.Day != stream.SystemTime.Day) ||
                                    (playTime.Hour != stream.SystemTime.Hour) ||
                                    (playTime.Minute != stream.SystemTime.Minute) ||
                                    (playTime.Second != stream.SystemTime.Second))
                                {
                                    playTime = new DateTime(stream.SystemTime.Year,
                                        stream.SystemTime.Month,
                                        stream.SystemTime.Day,
                                        stream.SystemTime.Hour,
                                        stream.SystemTime.Minute,
                                        stream.SystemTime.Second,
                                        stream.SystemTime.Milliseconds);
                                    UpdatePlayTime();
                                }
                                break;
                            }

                            if ((videoWidth != stream.Data.Video.Width) ||
                                (videoHeight != stream.Data.Video.Height) ||
                                (videoCodec != stream.Data.Video.Codec))
                            {
                                videoWidth = stream.Data.Video.Width;
                                videoHeight = stream.Data.Video.Height;
                                videoCodec = stream.Data.Video.Codec;
                                lock (objDispatcher)
                                {
                                    UpdateStreamStatus();
                                }
                            }
                            break;
                        case NZSDK.StreamTypes.Audio:
                            break;
                    }
                    sdk.ReleaseStream(ptrStream);
                }
                else
                    Thread.Sleep(0);
            }

            Marshal.FreeHGlobal(ptrStream);
        }

        private void UpdateStreamStatus()
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(delegate() { UpdateStreamStatus(); }));
                return;
            }

            string status = String.Format("Resolution : {0} x {1}, Codec : {2}", videoWidth, videoHeight, videoCodec);
            txtStreamStatus.Text = status;
        }

        private void UpdatePlayTime()
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(delegate() { UpdatePlayTime(); }));
                return;
            }

            dtpPlaybackTime.Value = playTime;
        }

        private void OnExportMessages(NZSDK.ExportMessages message, IntPtr param1, IntPtr param2, IntPtr userParam)
        {
            switch (message)
            {
                case NZSDK.ExportMessages.Started:
                    break;
                case NZSDK.ExportMessages.Updated:
                    OnExportUpdated(param1.ToInt32());
                    break;
                case NZSDK.ExportMessages.Finished:
                    {
                        switch (param2.ToInt32())
                        {
                            case 0:
                                OnExportSucceed();
                                break;
                            case 1:
                                OnExportFailed();
                                break;
                            case 2:
                                OnExportCanceled();
                                break;
                        }
                    }
                    break;
            }
        }

        private void OnExportUpdated(int percent)
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(delegate() { OnExportUpdated(percent); }));
                return;
            }

            progressBar1.Value = percent;
        }

        private void OnExportSucceed()
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(delegate() { OnExportSucceed(); }));
                return;
            }

            if (SelectedExportKind == ExportKind.Video)
            {
                butExportStart.Enabled = true;
                progressBar1.Value = 100;
            }
        }

        private void OnExportFailed()
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(delegate() { OnExportFailed(); }));
                return;
            }

            if (SelectedExportKind == ExportKind.Video)
            {
                butExportStart.Enabled = true;
            }
        }

        private void OnExportCanceled()
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(delegate() { OnExportCanceled(); }));
                return;
            }

            if (SelectedExportKind == ExportKind.Video)
            {
                butExportStart.Enabled = true;
            }
        }

        #endregion

        #region Public Methods

        public void Close()
        {
            lock (objDispatcher)
            {
                sdk.ClosePlaybackVideo(DeviceID);

                if (streamDispatcher != null)
                {
                    exitStreamDispatcher = true;
                    if (!streamDispatcher.Join(5000))
                        streamDispatcher.Abort();
                    streamDispatcher = null;
                }
            }
        }

        #endregion

        #region Event Handlers

        private void butOpen_Click(object sender, EventArgs e)
        {
            streamDispatcher = new Thread(new ParameterizedThreadStart(OnStreamHandler));
            exitStreamDispatcher = false;
            streamDispatcher.Start(NrsID);

            if (!sdk.OpenPlaybackVideo(DeviceID, pictureBox1.Handle))
            {
                exitStreamDispatcher = true;
                if (!streamDispatcher.Join(5000))
                    streamDispatcher.Abort();
                streamDispatcher = null;
                return;
            }

            Settings.Default.NZSDK_NvrPlaybackLastDeviceId = txtDeviceID.Text;
            Settings.Default.NZSDK_NvrPlaybackLastNrsId = txtNrsID.Text;
            Settings.Default.Save();

            butOpen.Enabled = false;
            tabControl1.Enabled = true;
        }

        private void butClose_Click(object sender, EventArgs e)
        {
            Close();
            butOpen.Enabled = true;
            tabControl1.Enabled = false;
        }

        private void pictureBox1_SizeChanged(object sender, EventArgs e)
        {
            if (sdk == null)
                return;
        }

        private void rdoBackward_CheckedChanged(object sender, EventArgs e)
        {
            if (!rdoBackward.Checked)
                return;
            sdk.PlaybackPlayBackward(DeviceID, PlaybackTime, PlaybackSpeed, PlaybackRefresh);
            dtpPlaybackTime.Enabled = false;
        }

        private void rdoForward_CheckedChanged(object sender, EventArgs e)
        {
            if (!rdoForward.Checked)
                return;
            sdk.PlaybackPlayForward(DeviceID, PlaybackTime, PlaybackSpeed, PlaybackRefresh);
            dtpPlaybackTime.Enabled = false;
        }

        private void butPause_Click(object sender, EventArgs e)
        {
            sdk.PlaybackPause(DeviceID);
            rdoBackward.Checked = false;
            rdoForward.Checked = false;
            dtpPlaybackTime.Enabled = true;
        }

        private void cboExportKind_SelectedIndexChanged(object sender, EventArgs e)
        {
            GenericItem item = cboExportKind.SelectedItem as GenericItem;
            switch ((ExportKind)item.ItemValue)
            {
                case ExportKind.Video:
                    {
                        lblEndDateTime.Enabled = true;
                        dtpEndDateTime.Enabled = true;

                        cboFormat.Items.Clear();
                        cboFormat.Items.Add(new GenericItem("AVI", NZSDK.ExportVideoFormat.Avi));
                        cboFormat.Items.Add(new GenericItem("EXE", NZSDK.ExportVideoFormat.Exe));
                        cboFormat.SelectedIndex = 0;

                        butExportStop.Enabled = true;
                    }
                    break;
                case ExportKind.Image:
                    {
                        lblEndDateTime.Enabled = false;
                        dtpEndDateTime.Enabled = false;

                        cboFormat.Items.Clear();
                        cboFormat.Items.Add(new GenericItem("Bitmap", NZSDK.ExportImageFormat.Bmp));
                        cboFormat.Items.Add(new GenericItem("Png", NZSDK.ExportImageFormat.Png));
                        cboFormat.Items.Add(new GenericItem("Jpeg", NZSDK.ExportImageFormat.Jpg));
                        cboFormat.Items.Add(new GenericItem("Tiff", NZSDK.ExportImageFormat.Tif));
                        cboFormat.SelectedIndex = 0;

                        butExportStop.Enabled = false;
                    }
                    break;
            }
        }

        private void butExportBrowse_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() != DialogResult.OK)
                return;

            txtExportPath.Text = folderBrowserDialog1.SelectedPath;
        }

        private void butExportStart_Click(object sender, EventArgs e)
        {
            if (dtpStartDateTime.Value >= dtpEndDateTime.Value)
                return;

            progressBar1.Value = 0;

            if (SelectedExportKind == ExportKind.Video)
            {
                exportHandler = new NZSDK.ExportMessageHandler(OnExportMessages);
                GenericItem format = cboFormat.SelectedItem as GenericItem;
                bool result = sdk.StartExportVideo(DeviceID,
                    (NZSDK.ExportVideoFormat)format.ItemValue,
                    dtpStartDateTime.Value,
                    dtpEndDateTime.Value,
                    txtExportPath.Text,
                    Marshal.GetFunctionPointerForDelegate(exportHandler),
                    IntPtr.Zero);
                if (!result)
                    return;
                butExportStart.Enabled = false;
            }
            else
            {
                exportHandler = new NZSDK.ExportMessageHandler(OnExportMessages);
                GenericItem format = cboFormat.SelectedItem as GenericItem;
                bool result = sdk.ExportImage(DeviceID,
                    (NZSDK.ExportImageFormat)format.ItemValue,
                    dtpStartDateTime.Value,
                    dtpEndDateTime.Value,
                    txtExportPath.Text,
                    Marshal.GetFunctionPointerForDelegate(exportHandler),
                    IntPtr.Zero);
            }
        }

        private void butExportStop_Click(object sender, EventArgs e)
        {
            sdk.StopExportVideo();
            if (SelectedExportKind == ExportKind.Video)
                butExportStart.Enabled = true;
        }

        #endregion
    }
}
