using Pomelo;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using CommonLang.Log;
using System.Runtime.InteropServices;
using System.Xml;
using CommonLang.Xml;
using System.Xml.Linq;
using CommonLang.Vector;
using System.Text;
using System.Security.Cryptography;
using CommonAI.Data;
using CommonLang;
using CommonAI.Zone.Helper;

namespace test
{
    public class Program
    {
        private static bool isRunning = false;
        private static bool isTest = false;

		public static void Main(string[] args)
        {
			try
			{
				DisbleQuickEditMode();
                dynamic intput = new ExpandoObject();
                isRunning = true;
                // -- ZoneConfig
                var zoneConfig = new ZoneConfig();
                zoneConfig.startPath = Environment.CurrentDirectory;
                zoneConfig.assetPath = GetConfigAsString("zoneConfig.assetPath");

                intput.zoneConfig = zoneConfig;
                // -- logConfig
                var logConfig = new LogConfig();
                
                logConfig.serverId = GetConfigAsString("game.server.id");
                logConfig.outputPath = GetConfigAsString("logConfig.outputPath");
                logConfig.level = GetConfigLoglevel("logConfig.level");
				string socketPort = "socket_" + GetConfigAsString("fastStreamConfig.port");

				//log4j默认的配置文件名,其实也不能修改
				string sourceFile = "log4net";// GetConfigAsString("logConfig.configFile");
                logConfig.configFile = sourceFile + ".config";
				//根据服务器id,重载log文件配置
				string logExt = string.IsNullOrEmpty(logConfig.serverId) ? socketPort : logConfig.serverId;
				ReloadLogConfig(sourceFile, logConfig.outputPath + logExt, logConfig.configFile);

                LoggerFactory.SetFactory(new PomeloLog(logConfig));

                if (isTest)
                {
                    testLog(logConfig);
                    return;
                }


                intput.logConfig = logConfig;
                // -- iceConfig
                var iceConfig = new IceConfig();
                iceConfig.host = GetConfigAsString("iceConfig.host");
                iceConfig.port = GetConfigAsInt("iceConfig.port");
                iceConfig.isTraceNetwork = GetConfigAsBool("iceConfig.isTraceNetwork");
                iceConfig.isTraceProtocol = GetConfigAsBool("iceConfig.isTraceProtocol");
                iceConfig.isWarnConnections = GetConfigAsBool("iceConfig.isWarnConnections");

                intput.iceConfig = iceConfig;
                GlobalData.GAME_BS_TEST = GetConfigAsBool("game.bstest") || (logConfig.serverId.Equals("10004") && iceConfig.port == 9910);

                // -- fastStreamConfig
                var fastStreamConfig = new FastStreamConfig();
                fastStreamConfig.port = GetConfigAsInt("fastStreamConfig.port");

                intput.fastStreamConfig = fastStreamConfig;
                Task.WaitAll(new EdgeJS().init(intput));
            }
            catch (Exception e)
            {
                isRunning = false;
                Console.WriteLine(e);//捕获异常,输出异常信息
                Console.ReadKey();
                return;
            }
            //
            StartCommandConsoleThread();
            // -- 启动gameServer
            var startBatFile = GetConfigAsString("gameServer.start.bat");
            if (!string.IsNullOrEmpty(startBatFile))
            {
                var start = new ProcessStartInfo();
                start.WorkingDirectory = Path.GetDirectoryName(startBatFile);
                start.FileName = startBatFile;

                start.CreateNoWindow = false;
                start.UseShellExecute = false;
                start.RedirectStandardInput = false;

                start.RedirectStandardOutput = false;
                Process pro = null;
                try
                {
                    pro = Process.Start(start);
                    pro.WaitForExit();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);//捕获异常,输出异常信息
                }
                finally
                {
                    pro.Close();
                }
            }
            isRunning = false;
        }


        public static void testLog(LogConfig logConfig)
        {
            Logger defLog = LoggerFactory.GetDefLogger();
            Logger testLog = LoggerFactory.GetLogger("test");

            defLog.Debug("debug def");
            defLog.Info("info def");
            defLog.Warn("warn def");
            defLog.Error("error def");

            defLog.DebugFormat("{0} format","def debug");
            defLog.InfoFormat("{0} format", "def info");
            defLog.WarnFormat("{0} format", "def warn");
            defLog.ErrorFormat("{0} format", "def error");


            testLog.Debug("debug test");
            testLog.Info("info test");
            testLog.Warn("warn test");
            testLog.Error("error test");

            testLog.DebugFormat("{0} format", "test debug");
            testLog.InfoFormat("{0} format", "test info");
            testLog.WarnFormat("{0} format", "test warn");
            testLog.ErrorFormat("{0} format", "test error");
        }

		#region 关闭控制台 快速编辑模式、插入模式
		const int STD_INPUT_HANDLE = -10;
		const uint ENABLE_QUICK_EDIT_MODE = 0x0040;
		const uint ENABLE_INSERT_MODE = 0x0020;
		[DllImport("kernel32.dll", SetLastError = true)]
		internal static extern IntPtr GetStdHandle(int hConsoleHandle);
		[DllImport("kernel32.dll", SetLastError = true)]
		internal static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint mode);
		[DllImport("kernel32.dll", SetLastError = true)]
		internal static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint mode);

		public static void DisbleQuickEditMode()
		{
			IntPtr hStdin = GetStdHandle(STD_INPUT_HANDLE);
			uint mode;
			GetConsoleMode(hStdin, out mode);
			mode &= ~ENABLE_QUICK_EDIT_MODE;//移除快速编辑模式
			mode &= ~ENABLE_INSERT_MODE;      //移除插入模式
			SetConsoleMode(hStdin, mode);
		}
		#endregion

		public static void StartCommandConsoleThread()
        {
            new Thread(()=>
            {
                while(isRunning)
                {
                    var cmd = Console.ReadLine();
                    if(cmd == "cls")
                    {
                        Console.Clear();
                    }
                }
                Thread.Sleep(100);
            }).Start();
        }

        private static void LoglevelConfigErr(string errString)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("/*********************************************************");
            Console.WriteLine("*logConfig.level配置错误,logConfig.level=" + errString);
            Console.WriteLine("*请检查xmds-battle-server.exe.config文件配置");
            Console.WriteLine("**********************************************************");
            Console.ForegroundColor = ConsoleColor.White;
        }

        //吐血。。。一顿操作猛如虎, 最后还得二次转换,
        //只加几个简单的转换
        private static uint GetConfigLoglevel(string key)
        {
            uint level = LoggerLevel.INFO;
            String logLevel = GetConfigAsString(key);
            if (logLevel == null)
            {
                LoglevelConfigErr(logLevel);
                return LoggerLevel.INFO;
            }
            else
            {
                logLevel = logLevel.ToUpper();
            }

            switch (logLevel)
            {
                case "DEBUG":
                    level = LoggerLevel.DEBUG | LoggerLevel.INFO | LoggerLevel.WARNNING | LoggerLevel.ERROR;
                    break;
                case "INFO":
                    level = LoggerLevel.INFO | LoggerLevel.WARNNING | LoggerLevel.ERROR;
                    break;
                case "WARNNING":
                    level = LoggerLevel.WARNNING | LoggerLevel.ERROR;
                    break;
                case "ERROR":
                    level = LoggerLevel.ERROR;
                    break;
                default:
                    level = LoggerLevel.ERROR;
                    LoglevelConfigErr(logLevel);
                    break;
            }

            return level;
        }

        private static void ReloadLogConfig(string fileName, string path, string saveFileName)
        {
            try
            {
                XmlDocument xmlDoc = XmlUtil.LoadXML(fileName);
                XmlNode xmlNode = xmlDoc.SelectSingleNode("log4net");
                XmlNodeList nodeList = xmlNode.ChildNodes;
                for (int i = 0; i < nodeList.Count; i++)
                {
                    XmlNode nodeTemp = nodeList.Item(i);
                    if (nodeTemp == null || !nodeTemp.Name.Equals("appender"))
                    {
                        continue;
                    }

                    XmlNode fileAttribute = nodeTemp.SelectSingleNode("file");
                    if (fileAttribute != null)
                    {
                        XmlAttributeCollection attribute = fileAttribute.Attributes;
                        if (attribute != null && attribute.Count == 1)
                        {
                            XmlNode fileNode = attribute.Item(0);
                            //perf, debug, info, warn, err
                            if (!fileNode.InnerText.EndsWith(".log"))
                            {
                                fileNode.InnerText = path + "/" + fileNode.InnerText + ".log";
                            }                            
                        }
                    }
                }

                xmlDoc.Save(saveFileName);
            }
            catch(Exception e)
            {
                throw e;
            }           
        }

        public static int GetConfigAsInt(string key)
        {
            var str = ConfigurationManager.AppSettings[key];
            if (string.IsNullOrEmpty(str))
            {
                return 0;
            }
            return int.Parse(str);
        }

        public static string GetConfigAsString(string key)
        {
            return ConfigurationManager.AppSettings[key];
        }

        public static bool GetConfigAsBool(string key)
        {
            var str = ConfigurationManager.AppSettings[key];
            if (string.IsNullOrEmpty(str))
            {
                return false;
            }
            return bool.Parse(str);
        }

    }
}