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 System.Runtime.InteropServices;
using NZSDK_CSharpSample.Properties;
using System.Reflection;
using System.IO;

namespace NZSDK_CSharpSample
{
    public partial class PageNZSdkLive : UserControl
    {
        #region Fields

        NZSDK sdk;
        Thread streamDispatcher;
        bool exitStreamDispatcher = false;
        object objDispatcher = new object();
        uint videoWidth;
        uint videoHeight;
        NZSDK.CodecKinds videoCodec;
        bool motionEventRaised;
        bool alarmEventRaised;

        #endregion

        #region Constructors

        public PageNZSdkLive()
        {
            InitializeComponent();
        }

        #endregion

        #region Properties

        public NZSDK SDK
        {
            get { return sdk; }
            set 
            { 
                sdk = value;
                if (sdk == null)
                    return;
                if (sdk.SDKKind == NZSDK.SDKKinds.NVR)
                {
                    lblDeviceID.Text = "Device ID : ";
                    txtDeviceID.Text = Settings.Default.NZSDK_NvrLiveLastDeviceId;
                    lblNrsID.Visible = true;
                    txtNrsID.Visible = true;
                    txtNrsID.Text = Settings.Default.NZSDK_NvrLiveLastNrsId;
                }
                else
                {
                    lblDeviceID.Text = "Channel : ";
                    txtDeviceID.Text = Settings.Default.NZSDK_NrsLiveLastDeviceId;
                    lblNrsID.Visible = false;
                    txtNrsID.Visible = false;
                }
            }
        }

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

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

        protected int StreamNumber
        {
            get
            {
                return chkHighStream.Checked ? 1 : 2;
            }
        }

        protected int PtzSpeed
        {
            get
            {
                return Int32.Parse(txtPtzSpeed.Text);
            }
        }

        protected int PresetNumber
        {
            get
            {
                return Int32.Parse(txtPreset.Text);
            }
        }

        #endregion

        #region Private / Protected Methods

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            openFileDialog1.InitialDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            openFileDialog1.FileName = string.Empty;
        }

        #endregion

        #region Public Methods

        public void Close()
        {
            lock (objDispatcher)
            {
                if (chkAudio.Checked)
                    sdk.CloseAudio(DeviceID, StreamNumber);
                if (chkEvent.Checked)
                    sdk.CloseEvent();
                sdk.CloseVideo(DeviceID, StreamNumber);

                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)
        {
            motionEventRaised = false;
            alarmEventRaised = false;

            streamDispatcher = new Thread(new ParameterizedThreadStart(OnStreamHandler));
            exitStreamDispatcher = false;
            streamDispatcher.Start(NrsID);

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

            sdk.ViewResize(DeviceID, StreamNumber);
            sdk.ViewShowSelection(DeviceID, StreamNumber, false);
            sdk.ViewShowName(DeviceID, StreamNumber, "테스트", 20);

            if (chkAudio.Checked)
                sdk.OpenAudio(DeviceID, StreamNumber, true);
            if (chkEvent.Checked)
                sdk.OpenEvent(DeviceID.ToString());

            if (sdk.SDKKind == NZSDK.SDKKinds.NVR)
            {
                Settings.Default.NZSDK_NvrLiveLastDeviceId = txtDeviceID.Text;
                Settings.Default.NZSDK_NvrLiveLastNrsId = txtNrsID.Text;
            }
            else
                Settings.Default.NZSDK_NrsLiveLastDeviceId = txtDeviceID.Text;

            Settings.Default.Save();

            butOpen.Enabled = false;
        }

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

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

            while (!exitStreamDispatcher)
            {
                bool dispatched = false;
                if (sdk.SDKKind == NZSDK.SDKKinds.NVR)
                    dispatched = sdk.GetStream(NZSDK.SessionTypes.Live, (int)obj, ptrStream);
                else
                    dispatched = sdk.GetStream(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)
                                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;
                        case NZSDK.StreamTypes.Event:
                            switch (stream.Data.Event.Event)
                            {
                                case NZSDK.EventTypes.Motion:
                                    if (motionEventRaised != stream.Data.Event.Triggered)
                                    {
                                        motionEventRaised = stream.Data.Event.Triggered;
                                        lock (objDispatcher)
                                        {
                                            UpdateStreamStatus();
                                        }
                                    }
                                    break;
                                case NZSDK.EventTypes.Alarm:
                                    if (alarmEventRaised != stream.Data.Event.Triggered)
                                    {
                                        alarmEventRaised = stream.Data.Event.Triggered;
                                        lock (objDispatcher)
                                        {
                                            UpdateStreamStatus();
                                        }
                                    }
                                    break;
                            }
                            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);
            string events = string.Empty;
            if (motionEventRaised)
                events += "Motion";
            if (alarmEventRaised)
            {
                if (!String.IsNullOrEmpty(events))
                    events += "|";
                events += "Alarm";
            }

            if (!String.IsNullOrEmpty(events))
                status += String.Format(" , Events : {0}", events);
            txtStreamStatus.Text = status;
        }

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

        private void butPtzLU_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.LeftUp, DeviceID, PtzSpeed);
        }

        private void butPtzLU_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.LeftUp, DeviceID, 0);
        }

        private void butPtzU_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.Up, DeviceID, PtzSpeed);
        }

        private void butPtzU_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.Up, DeviceID, 0);
        }

        private void butPtzRU_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.RightUp, DeviceID, PtzSpeed);
        }

        private void butPtzRU_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.RightUp, DeviceID, 0);
        }

        private void butPtzL_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.Left, DeviceID, PtzSpeed);
        }

        private void butPtzL_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.Left, DeviceID, 0);
        }

        private void butPtzR_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.Right, DeviceID, PtzSpeed);
        }

        private void butPtzR_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.Right, DeviceID, 0);
        }

        private void butPtzLD_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.LeftDown, DeviceID, PtzSpeed);
        }

        private void butPtzLD_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.LeftDown, DeviceID, 0);
        }

        private void butPtzD_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.Down, DeviceID, PtzSpeed);
        }

        private void butPtzD_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.Down, DeviceID, 0);
        }

        private void butPtzRD_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.RightDown, DeviceID, PtzSpeed);
        }

        private void butPtzRD_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.PanTiltControl(NZSDK.PtzDirection.RightDown, DeviceID, 0);
        }

        private void butTele_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.ZoomControl(NZSDK.ZoomMethod.Tele, DeviceID, PtzSpeed);
        }

        private void butTele_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.ZoomControl(NZSDK.ZoomMethod.Tele, DeviceID, 0);
        }

        private void butWide_MouseDown(object sender, MouseEventArgs e)
        {
            sdk.ZoomControl(NZSDK.ZoomMethod.Wide, DeviceID, PtzSpeed);
        }

        private void butWide_MouseUp(object sender, MouseEventArgs e)
        {
            sdk.ZoomControl(NZSDK.ZoomMethod.Wide, DeviceID, 0);
        }

        private void butPresetSet_Click(object sender, EventArgs e)
        {
            sdk.SetPtzPreset(DeviceID, PresetNumber);
        }

        private void butPresetMove_Click(object sender, EventArgs e)
        {
            sdk.MovePtzPreset(DeviceID, PresetNumber);
        }

        private void butTourStart_Click(object sender, EventArgs e)
        {
            sdk.StartPresetTour(DeviceID);
        }

        private void butTourStop_Click(object sender, EventArgs e)
        {
            sdk.StopPresetTour(DeviceID);
        }

        private void butPositionSpec_Click(object sender, EventArgs e)
        {
            NZSDK.PtzPositionSpecification spec = sdk.GetPtzPositionSpecification(DeviceID);
            txtPositionSpec.Text = String.Format("SupportPanTilt={0}, SupportZoom={1}, Pan={2}~{3}, Tilt={4}~{5}, Zoom={6}~{7}",
                spec.SupportPanTiltPosition,
                spec.SupportZoomPosition,
                spec.MinPanPosition,
                spec.MaxPanPosition,
                spec.MinTiltPosition,
                spec.MaxTiltPosition,
                spec.MinZoomPosition,
                spec.MaxZoomPosition);
        }

        private void butGetPosition_Click(object sender, EventArgs e)
        {
            NZSDK.PtzPosition position = sdk.GetPtzPosition(DeviceID);
            txtPositionPanR.Text = position.PanPosition.ToString();
            txtPositionTiltR.Text = position.TiltPosition.ToString();
            txtPositionZoomR.Text = position.ZoomPosition.ToString();
        }

        private void butSetPosition_Click(object sender, EventArgs e)
        {
            NZSDK.PtzPosition position = new NZSDK.PtzPosition();
            position.PanPosition = Convert.ToDouble(txtPositionPanW.Text);
            position.TiltPosition = Convert.ToDouble(txtPositionTiltW.Text);
            position.ZoomPosition = Convert.ToDouble(txtPositionZoomW.Text);
            sdk.SetPtzPosition(DeviceID, position);
        }

        private void butTalkStart_Click(object sender, EventArgs e)
        {
            if (!sdk.StartTalk(DeviceID, StreamNumber))
                return;
            butTalkStart.Enabled = false;
            butPlayWaveStart.Enabled = false;
            butPlayWaveStop.Enabled = false;
        }

        private void butTalkStop_Click(object sender, EventArgs e)
        {
            sdk.StopTalk(DeviceID, StreamNumber);
            butTalkStart.Enabled = true;
            butPlayWaveStart.Enabled = true;
            butPlayWaveStop.Enabled = true;
        }

        private void butAudioFileBrowse_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog(this) != DialogResult.OK)
                return;
            txtAudioFile.Text = openFileDialog1.FileName;
        }

        private void butPlayWaveStart_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(txtAudioFile.Text) || !File.Exists(txtAudioFile.Text))
                return;
            sdk.StartSendWave(DeviceID, StreamNumber, txtAudioFile.Text);
            butPlayWaveStart.Enabled = false;
            butTalkStart.Enabled = false;
            butTalkStop.Enabled = false;
        }

        private void butPlayWaveStop_Click(object sender, EventArgs e)
        {
            sdk.StopSendWave(DeviceID, StreamNumber);
            butPlayWaveStart.Enabled = true;
            butTalkStart.Enabled = true;
            butTalkStop.Enabled = true;
        }

        #endregion
    }
}
