/********************************************************************
	created:	2017/11/6
	author:		LuoJiEn
	purpose:    Interface of the global singleton log system.
*********************************************************************/
//#if UNITY_IOS || UNITY_ANDROID
//#define DISABLE_LOG_TO_FILE 
//#endif
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using Giant.Common;
using Giant.Resource;
using UnityEngine;

namespace Giant
{
    /// List all categories of log messages.
    public enum LogCategory
    {
        System,
        Framework,
        AI,
        Animation,
        Audio,
        GameLogic,
        Graphics,
        GUI,
        Input,
        Network,
        Particle,
        Physics,
        MeshBaker,
        ModelBuilder,
        Profile,
        AutoTest,
        ResourceWarmUp,
        WeTest,
        NetSync,
        All,
        Guide,
        Weather,
    }

    public static class ILogSystem
    {
        /// <summary>
        ///  close log flag
        /// </summary>
        static public bool CloseLog = false;
        // a StringWriter for writing information to a string
        static private StringWriter m_stringWriter;

        // a File Stream Writer for writing information to an external log file
        static private StreamWriter m_fileWriter = null;

        static private string m_filePath;

        static private string[] m_logCategoryString =
        {
            "System",
            "Framework",
            "AI",
            "Animation",
            "Audio",
            "GameLogic",
            "Graphics",
            "GUI",
            "Input",
            "Network",
            "Particle",
            "Physics",
            "MeshBaker",
            "ModelBuilder",
            "Profile",
            "AutoTest",
            "ResourceWarmUp",
            "WeTest",
            "NetSync",
            "All",
            "Guide",
            "Weather"
        };

        static private string[] m_logTypeString =
        {
            "Error",
            "Assert",
            "Warning",
            "Log",
            "Exception",
        };

        static DbtLogHandler logHandler;

        static public void DoStart(string bundleVersion)
        {
            if (Application.isBatchMode)
                return;
            logHandler = new DbtLogHandler();
            Application.logMessageReceivedThreaded += LogCallback;
            InitBugly(bundleVersion);

            RuntimePlatform platform = Application.platform;
           
            string strDirPath = GetLogPath(platform);
            if (!Directory.Exists(strDirPath))
            {
                Directory.CreateDirectory(strDirPath);
            }
            m_filePath = GiantUtilities.BuildString(GetLogPath(platform), "/log_output.txt");
            string m_fileoldpath = GetLogPath(Application.platform) + "/log_output_old.txt";
            if (!File.Exists(m_fileoldpath)){

                File.Create(m_fileoldpath);
            }
            

            if (File.Exists(m_filePath))
            {
                File.Replace(GetLogPath(Application.platform) + "/log_output.txt", m_fileoldpath, GetLogPath(Application.platform) + "/log_output_del.txt");
                
            }
            if (File.Exists(GetLogPath(Application.platform) + "/log_output_del.txt"))
            {
                File.Delete(GetLogPath(Application.platform) + "/log_output_del.txt");
            }
            m_stringWriter = new StringWriter();
            try
            {
                m_fileWriter = new StreamWriter(m_filePath, false);
            }
            catch
            {
                UnityEngine.Debug.LogError("log stream writer create failed!");
            }           
        }




        [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
        static private string GetLogCategoryString(LogCategory category)
        {
            return m_logCategoryString[(int)category];
        }

        [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
        static private string GetLogTypeString(LogType logtype)
        {
            return m_logTypeString[(int)logtype];
        }

        /// Called when the instance will be destroyed.
        static public void DoDestroy()
        {
            DestoryBugly();
            Flush();
            // close the stream writers
            if (null != m_stringWriter)
                m_stringWriter.Close();
            if (null != m_fileWriter)
                m_fileWriter.Close();
            m_stringWriter = null;
            m_fileWriter = null;

            Application.logMessageReceivedThreaded -= LogCallback;
        }

        /// Log a message.
        /// <param name="category"> the log message belonged to which log category.</param>
        /// <param name="logType">  the type of the log message.
        ///                         Error: 	   LogType used for Debug.LogError.
        ///                         Assert:    LogType used for Asserts (This indicate an error inside Utity itself), namely Debug.LogError.
        ///                         Warning:   LogType used for Debug.LogWarning.
        ///                         Log:       LogType used for regular log messages, Debug.Log.
        ///                         Exception: LogType used for Debug.LogException. </param>  
        /// <param name="msg">      message to log.</param>
        static public void Log(LogCategory category, string msg, UnityEngine.LogType logType)
        {
            if (!CloseLog)
            {
                string output = GiantUtilities.BuildString("[", GetLogCategoryString(category), "] ", msg);

                if (logType == LogType.Warning)
                {
                    UnityEngine.Debug.LogWarning(output);
                }
                else if (logType == LogType.Error)
                {
                    UnityEngine.Debug.LogError(output);
                }
                else if (logType == LogType.Log)
                {
                    UnityEngine.Debug.Log(output);
                }
                else if (logType == LogType.Exception)
                {
                    UnityEngine.Debug.LogException(new Exception(output));
                }             
            }
            

        }

        /// all implementations to dump logs to an external file.
        /// Get path to contain the log file.
        /// <param name="platform"> which platform to get the log file.</param>
        static public string GetLogPath(RuntimePlatform platform)
        {
            string filePath = string.Empty;
            switch (platform)
            {
#if UNITY_EDITOR
                case RuntimePlatform.WindowsEditor:
                case RuntimePlatform.OSXEditor:
                    // Environment.CurrentDirectory: "C:\Users\jeluo\AppData\LocalLow\DefaultCompany\DemoApp"
                    filePath = GiantUtilities.BuildFormatString("{0}/logs", Environment.CurrentDirectory);
                    break;
#endif
                case RuntimePlatform.WindowsPlayer:
                case RuntimePlatform.Android:
                case RuntimePlatform.IPhonePlayer:
                    // public directory on the device
                    filePath = IResourceLoader.persistentDataPath;
                    break;
            }
            return filePath;
        }

        /// Flush all logged messages to the external log file.
        //[Conditional("DEBUG")]
        static private void Flush()
        {
            
            // flush all logged messages to the external log file
            if (null != m_fileWriter)
            {
                if (null != m_stringWriter)
                {
                    m_fileWriter.WriteLine(m_stringWriter.ToString());
                    m_stringWriter.GetStringBuilder().Remove(0, m_stringWriter.ToString().Length);
                }
                m_fileWriter.Flush();
            }

        }

        /// A delegate to be called on log messages (otherwise, log messages will be routed to the Unity Console).
        /// <param name="msg">        message to log.</param>
        /// <param name="stackTrace"> call stack from the first caller to this Log method.</param>
        /// <param name="logType">    the type of the log message.
        ///                           Error: 	 LogType used for Debug.LogError.
        ///                           Assert:    LogType used for Asserts (This indicate an error inside Utity itself), namely Debug.LogError.
        ///                           Warning:   LogType used for Debug.LogWarning.
        ///                           Log:       LogType used for regular log messages, Debug.Log.
        ///                           Exception: LogType used for Debug.LogException. </param>  
        static private void LogCallback(string msg, string stackTrace, UnityEngine.LogType logType)
        {
            if (!string.IsNullOrEmpty(msg) && null != m_stringWriter)
            {
                if (!string.IsNullOrEmpty(stackTrace))
                {
                    msg = GiantUtilities.BuildString(msg, stackTrace);
                    msg = GiantUtilities.BuildString("[", getTime() , "]", "[" + logType.ToString(),"]",msg);
                }               
                m_stringWriter.WriteLine(msg);
            }
            Flush();
        }


        static string getTime()
        {
            return string.Format("{0:D2}:{1:D2}:{2:D2} " + "{3:D4}/{4:D2}/{5:D2}", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);

        }

        static void InitBugly(string bundleVersion)
        {
        LogUtils.LogWarning($"Application.version ={Application.version}");
        }

        static void DestoryBugly()
        {
        }

    }
}