#define TRACE
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Aitex.Core.Util;
using log4net.Core;

namespace Aitex.Core.RT.Log
{
	/// <summary>
	/// 实现ICommonLog接口的日志管理器对象。
	/// </summary>
	public class LogManager : ICommonLog
	{
        #region Variables

        /// <summary>
        /// 周期性任务执行定时器。
        /// </summary>
		private PeriodicJob _loggingJob;

        /// <summary>
        /// 具有最大数量限制的列队。
        /// </summary>
		private FixSizeQueue<LogItem> _logQueue;

        /// <summary>
        /// 将日志信息写入磁盘的写入器对象。
        /// </summary>
		private LogWriter _writer;
        
        #endregion

        #region Private Methods
		
		/// <summary>
		/// 在后台线程中周期性执行的任务。
		/// </summary>
		/// <returns></returns>
        private bool BackgroundTask()
        {
            while (_logQueue.TryDequeue(out var log))
            {
                try
                {
                    _writer.Write(log);
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex);
                }
            }
            
            return true;
        }

        /// <summary>
        /// 缓存一条日志。
        /// <remarks>
        /// 日志延时写入磁盘，以减少磁盘IO次数，提高写入性能。
        /// </remarks>
        /// </summary>
        /// <param name="message">日志内容。</param>
        /// <param name="level">日志等级。</param>
        /// <param name="exception">异常对象实例。</param>
        /// <param name="isTraceOn">是否跟踪调用堆栈。</param>
        /// <param name="stackFile">产生日志的源文件名称。</param>
        /// <param name="line">写入日志的源代码行号。</param>
        private void CacheLog(string message, Level level, Exception exception, bool isTraceOn, string stackFile, int line = 0)
        {
            _logQueue.Enqueue(new LogItem(message, new StackTrace(fNeedFileInfo: true).GetFrame(5), level, exception, stackFile, line));
        }

        #endregion

        #region Methods


        /// <summary>
        /// 初始化日志管理器。
        /// </summary>
        public void Initialize()
		{
			_logQueue = new FixSizeQueue<LogItem>(1000);
			_loggingJob = new PeriodicJob(300, BackgroundTask, "Save Log Job", isStartNow: true);
			_writer = new LogWriter();
			LOG.InnerLogger = this;
		}

		/// <summary>
		/// 终止日志管理器。
		/// </summary>
		public void Terminate()
		{
			try
			{
				if (_loggingJob != null)
				{
					_loggingJob.Stop();
					_loggingJob = null;
				}
			}
			catch (Exception ex)
			{
				Trace.WriteLine(ex.Message);
			}
		}


        /// <inheritdoc />
        public void Debug(string message, [CallerFilePath] string file = "", [CallerMemberName] string member = "", [CallerLineNumber] int line = 0)
        {
            CacheLog(message, Level.Debug, null, false, file, line);
        }

        /// <summary>
        /// 输出普通日志。
        /// </summary>
        /// <param name="message">日志内容。</param>
        /// <param name="isTraceOn">是否跟踪调用堆栈。</param>
        /// <param name="stackFile">产生日志的源文件名称。</param>
        public void Info(string message, bool isTraceOn, string stackFile)
		{
			CacheLog(message, Level.Info, null, isTraceOn, stackFile);
		}

        /// <summary>
        /// 输出报警日志。
        /// </summary>
        /// <param name="message">日志内容。</param>
        /// <param name="stackFile">产生日志的源文件名称。</param>
        public void Warning(string message, string stackFile)
		{
			CacheLog(message, Level.Warn, null, isTraceOn: true, stackFile);
		}

        /// <summary>
        /// 输出报警日志。
        /// </summary>
        /// <param name="message">日志内容。</param>
        /// <param name="ex">异常对象实例。</param>
        /// <param name="stackFile">产生日志的源文件名称。</param>
        public void Warning(string message, Exception ex, string stackFile)
        {
            CacheLog(message, Level.Warn, ex, isTraceOn: true, stackFile);
        }

        /// <summary>
        /// 输出错误日志。
        /// </summary>
        /// <param name="message">日志内容。</param>
        /// <param name="stackFile">产生日志的源文件名称。</param>
        public void Error(string message, string stackFile)
		{
			CacheLog(message, Level.Error, null, isTraceOn: true, stackFile);
		}
        
        /// <summary>
        /// 输出错误日志。
        /// </summary>
        /// <param name="message">日志内容。</param>
        /// <param name="ex">异常对象实例。</param>
        /// <param name="stackFile">产生日志的源文件名称。</param>
        public void Error(string message, Exception ex, string stackFile)
		{
			CacheLog(message, Level.Error, ex, isTraceOn: true, stackFile);
		}
        
        #endregion

    }
}
