using System;
using System.Reflection;
using System.Text;
using log4net.Core;

namespace Aitex.Core.RT.Log
{
	/// <summary>
	/// 将日志信息写入磁盘的写入器对象。
	/// </summary>
	internal class LogWriter
	{
        #region Variables

        private readonly ILogger _logger;

		#endregion

        #region Constructors

		/// <summary>
		/// 构造日志写入器对象的实例。
		/// </summary>
        public LogWriter()
        {
            _logger = LoggerManager.GetLogger(Assembly.GetExecutingAssembly(), "CommonLogger");
        }

		#endregion

        #region Methods

        /// <summary>
        /// 格式化日志字串。
        /// </summary>
        /// <param name="logItem">日志项目对象。</param>
        /// <returns></returns>
        private static string FormatLogString(LogItem logItem)
        {
            var sb = new StringBuilder();

            // 写入日志时间
            var header = $"{logItem.Time:yyyy-MM-dd HH:mm:ss.fff} {logItem.Level,-7}";
            sb.Append(header);

            // 日志消息体缩进使用时间部分的字串长度，解决多行消息体换行后保持正确缩进的问题。
            var intend = header.Length;
            var msgLines = logItem.Message.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
            for (var i = 0; i < msgLines.Length; i++)
            {
                var line = msgLines[i].TrimEnd('\r', '\n');

                if(i == 0) 
                    // 第一条消息不要添加缩进
                    sb.AppendLine(line);
                else if(i == msgLines.Length - 1)
                    // 最后一条消息末尾不要添加换行
                    sb.Append($"{new string(' ', intend)}{line}");
                else
                    // 其它消息添加缩进和换行
                    sb.AppendLine($"{new string(' ', intend)}{line}");
            }

            return sb.ToString().TrimEnd('\r', '\n');
        }

        /// <summary>
        /// 日志写入磁盘。
        /// </summary>
        /// <param name="logItem"></param>
        /// <returns></returns>
		public string Write(LogItem logItem)
		{
			var formattedLogString = FormatLogString(logItem);
            _logger.Log(typeof(LogWriter), logItem.Level, formattedLogString, logItem.Exception);
            return formattedLogString;
		}

        #endregion
    }
}
