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

namespace SalamanderWnmp.Tool
{
    public class CodeHelper
    {
        /// <summary>
        /// 编程语言枚举
        /// </summary>
        public enum ProgramLan
        {
            JavaScript,
            PHP,
            Python,
            Go,
            CSharp
        }

        private const string CODE_TMP_FILENAME = "code";
        // 临时代码文件路径
        string codeTmpPath = "";
        // 开始执行代码前做的事
        private Action preWork;
        // 执行代码后做的事
        private Action<string> afterWork;

        private string code;
        private ProgramLan selectedLan;

        public CodeHelper SetPreWork(Action work)
        {
            this.preWork = work;
            return this;
        }

        public CodeHelper SetAfterWork(Action<string> work)
        {
            this.afterWork = work;
            return this;
        }


        /// <summary>
        /// 执行代码
        /// </summary>
        public void Run(string code, ProgramLan selectedLan)
        {
            this.code = code;
            this.selectedLan = selectedLan;
            Thread thread = new Thread(ExecuteByProgramLan);
            thread.Start();
        }



        /// <summary>
        /// 通过编程语言执行代码
        /// </summary>
        /// <param name="code"></param>
        private void ExecuteByProgramLan()
        {
            if(preWork != null)
            {
                preWork();
            }
            //// 创建临时文件
            codeTmpPath = Constants.APP_STARTUP_PATH + CODE_TMP_FILENAME;
            switch (selectedLan)
            {
                case ProgramLan.JavaScript:
                    codeTmpPath += ".js";
                    break;
                case ProgramLan.PHP:
                    codeTmpPath += ".php";
                    break;
                case ProgramLan.Python:
                    codeTmpPath += ".py";
                    break;
                case ProgramLan.Go:
                    codeTmpPath += ".go";
                    break;
                default:
                    codeTmpPath += ".tmp";
                    break;
            }
            FileStream fs = new FileStream(codeTmpPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            StreamWriter sw = new StreamWriter(fs);
            // end 创建临时文件

            Func<string> runCode = null;
            switch (selectedLan)
            {
                case ProgramLan.JavaScript:
                    sw.Write(code);
                    runCode = RunNode;
                    break;
                case ProgramLan.PHP:
                    runCode = RunPHP;
                    sw.WriteLine("<?php ");
                    sw.Write(code);
                    break;
                case ProgramLan.Python:
                    runCode = RunPython;
                    sw.Write(code);
                    break;
                case ProgramLan.Go:
                    sw.Write(code);
                    runCode = RunGo;
                    break;
                default:
                    sw.Write(code);
                    runCode = DefaultRunCode;
                    break;
            }
            sw.Close(); // 关闭输入流
            Task<String> task = new Task<String>(runCode);
            task.Start();
            task.Wait();
            if(afterWork != null)
            {
                afterWork(task.Result);
            }
            // 删除临时文件
            if (File.Exists(codeTmpPath))
            {
                File.Delete(codeTmpPath);
            }
        }

        /// <summary>
        /// 公共ProcessInfo
        /// </summary>
        /// <returns></returns>
        private ProcessStartInfo GetCommonProcessInfo()
        {
            ProcessStartInfo info = new ProcessStartInfo();
            info.RedirectStandardError = true;
            info.RedirectStandardOutput = true;
            info.StandardOutputEncoding = Encoding.UTF8;
            info.StandardErrorEncoding = Encoding.UTF8;
            info.UseShellExecute = false;
            info.CreateNoWindow = true;
            return info;
        }


        /// <summary>
        /// 运行js脚本
        /// </summary>
        /// <returns></returns>
        private string RunNode()
        {
            Process scriptProc = new Process();
            ProcessStartInfo info = GetCommonProcessInfo();
            info.Arguments = codeTmpPath;
            info.FileName = "node.exe";
            scriptProc.StartInfo = info;
            try
            {
                scriptProc.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show("node未安装或者未设置node环境变量！");
                return "";
            }
            string outStr = scriptProc.StandardOutput.ReadToEnd();
            // 有错误，读取错误信息
            if (String.IsNullOrEmpty(outStr))
            {
                outStr = scriptProc.StandardError.ReadToEnd();
            }
            scriptProc.Close();
            return outStr;

        }

        /// <summary>
        /// 运行PHP脚本
        /// </summary>
        /// <returns></returns>
        private string RunPHP()
        {
            Process scriptProc = new Process();
            ProcessStartInfo info = GetCommonProcessInfo();
            info.FileName = Constants.APP_STARTUP_PATH + Common.Settings.PHPDirName.Value
                + "/php.exe";
            info.Arguments = "-f " + codeTmpPath;
            scriptProc.StartInfo = info;
            try
            {
                scriptProc.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show("PHP目录不存在！");
                return "";
            }
            string outStr = scriptProc.StandardOutput.ReadToEnd();
            // 有错误，读取错误信息
            if (String.IsNullOrEmpty(outStr))
            {
                outStr = scriptProc.StandardError.ReadToEnd();
            }
            scriptProc.Close();
            return outStr;

        }

        /// <summary>
        /// 运行Python脚本
        /// </summary>
        /// <returns></returns>
        private string RunPython()
        {
            Process scriptProc = new Process();
            ProcessStartInfo info = GetCommonProcessInfo();
            info.FileName = "python.exe";
            info.Arguments = codeTmpPath;
            scriptProc.StartInfo = info;
            try
            {
                scriptProc.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Python环境未安装或未添加到环境变量！");
                return "";
            }
            string outStr = scriptProc.StandardOutput.ReadToEnd();
            // 有错误，读取错误信息
            if (String.IsNullOrEmpty(outStr))
            {
                outStr = scriptProc.StandardError.ReadToEnd();
            }
            scriptProc.Close();
            return outStr;

        }

        /// <summary>
        /// 运行Go脚本
        /// </summary>
        /// <returns></returns>
        public string RunGo()
        {
            Process scriptProc = new Process();
            ProcessStartInfo info = GetCommonProcessInfo();
            info.FileName = "go.exe";
            info.Arguments = "run " + codeTmpPath;
            scriptProc.StartInfo = info;
            try
            {
                scriptProc.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Go环境未安装！");
                return "";
            }
            string outStr = scriptProc.StandardOutput.ReadToEnd();
            // 有错误，读取错误信息
            if (String.IsNullOrEmpty(outStr))
            {
                outStr = scriptProc.StandardError.ReadToEnd();
            }
            scriptProc.Close();
            return outStr;
        }

        /// <summary>
        /// 默认执行方式
        /// </summary>
        /// <returns></returns>
        public string DefaultRunCode()
        {
            return "还未实现哦 \\﻿(•◡•)/";
        }

    }
}
