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

namespace Asa.IOModule
{
    /// <summary>
    /// 日志操作类
    /// </summary>
    internal class LogFile
    {
        //private string args;
        private bool loop;
        private System.IO.FileStream fs;
        private StackTrace trace;
        private StackFrame frame;
        private MethodBase method;
        private System.Threading.Thread tSave;
        private System.Collections.Concurrent.ConcurrentQueue<string> info;

        private readonly string PATH;

        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="path">文件夹路径</param>
        /// <param name="ip"></param>
        internal LogFile(string path, string ip)
        {
            if (path == null) return;
            //this.args = ip;
            PATH = path.EndsWith("\\") ? path : path + "\\";
            if (!System.IO.Directory.Exists(PATH))
                System.IO.Directory.CreateDirectory(PATH);

            loop = true;
            tSave = new System.Threading.Thread(new System.Threading.ThreadStart(SaveLog));
            info = new System.Collections.Concurrent.ConcurrentQueue<string>();
            tSave.Start();
            string file = string.Format("{0}{1:yyyy-MM-dd}_({2}).log", PATH, DateTime.Now, ip);
            fs = System.IO.File.OpenWrite(file);
            fs.Position = fs.Length;
        }

        /// <summary>
        /// 关闭文件
        /// </summary>
        internal void Close()
        {
            loop = false;
            System.Threading.Thread.Sleep(5);
            if (fs != null)
                fs.Close();
        }

        /// <summary>
        /// 输出错误
        /// </summary>
        /// <param name="s"></param>
        internal 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);
            //byte[] array = System.Text.Encoding.UTF8.GetBytes(log);
            //fs.Write(array, 0, array.Length);
            info.Enqueue(log);
        }

        /// <summary>
        /// 输出信息
        /// </summary>
        /// <param name="s"></param>
        internal 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}\r\n  {6}\r\n",
                DateTime.Now, name, frame.GetFileLineNumber(), frame.GetFileColumnNumber(), s1, s2, s);
            //byte[] array = System.Text.Encoding.UTF8.GetBytes(log);
            //fs.Write(array, 0, array.Length);
            info.Enqueue(log);
        }

        /// <summary>
        /// 输出数据
        /// </summary>
        /// <param name="tr"></param>
        /// <param name="buff"></param>
        internal void OutData(string tr, byte[] buff)
        {
            string log = string.Format("{0:HH:mm:ss.fff} {1} ", DateTime.Now, tr);
            for (int i = 0; i < buff.Length; i++)
                log += buff[i].ToString("X2") + " ";
            log += "\r\n";
            //byte[] array = System.Text.Encoding.UTF8.GetBytes(log);
            //fs.Write(array, 0, array.Length);
            info.Enqueue(log);
        }

        /// <summary>
        /// 输出数据
        /// </summary>
        /// <param name="s"></param>
        internal void OutData(string s)
        {
            string log = string.Format("{0:HH:mm:ss.fff} {1}\r\n", DateTime.Now, s);
            //byte[] array = System.Text.Encoding.UTF8.GetBytes(log);
            //fs.Write(array, 0, array.Length);
            info.Enqueue(log);
        }

        internal void SaveLog()
        {
            while (loop)
            {
                try
                {
                    if (info.TryDequeue(out string result))
                    {
                        byte[] array = System.Text.Encoding.UTF8.GetBytes(result);
                        fs.Write(array, 0, array.Length);
                    }
                }
                catch (Exception)
                { }
                System.Threading.Thread.Sleep(2);
            }
        }



    }


}