using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;


namespace SXLibrary
{
    public class Log
    {
        private static readonly Thread WriteThread;
        private static readonly Queue<string> MsgQueue;
        private static readonly object FileLock;
        private static readonly string FilePath;

        static Log()
        {
            FileLock = new object();
            FilePath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "log\\";
            WriteThread = new Thread(WriteMsg);
            WriteThread.IsBackground = true;
            MsgQueue = new Queue<string>();
            WriteThread.Start();
        }

        public static void WriteInfoLog(string msg)
        {
            Monitor.Enter(MsgQueue);
            MsgQueue.Enqueue(string.Format("[{0}][{1}]{2}\r\n", DateTime.Now.ToString("HH:mm:ss fff"), "Info", msg));
            Monitor.Exit(MsgQueue);
        }
        public static void WriteErrorLog(string msg)
        {
            Monitor.Enter(MsgQueue);
            MsgQueue.Enqueue(string.Format("[{0}][{1}]{2}\r\n", DateTime.Now.ToString("HH:mm:ss fff"), "Error", msg));
            Monitor.Exit(MsgQueue);
        }
        public static void WriteDebugLog(string msg)
        {
            Monitor.Enter(MsgQueue);
            MsgQueue.Enqueue(string.Format("[{0}][{1}]{2}\r\n", DateTime.Now.ToString("HH:mm:ss fff"), "Debug", msg));
            Monitor.Exit(MsgQueue);
        }

        /// <summary>
        /// 用于记录函数耗时的日志;
        /// </summary>
        /// <param name="msg"></param>
        public static void WriteTimesdLog(string msg)
        {
            Monitor.Enter(MsgQueue);
            MsgQueue.Enqueue(string.Format("{0}[{1}]{2}\r\n", "Times", DateTime.Now.ToString("HH:mm:ss fff"), msg));
            Monitor.Exit(MsgQueue);
        }

        public static void WriteGetKeyLog(string msg)
        {
            Monitor.Enter(MsgQueue);
            MsgQueue.Enqueue(string.Format("[{0}][{1}]{2}\r\n",  DateTime.Now.ToString("HH:mm:ss fff"), "HTTP", msg));
            Monitor.Exit(MsgQueue);
        }

        private static void WriteMsg()
        {
            while (true)
            {
                if (MsgQueue.Count > 0)
                {
                    Monitor.Enter(MsgQueue);
                    string msg = MsgQueue.Dequeue();
                    Monitor.Exit(MsgQueue);

                    Monitor.Enter(FileLock);

                    string _path = FilePath + DateTime.Now.ToString("yyyy-MM");
                    if (msg.StartsWith("Times"))
                    {
                        _path = FilePath + msg.Substring(0, 5).Trim() + "\\" + DateTime.Now.ToString("yyyy-MM");
                        msg = msg.Remove(0, 5);
                    }

                    if (!Directory.Exists(_path))
                    {
                        Directory.CreateDirectory(_path);
                    }
                    string fileName = _path + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + ".log";
                    var logStreamWriter = new StreamWriter(fileName, true);
                    logStreamWriter.WriteLine(msg);
                    logStreamWriter.Close();
                    logStreamWriter.Dispose();
                    Monitor.Exit(FileLock);
                    // 大于10M时,备份日志文件;
                    if (GetFileSize(fileName) > 10)
                    {
                        fileName = DateTime.Now.ToString("yyyy-MM-dd");
                        CopyToBak(_path, fileName);
                    }
                }
                else
                {
                    System.Threading.Thread.Sleep(5);
                }
            }
        }


        private static long GetFileSize(string fileName)
        {
            long strRe = 0;
            if (File.Exists(fileName))
            {
                Monitor.Enter(FileLock);
                var myFs = new FileStream(fileName, FileMode.Open);
                strRe = myFs.Length / 1048576;
                myFs.Close();
                myFs.Dispose();
                Monitor.Exit(FileLock);
            }
            return strRe;
        }
        private static void CopyToBak(string dir, string sFileName)
        {
            int fileCount = 0;
            string strBackFile = dir + "\\bak";
            string strOriginalFile = dir + "\\" + sFileName + ".log";

            if (!Directory.Exists(strBackFile))
            {
                Directory.CreateDirectory(strBackFile);
            }

            Monitor.Enter(FileLock);
            do
            {
                fileCount++;
                strBackFile = dir + "\\bak\\" + sFileName + "-bak." + fileCount + ".log";
            }
            while (File.Exists(strBackFile));

            File.Copy(strOriginalFile, strBackFile);
            File.Delete(strOriginalFile);
            Monitor.Exit(FileLock);
        }
    }
}