using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using NewTek;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using NewTek.NDI;

namespace VIZ.Framework.Common
{
    /// <summary>
    /// NDI流
    /// </summary>
    public partial class NDIStream : VideoStreamBase<NDIStreamOption>
    {
        /// <summary>
        /// NDI流
        /// </summary>
        /// <param name="localRecevierName">本地接收者名称</param>
        /// <param name="remoteSenderName">远程发送者名称</param>
        /// <param name="option">设置</param>
        public NDIStream(string localRecevierName, string remoteSenderName, NDIStreamOption option)
            : base(option)
        {
            this.LocalRecevierName = localRecevierName;
            this.RemoteSenderName = remoteSenderName;

            // 查找NDI流任务
            this.TaskDic.Add(NDIStreamTaskNames.FIND_STREAM, new NDIStreamFindStreamTask(this));
            // 接收视频帧任务
            this.TaskDic.Add(NDIStreamTaskNames.RECV_VIDEO, new NDIStreamRecvVideoTask(this));
            // 处理视频帧任务
            this.TaskDic.Add(NDIStreamTaskNames.EXECUTE_VIDEO, new NDIStreamExecuteVideoTask(this));
        }

        /* ========================================================================================================= */
        /* === Const === */
        /* ========================================================================================================= */

        /// <summary>
        /// the size of an NDIlib.source_t, for pointer offsets
        /// </summary>
        public readonly int SOURCE_SIZE_IN_BYTES = Marshal.SizeOf(typeof(NDIlib.source_t));

        /* ========================================================================================================= */
        /* === Property === */
        /* ========================================================================================================= */

        /// <summary>
        /// NDI流信息集合
        /// </summary>
        public List<NDIStreamInfo> StreamInfos { get; private set; } = new List<NDIStreamInfo>();

        /// <summary>
        /// 远程NDI发送者名称
        /// </summary>
        public string RemoteSenderName { get; private set; }

        /// <summary>
        /// 本地NDI接收者名称
        /// </summary>
        public string LocalRecevierName { get; private set; }

        /* ========================================================================================================= */
        /* === Internal Field === */
        /* ========================================================================================================= */

        /// <summary>
        /// 查找NDI流实例句柄
        /// </summary>
        internal IntPtr FindInstancePtr;

        /// <summary>
        /// 当前正在处理的NDI流源
        /// </summary>
        internal NDIlib.source_t? CurrentRemoteSenderSource;

        /// <summary>
        /// 接收NDI流实例句柄
        /// </summary>
        internal IntPtr RecvInstancePtr;

        /// <summary>
        /// 接收NDI流同步信息实例句柄
        /// </summary>
        internal IntPtr RecvSyncInstancePtr;

        /* ========================================================================================================= */
        /* === Field === */
        /* ========================================================================================================= */

        /// <summary>
        /// 任务池
        /// </summary>
        private Dictionary<NDIStreamTaskNames, NDIStreamTaskBase> TaskDic = new Dictionary<NDIStreamTaskNames, NDIStreamTaskBase>();

        /* ========================================================================================================= */
        /* === Function === */
        /* ========================================================================================================= */

        /// <summary>
        /// 开始
        /// </summary>
        public void Start()
        {
            NDIlib.find_create_t findCreateDesc = new NDIlib.find_create_t();
            findCreateDesc.p_groups = IntPtr.Zero;
            findCreateDesc.show_local_sources = true;
            findCreateDesc.p_extra_ips = IntPtr.Zero;

            // 创建NDI流查找实例句柄
            this.FindInstancePtr = NDIlib.find_create_v2(ref findCreateDesc);

            // 启动NDI流查找任务
            this.TaskDic[NDIStreamTaskNames.FIND_STREAM].Start();
            // 启动NDI视频帧接收任务
            this.TaskDic[NDIStreamTaskNames.RECV_VIDEO].Start();
            // 启动NDI视频帧处理任务
            this.TaskDic[NDIStreamTaskNames.EXECUTE_VIDEO].Start();
        }

        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            // 停止所有任务
            foreach (var task in this.TaskDic.Values)
            {
                task.Stop();
            }

            // 重置当前NDI流信息
            this.CurrentRemoteSenderSource = null;

            // 清理流信息
            lock (this.StreamInfos)
            {
                this.StreamInfos.Clear();
            }

            // 释放查找NDI流句柄
            if (this.FindInstancePtr != IntPtr.Zero)
            {
                NDIlib.find_destroy(this.FindInstancePtr);
                this.FindInstancePtr = IntPtr.Zero;
            }
            // 释放接收NDI流实例句柄
            if (this.RecvInstancePtr != IntPtr.Zero)
            {
                NDIlib.recv_destroy(this.RecvInstancePtr);
                this.RecvInstancePtr = IntPtr.Zero;
            }
            // 释放NDI流同步接收实例句柄
            if (this.RecvSyncInstancePtr != IntPtr.Zero)
            {
                NDIlib.framesync_destroy(this.RecvSyncInstancePtr);
                this.RecvSyncInstancePtr = IntPtr.Zero;
            }
        }

        /// <summary>
        /// 销毁
        /// </summary>
        public override void Dispose()
        {
            this.Stop();
        }

        /// <summary>
        /// 切换远程发送者名称
        /// </summary>
        /// <param name="remoteSenderName">远程发送者名称</param>
        /// <returns>是否成功切换</returns>
        public bool ChangeRemoteSenderName(string remoteSenderName)
        {
            // -------------------------------------------------------------------------------
            // 获取将要切换的NDI流信息

            // 获取要切换的NDI流信息
            NDIStreamInfo info = null;
            lock (this.StreamInfos)
            {
                info = this.StreamInfos.FirstOrDefault(p => p.FullName == remoteSenderName);
            }

            // -------------------------------------------------------------------------------
            // 释放

            // 释放接收NDI流实例句柄
            if (this.RecvInstancePtr != IntPtr.Zero)
            {
                NDIlib.recv_destroy(this.RecvInstancePtr);
                this.RecvInstancePtr = IntPtr.Zero;
            }
            // 释放NDI流同步接收实例句柄
            if (this.RecvSyncInstancePtr != IntPtr.Zero)
            {
                NDIlib.framesync_destroy(this.RecvSyncInstancePtr);
                this.RecvSyncInstancePtr = IntPtr.Zero;
            }

            // -------------------------------------------------------------------------------
            // 初始化

            // 设置NDI发送者名称
            this.RemoteSenderName = remoteSenderName;

            if (info == null)
            {
                this.CurrentRemoteSenderSource = null;
                return true;
            }

            // 设置当前NDI发送源
            this.CurrentRemoteSenderSource = info.Source;

            // 创建NDI接收实例句柄 & NDI同步接收实例对象
            NDIlib.recv_create_v3_t recvCreateDesc = new NDIlib.recv_create_v3_t();
            recvCreateDesc.source_to_connect_to = info.Source;
            recvCreateDesc.color_format = NDIlib.recv_color_format_e.recv_color_format_BGRX_BGRA;
            recvCreateDesc.bandwidth = NDIlib.recv_bandwidth_e.recv_bandwidth_highest;
            recvCreateDesc.allow_video_fields = false;
            recvCreateDesc.p_ndi_recv_name = UTF.StringToUtf8(this.LocalRecevierName);

            this.RecvInstancePtr = NDIlib.recv_create_v3(ref recvCreateDesc);
            this.RecvSyncInstancePtr = NDIlib.framesync_create(this.RecvInstancePtr);

            // -------------------------------------------------------------------------------
            // 切换成功

            return true;
        }
    }
}
