using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace PushPlatform.Common.Util
{
    /// <summary>
    /// 日志辅助类
    /// </summary>
    public class LogHelper
    {
        private static object _Lock = new object();

        #region 获取调用日志堆栈信息，受保护的方法
        /// <summary>
        /// 获取调用日志堆栈信息，受保护的方法
        /// </summary>
        /// <returns>StackTrace信息</returns>
        protected static string GetStackTrace()
        {
            StackTrace st = new StackTrace(true);
            //index:0为本身的方法；1为调用方法；2为其上上层，依次类推
            MethodBase mb = st.GetFrame(2).GetMethod();
            StringBuilder sb = new StringBuilder(Environment.NewLine);
            sb.AppendLine("记录时间:{0}");
            sb.AppendLine("模块名:{1}");
            sb.AppendLine("命名空间:{2}");
            sb.AppendLine("类名:{3}");
            sb.AppendLine("方法名:{4}");
            string str = string.Format(sb.ToString(), DateTime.Now
                , mb.Module == null ? "" : mb.Module.Name
                , mb.DeclaringType==null ? "": mb.DeclaringType.Namespace
                , mb.DeclaringType == null ? "" : mb.DeclaringType.Name
                , mb.Name);
            return str;
        }

        /// <summary>
        /// 获取调用日志堆栈信息，受保护的方法
        /// </summary>
        /// <param name="className">引发异常的类名</param>
        /// <param name="functionName">引发异常的方法名</param>
        /// <param name="lineNumber">引发异常的代码行号</param>
        /// <returns>StackTrace信息</returns>
        protected static string GetStackTrace(Exception ex, out string className, out string functionName, out string lineNumber)
        {
            StackTrace st = new StackTrace(true);
            //index:0为本身的方法；1为调用方法；2为其上上层，依次类推
            MethodBase mb = st.GetFrame(2).GetMethod();
            int line = st.GetFrame(2).GetFileLineNumber();
            StringBuilder sb = new StringBuilder(Environment.NewLine);
            sb.AppendLine("记录时间:{0}");
            sb.AppendLine("模块名:{1}");
            sb.AppendLine("命名空间:{2}");
            sb.AppendLine("类名:{3}");
            sb.AppendLine("方法名:{4}");
            string str = string.Format(sb.ToString(), DateTime.Now
                , mb.Module.Name
                , mb.DeclaringType.Namespace
                , mb.DeclaringType.Name
                , mb.Name);
            className = mb.DeclaringType.Name;
            functionName = mb.Name;
            lineNumber = st.GetFrame(2).GetFileLineNumber().ToString();
            return str;
        }
        #endregion

        #region 写入文件，私有方法
        /// <summary>
        /// 写入文件，私有方法
        /// </summary>
        /// <param name="folder">文件夹</param>
        /// <param name="content">写入内容</param>
        private static void Write(string folder, string content)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory + "\\Log\\" + folder + "\\";

            string fileName = DateTime.Now.ToString("yyyy-MM-dd") + ".log";

            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            lock (_Lock)
            {
                using (FileStream fs = new FileStream(path + fileName, FileMode.Append, FileAccess.Write, FileShare.Write, 1024, FileOptions.Asynchronous))
                {
                    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(content);
                    //异步写入
                    //IAsyncResult writeResult = fs.BeginWrite(buffer, 0, buffer.Length,
                    //    (asyncResult) =>
                    //    {
                    //        var fStream = (FileStream)asyncResult.AsyncState;
                    //        fStream.EndWrite(asyncResult);
                    //    },
                    //    fs);
                    fs.Write(buffer, 0, buffer.Length);
                    fs.Close();
                }
            }
        }
        #endregion

        #region 调试日志
        /// <summary>
        /// 调试日志
        /// </summary>
        /// <param name="debugContent">调试内容</param>
        public static void Debug(string debugContent)
        {
            string stackTrace = GetStackTrace();
            StringBuilder sb = new StringBuilder(stackTrace);
            sb.AppendLine("调试内容:" + debugContent + Environment.NewLine);
            Write("debug", sb.ToString());
        }
        #endregion

        #region 打印信息
        /// <summary>
        /// 打印信息
        /// </summary>
        /// <param name="infoContent">打印内容</param>
        public static void Info(string infoContent)
        {
            string stackTrace = GetStackTrace();
            StringBuilder sb = new StringBuilder(stackTrace);
            sb.AppendLine("打印内容:" + infoContent + Environment.NewLine);
            Write("info", sb.ToString());
        }
        #endregion

        #region 错误日志
        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="ex">异常</param>
        public static void Error(Exception ex)
        {
            string className;
            string functionName;
            string lineNumber;
            string stackTrace = GetStackTrace(ex, out className, out functionName, out lineNumber);
            StringBuilder sb = new StringBuilder(stackTrace);
            sb.AppendLine("错误内容如下:");
            sb.AppendLine("消息类型:{0}");
            sb.AppendLine("消息内容:{1}");
            sb.AppendLine("引发异常的方法:{2}");
            sb.AppendLine("引发异常的对象:{3}");
            sb.AppendLine("引发异常的类:{4}");
            sb.AppendLine("引发异常的方法:{5}");
            sb.AppendLine("引发异常的代码行号:{6}");
            sb.AppendLine("引发异常实例:{7}");
            string errMsg = string.Format(sb.ToString()
                , ex.GetType().Name
                , ex.Message + Environment.NewLine + ex.StackTrace
                , ex.TargetSite
                , ex.Source
                , className
                , functionName
                , lineNumber
                , ex.InnerException==null?"":ex.InnerException.Message);
            Write("error", errMsg);
        }

        public static void Error(string errorMsg)
        {
            string stackTrace = GetStackTrace();
            StringBuilder sb = new StringBuilder(stackTrace);
            sb.AppendLine("错误信息:" + Environment.NewLine + errorMsg + Environment.NewLine);
            Write("error", sb.ToString());
        }
        #endregion
    }
}
