using System;
using System.Reflection;
using System.Diagnostics;

namespace Asa.RFID
{
    /// <summary>
    /// 日志操作类
    /// </summary>
    internal class Log
    {
        private bool exit = false;
        private int day = 0;
        private string fileName;
        private string filePath = "";
        private System.Collections.Concurrent.ConcurrentQueue<string> _info;
        private System.Threading.Thread tSave;

        private readonly string _path;
        private StackTrace trace;
        private StackFrame frame;
        private MethodBase method;

        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="path">文件夹目录</param>
        public Log(string path)
        {
            fileName = null;
            if (string.IsNullOrWhiteSpace(path))
            {
                _path = "";
            }
            else
            {
                _path = path.EndsWith("\\") ? path : path + "\\";
                if (!System.IO.Directory.Exists(_path))
                    System.IO.Directory.CreateDirectory(_path);
            }

            _info = new System.Collections.Concurrent.ConcurrentQueue<string>();
            tSave = new System.Threading.Thread(new System.Threading.ThreadStart(SaveLog));
            tSave.Start();
        }

        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="path">文件夹目录</param>
        /// <param name="name">文件名</param>
        public Log(string path, string name) : this(path)
        {
            fileName = name;
        }

        /// <summary>
        /// 退出
        /// </summary>
        public void Exit()
        {
            exit = true;
        }

        /// <summary>
        /// 输出错误信息
        /// </summary>
        /// <param name="s"></param>
        public void OutError(string s)
        {
            if (string.IsNullOrWhiteSpace(s)) return;
            trace = new StackTrace(true);
            frame = trace.GetFrame(1);

            string name = frame.GetFileName();
            name = System.IO.Path.GetFileName(name);
            string log = string.Format("[{0:HH:mm:ss.fff}] ERROR {1}({2},{3})\r\n",
                DateTime.Now, name, frame.GetFileLineNumber(), frame.GetFileColumnNumber());

            string[] arr = new string[trace.FrameCount - 1];
            for (int i = 1; i < trace.FrameCount; i++)  //0是本身Out
            {
                method = trace.GetFrame(i).GetMethod();
                arr[arr.Length - i] = "  " + method.DeclaringType.FullName + " -> " + method.ToString();
            }
            log += string.Join("\r\n", arr) + string.Format("\r\n  {0}\r\n", s);
            _info.Enqueue(log);
        }

        /// <summary>
        /// 输出信息
        /// </summary>
        /// <param name="s"></param>
        public void OutInfo(string s)
        {
            if (string.IsNullOrWhiteSpace(s)) return;
            trace = new StackTrace(true);
            frame = trace.GetFrame(1);
            method = trace.GetFrame(1).GetMethod();

            string name = frame.GetFileName();
            name = System.IO.Path.GetFileName(name);
            string s1 = method.DeclaringType.FullName;
            string s2 = method.Name;

            string log = string.Format("[{0:HH:mm:ss.fff}] INFO {1}({2},{3}) {4}->{5}  {6}\r\n",
                DateTime.Now, name, frame.GetFileLineNumber(), frame.GetFileColumnNumber(), s1, s2, s);
            _info.Enqueue(log);
        }

        /// <summary>
        /// 输出调试信息
        /// </summary>
        /// <param name="s"></param>
        public void OutDebug(string s)
        {
            if (string.IsNullOrWhiteSpace(s)) return;
            trace = new StackTrace(true);
            frame = trace.GetFrame(1);

            string name = frame.GetFileName();
            name = System.IO.Path.GetFileName(name);
            string log = string.Format("[{0:HH:mm:ss.fff}] DEBUG {1}({2},{3})\r\n",
                DateTime.Now, name, frame.GetFileLineNumber(), frame.GetFileColumnNumber());

            string[] arr = new string[trace.FrameCount];
            for (int i = 0; i < trace.FrameCount; i++)
            {
                method = trace.GetFrame(i).GetMethod();
                arr[arr.Length - i - 1] = "  " + method.DeclaringType.FullName + " -> " + method.ToString();
            }
            log += string.Join("\r\n", arr) + string.Format("\r\n  {0}\r\n", s);
            _info.Enqueue(log);
        }

        /// <summary>
        /// 输出字符串数据
        /// </summary>
        /// <param name="s"></param>
        public void OutString(string s)
        {
            if (string.IsNullOrEmpty(s)) return;
            string log = string.Format("[{0:HH:mm:ss.fff}] {1}\r\n", DateTime.Now, s);
            _info.Enqueue(log);
        }




        private void SaveLog()
        {
            while (true)
            {
                System.Threading.Thread.Sleep(5);
                if (_info.TryDequeue(out string result))
                {
                    try
                    {
                        SaveFile(result);
                    }
                    catch (ObjectDisposedException odex)
                    {
                        break;
                    }
                    catch (Exception ex)
                    {
                    }
                }

                if (exit)
                {
                    if (_info.Count == 0)
                        break;
                }
            }
        }

        private void SaveFile(string log)
        {
            if (_path == "") return;
            if (day != DateTime.Now.Day)
            {
                if (fileName == null)
                {
                    filePath = string.Format("{0}{1:yyyy-MM-dd}.log", _path, DateTime.Now);
                }
                else
                {
                    filePath = string.Format("{0}{1:yyyy-MM-dd}\\", _path, DateTime.Now);
                    System.IO.Directory.CreateDirectory(filePath);
                    filePath += fileName + ".log";
                }
                day = DateTime.Now.Day;
            }

            byte[] array = System.Text.Encoding.UTF8.GetBytes(log);
            System.IO.FileStream fs = System.IO.File.OpenWrite(filePath);
            fs.Position = fs.Length;
            fs.Write(array, 0, array.Length);
            fs.Close();
        }


    }


}