using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.IO;
using System.Collections.Generic;

using DirectShowLib;
using DatasteadDirectShow;


namespace DatasteadMultipurposeEncoder_CSharp_Demo
{
    public partial class MainForm : Form
    {
        [DllImport("ole32.dll")]
        static extern int CoInitialize(IntPtr pvReserved);

        public DatasteadDirectShowGraph_WithEventsMsg m_Graph = null;

        public MainForm()
        {
            InitializeComponent();
            CoInitialize((System.IntPtr)null);
            m_Graph = new DatasteadDirectShowGraph_WithEventsMsg();
            m_Graph.m_AddToLog = AddToLog;
            m_Graph.m_DisplayWindow = panel1;
        }

        private void AddToLog(string LogString)
        {
            tbLog.Text += Environment.NewLine + Environment.NewLine + LogString;
            tbLog.SelectionStart = tbLog.Text.Length;
            tbLog.ScrollToCaret();
        }

        private void AddToLog_(string LogString)
        {
            tbLog.Text += Environment.NewLine + LogString;
            tbLog.SelectionStart = tbLog.Text.Length;
            tbLog.ScrollToCaret();
        }

        IBaseFilter m_DatasteadMultipurposeEncoder;

        public bool OpenURL()
        {
            int hr = 0;

            string Step = "";

            try
            {
                // Get DirectShow interfaces
                m_Graph.GetStandardDirectShowInterfaces(this.Handle);


                Step = "create the Multipurpose Encoder instance";
                m_DatasteadMultipurposeEncoder = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(MultipurposeEncoder.CLSID_DatasteadMultipurposeDirectShowEncoder));


                hr = m_Graph.m_graphBuilder.AddFilter(m_DatasteadMultipurposeEncoder, "Datastead Multipurpose DirectShow Encoder");
                DsError.ThrowExceptionForHR(hr);

                MultipurposeEncoder.IDatasteadMultipurposeDirectShowEncoder MultipurposeDirectShowEncoderConfig = (MultipurposeEncoder.IDatasteadMultipurposeDirectShowEncoder)m_DatasteadMultipurposeEncoder;
                Step = "setting the Multipurpose Encoder command line";
                hr = MultipurposeDirectShowEncoderConfig.SetCommandLine(edtCommandLine.Text);
                DsError.ThrowExceptionForHR(hr);

                /* sample code to retrieve the command line from the filter
                IntPtr DefaultCommandLinePtr;
                hr = m_Graph.m_DatasteadMultipurposeEncoderConfig.GetCommandLine(out DefaultCommandLinePtr);
                DsError.ThrowExceptionForHR(hr);
                string DefaultCommandLine = Marshal.PtrToStringAuto(DefaultCommandLinePtr);
                Marshal.FreeCoTaskMem(DefaultCommandLinePtr);
                edtCommandLine.Text = DefaultCommandLine;
                 */

                if (comboBoxVideo.Items.Count > 0) {
                    Step = "creating the video device instance, add it and render it";
                    hr = RenderDeviceSelectedInComboBoxToMultipurposeEncoder(FilterCategory.VideoInputDevice, MediaType.Video, comboBoxVideo, chkPreviewRender.Checked);
                    DsError.ThrowExceptionForHR(hr);
                }

                if (comboBoxAudio.Items.Count > 0)
                {
                    Step = "creating the Audio device instance, add it and render it";
                    hr = RenderDeviceSelectedInComboBoxToMultipurposeEncoder(FilterCategory.AudioInputDevice, MediaType.Audio, comboBoxAudio, chkPreviewRender.Checked);
                    DsError.ThrowExceptionForHR(hr);
                }

                if (chkPreviewRender.Checked) {
                }

                // m_Graph.AddToROT();

                Step = "run the graph";
                hr = m_Graph.m_mediaControl.Run();
                DsError.ThrowExceptionForHR(hr);

            }
            catch
            {
                tbLog.Text = "failed to build the graph at step \"" + Step + "\" with return code: " + hr.ToString("x");
                m_Graph.CloseInterfaces();
                return false;
            }
            return true;
        }

        int RenderDeviceSelectedInComboBoxToMultipurposeEncoder(Guid FilterCategory, Guid mediaType, ComboBox ComboBox, bool PreviewAndRenderAudio)
        {
            int hr = -1;
            string SelectedDeviceName = ComboBox.Items[ComboBox.SelectedIndex].ToString();
            if (SelectedDeviceName != null)
            {
                IBaseFilter CaptureDeviceInstance = m_Graph.CreateCaptureDeviceInstanceFromName(FilterCategory, SelectedDeviceName);
                if (CaptureDeviceInstance != null)
                {
                    if (chkShowVideoDeviceDialog.Checked)
                    {
                        if (mediaType == MediaType.Video)
                        {
                            m_Graph.DisplayPropertyPages(this, CaptureDeviceInstance);
                        }
                    }
                    hr = m_Graph.m_graphBuilder.AddFilter(CaptureDeviceInstance, SelectedDeviceName);
                    if (hr == 0)
                    {
                        if (PreviewAndRenderAudio)
                        {
                            if (mediaType == MediaType.Video)
                            {
                                IBaseFilter pSmartTee = (IBaseFilter)new SmartTee();
                                hr = m_Graph.m_graphBuilder.AddFilter(pSmartTee, "Smart Tee");
                                if (hr == 0)
                                {
                                    hr = m_Graph.m_captureGraphBuilder.RenderStream(null, MediaType.Video, CaptureDeviceInstance, null, pSmartTee);
                                    if (hr == 0)
                                    {
                                        hr = m_Graph.m_captureGraphBuilder.RenderStream(null, MediaType.Video, pSmartTee, null, m_DatasteadMultipurposeEncoder);
                                        if (hr == 0)
                                        {
                                            IPin PreviewPin;
                                            if (m_Graph.m_captureGraphBuilder.FindPin(pSmartTee, PinDirection.Output, null, null, true, 0, out PreviewPin) == 0)
                                            {
                                                if (m_Graph.RenderVideoPin(PreviewPin))
                                                {
                                                }
                                            }
                                        }
                                    }
                                }

                            }
                            else if (mediaType == MediaType.Audio)
                            {
                                IBaseFilter PInfiniteTee = (IBaseFilter)new InfTee();
                                hr = m_Graph.m_graphBuilder.AddFilter(PInfiniteTee, "Infinite Tee");
                                if (hr == 0)
                                {
                                    hr = m_Graph.m_captureGraphBuilder.RenderStream(null, MediaType.Audio, CaptureDeviceInstance, PInfiniteTee, m_DatasteadMultipurposeEncoder);
                                    if (hr == 0)
                                    {
                                        IPin AudioPin;
                                        if (m_Graph.m_captureGraphBuilder.FindPin(PInfiniteTee, PinDirection.Output, null, MediaType.Audio, true, 0, out AudioPin) == 0)
                                        {
                                            if (m_Graph.RenderAudioPin(AudioPin))
                                            {
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            IPin CaptureDeviceOutputPin = null;
                            if (m_Graph.m_captureGraphBuilder.FindPin(CaptureDeviceInstance, PinDirection.Output, PinCategory.Capture, mediaType, true, 0, out CaptureDeviceOutputPin) == 0)
                            {
                                hr = m_Graph.m_graphBuilder.Render(CaptureDeviceOutputPin);
                                Marshal.ReleaseComObject(CaptureDeviceOutputPin);
                            }

                        }
                        Marshal.ReleaseComObject(CaptureDeviceInstance);
                    }
                }
            }
            return hr;
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case DatasteadHelper.WM_GRAPHNOTIFY:
                    {
                        m_Graph.HandleGraphEvent();
                        break;
                    }
            }

            // Pass this message to the video window for notification of system changes
            //if (m_Graph.m_videoWindow != null)
            {
            //    m_Graph.m_videoWindow.NotifyOwnerMessage(m.HWnd, m.Msg, m.WParam, m.LParam);
            }

            base.WndProc(ref m);
        }

        private void Form1_Resize(object sender, System.EventArgs e)
        {
            //m_Graph.ResizeVideoWindow();
        }

        /// <summary>
        /// Main app entry point
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }


        private void btnClose_Click(object sender, EventArgs e)
        {
            m_Graph.CloseInterfaces();
            AddToLog("closed.");

        }

        private void btnInfoLimitations_Click(object sender, EventArgs e)
        {
            const string info = "- if the video pin is connected in RGB32 or RGB24, a \"Datatead\" logo is overlayed\r\n- if the video pin is connected in another format, the video flashes periodically 1 time then 2 times";
            MessageBox.Show(info);

        }

        private void btnOpenSync_Click(object sender, EventArgs e)
        {
            m_Graph.CloseInterfaces();
            OpenURL();
            // starting from here the filter connects asynchrously, 
            // then when the connection completes the filter sends
            // an EC_RTSP_NOTIFY event to the graph event handler (HandleGraphEvent) 
            // that invokes CompleteGraph()
            // >>>>> SEE HandleGraphEvent() and CompleteGraph() <<<<<
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            m_Graph.CloseInterfaces();
        }

        private void btnBufferInfo_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Specify explicitely 0 to disable the default buffering. If the video freezes periodically, increase the value, e.g. between 200 and 1000 ms, or disable the video sync if not required");
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            m_Graph.GetDevicesNames(FilterCategory.VideoInputDevice, comboBoxVideo);
            m_Graph.GetDevicesNames(FilterCategory.AudioInputDevice, comboBoxAudio);
        }

        private void btnClose_Click_1(object sender, EventArgs e)
        {
            m_Graph.CloseInterfaces();
        }
    }
}    

