
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace AIRS
{
    /// <summary>
    /// 脚本执行类
    /// lbf 2020/05/20 14:18
    /// </summary>
    public abstract class ScriptExecutor
    {
        public DataReceivedEventHandler DataReceivedEvent;
        private ConcurrentQueue<DataReceivedEventArgs> concurrentQueue = new ConcurrentQueue<DataReceivedEventArgs>();
        /// <summary>
        /// 执行脚本的命令
        /// </summary>
        protected string ProcessName { get; set; }

        protected SynchronizationContext synchronizationContext = null;
        public event SendOrPostCallback ReceivedControlData;
        public ScriptExecutor(SynchronizationContext context,string ProcessName)
        {
            this.synchronizationContext = context;
            this.ProcessName = ProcessName;
            new Task(() => {
                DataReceivedEventArgs args;
                while (true)
                {
                    if (this.concurrentQueue.TryDequeue(out args))
                    {
                        // 为异步获取订阅事件
                        if (this.DataReceivedEvent != null)
                        {
                            this.DataReceivedEvent(this, args);
                        }
                    }
                    else
                    {
                        Task.Delay(10);
                    }
                }
            }).Start();

        }

        /// <summary>
        /// 根据脚本返回结果分类数据
        /// </summary>
        /// <param name="control">界面接收数据控件</param>
        /// <param name="e">异步返回数据</param>
        /// <returns>控件分类数据</returns>
        protected abstract ControlData produceControlData(Control control, DataReceivedEventArgs e);

        private void addDataReceivedEvent(Control control, string commandString)
        {
            if (DataReceivedEvent == null)
            {
                DataReceivedEvent += new DataReceivedEventHandler((sender1, e1) => {
                    if (!string.IsNullOrEmpty(e1.Data))
                    {
                        if (this.ReceivedControlData != null)
                        {
                            this.synchronizationContext.Post(this.ReceivedControlData, produceControlData(control,e1));
                        }
                    }
                });
            }

        }
        /// <summary>
        /// 执行脚本命令，结果会通过ReceivedControlData事件返回
        /// </summary>
        /// <param name="control">接收数据的控件</param>
        /// <param name="commandString">执行的脚本命令</param>
        public void execute(Control control, string commandString)
        {
            addDataReceivedEvent(control, commandString);
            if (this.ReceivedControlData != null)
            {
                this.synchronizationContext.Post(this.ReceivedControlData, new ControlData { Control = control, CallbackDataType = CallbackDataType.Command, DataString = commandString });
            }
            this.executeScript(commandString);
        }
        public void DataReceivedEventHandler(object sender, DataReceivedEventArgs e)
        {
            //push into queue
            this.concurrentQueue.Enqueue(e);
        }
        /// <summary>
        /// 执行脚本，脚本返回数据在OutputDataReceived数据中返回，调用都需要挂载OutputDataReceived事件接收返回数据
        /// </summary>
        /// <param name="processName">脚本进程名</param>
        /// <param name="commandString">要执行的脚本文件+参数</param>
        private void executeScript( string commandString)
        {

            ProcessStartInfo start = new ProcessStartInfo();
            start.FileName = this.ProcessName;
            start.Arguments = commandString;
            start.UseShellExecute = false;
            start.RedirectStandardOutput = true;
            start.RedirectStandardInput = true;
            start.RedirectStandardError = true;
            start.CreateNoWindow = true;

            using (Process p = Process.Start(start))
            {
                // 异步获取命令行内容
                p.BeginOutputReadLine();
                // 为异步获取订阅事件
                if (this.DataReceivedEvent != null)
                {
                    p.OutputDataReceived += DataReceivedEventHandler;
;
                }
                
            }
        }

    }
}