using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace CommonLang.Log
{
    public class LoggerFactory
    {
        public static LoggerFactory CurrentFactory { get; private set; }
        static LoggerFactory()
        {
            CurrentFactory = new LoggerFactory();
        }
        public static void SetFactory(LoggerFactory factory)
        {
            CurrentFactory = factory;
        }
        public static Logger GetLogger(string name)
        {
            return CurrentFactory.CreateLogger(name);
        }

        private static Logger mDefaultLog = null;
        public static Logger GetDefLogger()
        {
            if(mDefaultLog == null)
            {
                mDefaultLog = GetLogger("logger");
            }
            return mDefaultLog;
        }

        virtual protected Logger CreateLogger(string name)
        {
            Logger logger = new ConsoleLogger();
            logger.SetName(name);
            return logger;
        }

        public static Logger Dummy { get { return new DummyLogger(); } }
        private class DummyLogger : Logger
        {
            protected override void Print(string text)
            {
            }
        }
    }

    public class LoggerLevel
    {
        //public const uint FINE = 0x00000001;
        public const uint DEBUG = 0x00000002;
        //public const uint TRACE = 0x00000004;
        //public const uint LOG = 0x00000008;
        public const uint INFO = 0x00000010;
        public const uint WARNNING = 0x00000020;
        public const uint ERROR = 0x00000040;
        //public const uint FATAL = 0x00000080;
        public const uint LIXU = 0x00000100;
    }

    public abstract class Logger
    {
        private uint mLevel = 0xFFFFFFFF;
        protected string mName = "Log - ";
        public uint Level { get { return mLevel; } }
        //---------------------------------------------------------------------------------------
        protected internal void SetName(string name)
        {
            mName = name;
        }
        //---------------------------------------------------------------------------------------
        public bool IsDebugEnabled { get { return (mLevel & LoggerLevel.DEBUG) != 0; } }
        public bool IsErrorEnabled { get { return (mLevel & LoggerLevel.ERROR) != 0; } }
        public bool IsInfoEnabled { get { return (mLevel & LoggerLevel.INFO) != 0; } }
        public bool IsWarnEnabled { get { return (mLevel & LoggerLevel.WARNNING) != 0; } }
        //---------------------------------------------------------------------------------------
        public void SetLevel(uint level)
        {
            mLevel = level;
        }
        public bool IsLevelEnable(uint level)
        {
            return ((level & mLevel) != 0);
           // return level >= mLevel;
        }
        //---------------------------------------------------------------------------------------

        public virtual void LogLevel(uint level, string msg, Exception err)
        {
            if (err != null)
            {
                Print(msg, err);
            }
            else
            {
                Print(msg);
            }
        }
        virtual protected void LogLevelInternal(uint level, object msg, object[] args, Exception exception)
        {
            if (IsLevelEnable(level))
            {
                string message = msg != null ? msg.ToString() : "null";
                if (args != null && args.Length > 0)
                {
                    message = string.Format(message, args);
                }
                LogLevel(level, message, exception);
            }
        }
        virtual protected void Print(string text)
        {
        }
        protected void Print(string text, Exception err)
        {
            Print(text + " : " + err.Message + "\r\n" + err.StackTrace);
        }
        //---------------------------------------------------------------------------------------
       
        public void Log(string msg)
        {
            LogLevelInternal(LoggerLevel.INFO, msg, null, null);
        }
        public void Info(string msg)
        {
            LogLevelInternal(LoggerLevel.INFO, msg, null, null);
        }
        public void Error(string msg)
        {
            LogLevelInternal(LoggerLevel.ERROR, msg, null, null);
        }
        public void Error(string msg, Exception err)
        {
            LogLevelInternal(LoggerLevel.ERROR, msg, null, err);
        }
        //---------------------------------------------------------------------------------------
        public void Debug(object message)
        {
            LogLevelInternal(LoggerLevel.DEBUG, message, null, null);
        }
        public void Debug(object message, Exception exception)
        {
            LogLevelInternal(LoggerLevel.DEBUG, message, null, exception);
        }
        public void DebugFormat(string format, params object[] args)
        {
            LogLevelInternal(LoggerLevel.DEBUG, format, args, null);
        }
        //---------------------------------------------------------------------------------------
        public void Error(object message)
        {
            LogLevelInternal(LoggerLevel.ERROR, message, null, null);
        }
        public void Error(object message, Exception exception)
        {
            LogLevelInternal(LoggerLevel.ERROR, message, null, exception);
        }
        public void ErrorFormat(string format, params object[] args)
        {
            LogLevelInternal(LoggerLevel.ERROR, format, args, null);
        }

        public void Info(object message)
        {
            LogLevelInternal(LoggerLevel.INFO, message, null, null);
        }
        public void Info(object message, Exception exception)
        {
            LogLevelInternal(LoggerLevel.INFO, message, null, exception);
        }
        public void InfoFormat(string format, params object[] args)
        {
            LogLevelInternal(LoggerLevel.INFO, format, args, null);
        }
        //---------------------------------------------------------------------------------------
        public void Warn(object message)
        {
            LogLevelInternal(LoggerLevel.WARNNING, message, null, null);
        }
        public void Warn(object message, Exception exception)
        {
            LogLevelInternal(LoggerLevel.WARNNING, message, null, exception);
        }
        public void WarnFormat(string format, params object[] args)
        {
            LogLevelInternal(LoggerLevel.WARNNING, format, args, null);
        }
        //---------------------------------------------------------------------------------------

        public void LogSelf(uint level, object message)
        {
            LogLevelInternal(level, message, null, null);
        }

    }

    public class BlankLogger : Logger
    {
        protected override void Print(string text)
        {
        }
    }

    public class TextWriterLogger : Logger
    {
        //private StreamWriter output;

        public TextWriterLogger(StreamWriter output, string name)
        {
            //this.output = output;
            //this.output.AutoFlush = true;
            //this.SetName(name);
        }

        protected override void Print(string text)
        {
            //output.WriteLine(mName + " - " + text);
        }
    }

    public class ConsoleLogger : Logger
    {
#if ClientOnly
        public override void LogLevel(uint level, string msg, Exception err)
        {
            if (err != null)
            {
                msg = msg + " : " + err.Message + "\r\n" + err.StackTrace;
            }

            if(level == LoggerLevel.ERROR)
            {
                YXJDebug.logError(msg);
            }
            else if(level == LoggerLevel.WARNNING)
            {
                YXJDebug.logWarning(msg);
            }
            else if(level == LoggerLevel.INFO)
            {
                YXJDebug.logInfo(msg);
            }
            else
            {
                YXJDebug.logDebug(msg);
            }
        }
#endif
    }

    public class ListLogger : Logger
    {
        public static bool EnableConsole = true;

        //private List<string> output = new List<string>();

        public ListLogger(string name)
        {
            this.SetName(name);
        }
        protected override void Print(string text)
        {
            //lock (output)
            //{
            //    output.Add(text);
            //    if (EnableConsole) Console.WriteLine(mName + " - " + text);
            //}
        }

        public void PopLogs(List<string> input)
        {
            //lock (output)
            //{
            //    input.AddRange(output);
            //    output.Clear();
            //}
        }
    }

    public class ClientLog
    {
#if ClientOnly
        private static Logger mLog = null;
#endif

        public static void Log(uint level, string msg, params object[] args)
        {
#if ClientOnly
            if (mLog == null)
            {
                mLog = LoggerFactory.GetLogger("Client");
            }
            if (args != null && args.Length > 0)
            {
                msg = string.Format(msg, args);
            }

            mLog.LogLevel(level, msg, null);
#endif
        }

        public static void LogError(string msg, params object[] args)
        {
            Log(LoggerLevel.ERROR, msg, args);
        }
        public static void LogWarning(string msg, params object[] args)
        {
            Log(LoggerLevel.WARNNING, msg, args);
        }
        public static void LogDebug(string msg, params object[] args)
        {
            Log(LoggerLevel.DEBUG, msg, args);
        }
        public static void LogInfo(string msg, params object[] args)
        {
            Log(LoggerLevel.INFO, msg, args);
        }
    }
}