namespace SafeCampus.Core.Extension
{
    /// <summary>
    /// 日志帮助类
    /// </summary>
    public class LogHelper
    {
        /// <summary>
        /// 配置文件
        /// </summary>
        protected static LogConfig Config = new LogConfig();

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="isError"></param>
        /// <returns></returns>
        protected static StreamWriterLock GetLogWriter(bool isError = false)
        {
            try
            {
                string root = AppDomain.CurrentDomain.BaseDirectory;
                DateTime now = DateTime.Now;
                //日志文件路径
                string folder = isError ? Config.LogErrorFolder : Config.LogInfoFolder;
                folder = Path.Combine(root, folder, now.ToString(Config.LogFolderFormat));

                string filePath = Path.Combine(folder, now.ToString(Config.LogFileFormat) + Config.LogFileExt);

                if (!Directory.Exists(folder))
                {
                    Directory.CreateDirectory(folder);
                }
                return new StreamWriterLock(filePath);
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 写日志
        /// </summary>
        public static void WriteToLog(string content)
        {
            using (var sw = GetLogWriter())
            {
                var writer = sw.Writer;
                writer.WriteStart();
                writer.WriteTime();
                writer.WriteContent(content);
                writer.WriteLine();
            }
        }

        /// <summary>
        /// 写日志
        /// </summary>
        public static void WriteToLog(string[] contents)
        {
            using (var sw = GetLogWriter())
            {
                var writer = sw.Writer;
                writer.WriteStart();
                writer.WriteTime();
                writer.WriteContent(contents);
                writer.WriteEnd();
            }
        }

        /// <summary>
        /// 写日志
        /// </summary>
        public static void WriteToLog(string title, string content)
        {
            using (var sw = GetLogWriter())
            {
                var writer = sw.Writer;
                writer.WriteStart();
                writer.WriteTitle(title);
                writer.WriteTime();
                writer.WriteContent(content);
                writer.WriteEnd();
            }
        }

        /// <summary>
        /// 写日志(错误)
        /// </summary>
        public static void WriteToLog(Exception ex, string title = "", string content = "")
        {
            using (var sw = GetLogWriter(true))
            {
                var writer = sw.Writer;
                writer.WriteStart();
                writer.WriteTitle(title, true);
                writer.WriteTime();
                if (!string.IsNullOrEmpty(content))
                {
                    writer.WriteContent(content);
                }
                writer.WriteException(ex);
                writer.WriteEnd();
            }
        }
    }

    /// <summary>
    /// 日志目录配置
    /// </summary>
    public class LogConfig
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public LogConfig()
        {
            this.LogRoot = "Log";
            this.LogInfoFolder = Path.Combine(this.LogRoot, "LogInfo");
            this.LogErrorFolder = Path.Combine(this.LogRoot, "LogError");
            this.LogFolderFormat = "yyyyMMdd";
            this.LogFileFormat = "yyyyMMdd_HH";
            this.LogFileExt = ".log";
        }

        /// <summary>
        /// 日志根目录
        /// </summary>
        public string LogRoot { get; set; }

        /// <summary>
        /// 普通信息
        /// </summary>
        public string LogInfoFolder { get; set; }

        /// <summary>
        /// 错误信息
        /// </summary>
        public string LogErrorFolder { get; set; }

        /// <summary>
        /// 文件夹日期格式
        /// </summary>
        public string LogFolderFormat { get; set; }

        /// <summary>
        /// 文件日志格式
        /// </summary>
        public string LogFileFormat { get; set; }

        /// <summary>
        /// 文件后缀名
        /// </summary>
        public string LogFileExt { get; set; }
    }

    /// <summary>
    /// 日志工具
    /// </summary>
    public static class LogTools
    {
        /// <summary>
        /// 开始写日志
        /// </summary>
        /// <param name="writer"></param>
        public static void WriteStart(this StreamWriter writer)
        {
            writer.WriteLine("-------------------------------------------------------------------------------------");
        }

        /// <summary>
        /// 结束写
        /// </summary>
        /// <param name="writer"></param>
        public static void WriteEnd(this StreamWriter writer)
        {
            //writer.WriteLine("-------------------------------------------------------------------------------------");
            writer.WriteLine();
        }

        /// <summary>
        /// 写入时间
        /// </summary>
        /// <param name="writer"></param>
        public static void WriteTime(this StreamWriter writer)
        {
            writer.WriteLine("Date:{0:yyyy-MM-dd} Time:{0:HH:mm:ss}", DateTime.Now);
        }

        /// <summary>
        /// 写入标题
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="title"></param>
        /// <param name="isError"></param>
        public static void WriteTitle(this StreamWriter writer, string title, bool isError = false)
        {
            if (isError)
            {
                writer.WriteLine("Title:Error!!!");
                if (!string.IsNullOrEmpty(title))
                {
                    writer.WriteLine(title);
                }
            }
            else
            {
                writer.WriteLine("Title:{0}", title);
            }
        }

        /// <summary>
        /// 写入内容
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="content"></param>
        public static void WriteContent(this StreamWriter writer, string content)
        {
            writer.WriteLine("Content:{0}", content);
        }

        /// <summary>
        /// 写入内容
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="contents"></param>
        public static void WriteContent(this StreamWriter writer, string[] contents)
        {
            writer.WriteLine("Content:{0}", contents.Length);
            var dig = Math.Max(2, contents.Length.ToString().Length); //位数
            for (int i = 0; i < contents.Length; i++)
            {
                writer.WriteLine("No.{0}->{1}", (i + 1).ToString().PadLeft(2, '0'), contents[i]);
            }
        }

        /// <summary>
        /// 写入异常
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="ex"></param>
        public static void WriteException(this StreamWriter writer, Exception ex)
        {
            writer.WriteLine("Message:{0}", ex.Message);
            writer.WriteLine("StackTrace:{0}", ex.StackTrace);
            if (ex.InnerException != null)
            {
                writer.WriteLine("InnerException:");
                writer.WriteLine("Message:{0}", ex.InnerException.Message);
                writer.WriteLine("StackTrace:{0}", ex.InnerException.StackTrace);
            }
        }
    }

    /// <summary>
    /// 文件锁
    /// </summary>
    public class StreamWriterLock : IDisposable
    {
        /// <summary>
        /// 写入
        /// </summary>
        public StreamWriter Writer { get; protected set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="filePath"></param>
        public StreamWriterLock(string filePath)
        {
            Lock.EnterWriteLock();
            if (!File.Exists(filePath))//如果文件不存在
            {
                File.Create(filePath).Close();
            }
            this.Writer = File.AppendText(filePath);
        }

        /// <summary>
        /// 文件读写锁
        /// </summary>
        protected static ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();

        public void Dispose()
        {
            this.Writer.Dispose();
            Lock.ExitWriteLock();
        }
    }
}