using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;

namespace Websocket.Client.Logging.LogProviders
{
	internal class Class6 : LogProviderBase
	{
		public Class6()
		{
			if (!Class6.IsLoggerAvailable())
			{
				throw new LibLogException("log4net.LogManager not found");
			}
			this._getLoggerByNameDelegate = Class6.GetGetLoggerMethodCall();
		}

		public static bool ProviderIsAvailableOverride { get; set; } = true;

		public override Logger GetLogger(string name)
		{
			return new Logger(new Class6.Log4NetLogger(this._getLoggerByNameDelegate(name)).Log);
		}

		internal static bool IsLoggerAvailable()
		{
			return Class6.<ProviderIsAvailableOverride>k__BackingField && Class6.GetLogManagerType() != null;
		}

		protected override LogProviderBase.OpenNdc GetOpenNdcMethod()
		{
			PropertyInfo property = LogProviderBase.FindType("log4net.LogicalThreadContext", "log4net").GetProperty("Stacks");
			PropertyInfo property2 = property.PropertyType.GetProperty("Item");
			MethodInfo method = property2.PropertyType.GetMethod("Push");
			ParameterExpression parameterExpression;
			return Expression.Lambda<LogProviderBase.OpenNdc>(Expression.Call(Expression.Property(Expression.Property(null, property), property2, new Expression[] { Expression.Constant("NDC") }), method, new Expression[] { parameterExpression }), new ParameterExpression[] { parameterExpression }).Compile();
		}

		protected override LogProviderBase.OpenMdc GetOpenMdcMethod()
		{
			PropertyInfo property = LogProviderBase.FindType("log4net.LogicalThreadContext", "log4net").GetProperty("Properties");
			Type propertyType = property.PropertyType;
			PropertyInfo property2 = propertyType.GetProperty("Item");
			MethodInfo method = propertyType.GetMethod("Remove");
			ParameterExpression parameterExpression = Expression.Parameter(typeof(string), "key");
			ParameterExpression parameterExpression2 = Expression.Parameter(typeof(string), "value");
			MemberExpression memberExpression = Expression.Property(null, property);
			BinaryExpression binaryExpression = Expression.Assign(Expression.Property(memberExpression, property2, new Expression[] { parameterExpression }), parameterExpression2);
			MethodCallExpression methodCallExpression = Expression.Call(memberExpression, method, new Expression[] { parameterExpression });
			Action<string, string> set = Expression.Lambda<Action<string, string>>(binaryExpression, new ParameterExpression[] { parameterExpression, parameterExpression2 }).Compile();
			Action<string> remove = Expression.Lambda<Action<string>>(methodCallExpression, new ParameterExpression[] { parameterExpression }).Compile();
			return delegate(string key, object value, bool _)
			{
				set(key, value.ToString());
				return new DisposableAction(delegate
				{
					remove(key);
				});
			};
		}

		private static Type GetLogManagerType()
		{
			return LogProviderBase.FindType("log4net.LogManager", "log4net");
		}

		private static Func<string, object> GetGetLoggerMethodCall()
		{
			Type logManagerType = Class6.GetLogManagerType();
			Assembly log4netAssembly = Assembly.GetAssembly(logManagerType);
			MethodInfo method = logManagerType.GetMethod("GetLogger", new Type[]
			{
				typeof(Assembly),
				typeof(string)
			});
			ParameterExpression parameterExpression = Expression.Parameter(typeof(Assembly), "repositoryAssembly");
			ParameterExpression parameterExpression2 = Expression.Parameter(typeof(string), "name");
			MethodCallExpression methodCallExpression = Expression.Call(null, method, parameterExpression, parameterExpression2);
			Func<Assembly, string, object> lambda = Expression.Lambda<Func<Assembly, string, object>>(methodCallExpression, new ParameterExpression[] { parameterExpression, parameterExpression2 }).Compile();
			return (string name) => lambda(log4netAssembly, name);
		}

		private readonly Func<string, object> _getLoggerByNameDelegate;

		internal class Log4NetLogger
		{
			internal Log4NetLogger(object logger)
			{
				this._logger = logger.GetType().GetProperty("Logger").GetValue(logger);
			}

			private static bool Initialize()
			{
				bool flag;
				try
				{
					Type type = LogProviderBase.FindType("log4net.Core.Level", "log4net");
					if (type == null)
					{
						throw new LibLogException("Type log4net.Core.Level was not found.");
					}
					List<FieldInfo> list = type.GetFields().ToList<FieldInfo>();
					Class6.Log4NetLogger.s_levelAll = list.First((FieldInfo x) => x.Name == "All").GetValue(null);
					Class6.Log4NetLogger.s_levelDebug = list.First((FieldInfo x) => x.Name == "Debug").GetValue(null);
					Class6.Log4NetLogger.s_levelInfo = list.First((FieldInfo x) => x.Name == "Info").GetValue(null);
					Class6.Log4NetLogger.s_levelWarn = list.First((FieldInfo x) => x.Name == "Warn").GetValue(null);
					Class6.Log4NetLogger.s_levelError = list.First((FieldInfo x) => x.Name == "Error").GetValue(null);
					Class6.Log4NetLogger.s_levelFatal = list.First((FieldInfo x) => x.Name == "Fatal").GetValue(null);
					Type type2 = LogProviderBase.FindType("log4net.Core.ILogger", "log4net");
					if (type2 == null)
					{
						throw new LibLogException("Type log4net.Core.ILogger, was not found.");
					}
					ParameterExpression parameterExpression = Expression.Parameter(typeof(object));
					UnaryExpression unaryExpression = Expression.Convert(parameterExpression, type2);
					ParameterExpression parameterExpression2 = Expression.Parameter(typeof(object));
					UnaryExpression unaryExpression2 = Expression.Convert(parameterExpression2, type);
					Class6.Log4NetLogger.s_isEnabledForDelegate = Class6.Log4NetLogger.GetIsEnabledFor(type2, type, unaryExpression, unaryExpression2, parameterExpression, parameterExpression2);
					Type type3 = LogProviderBase.FindType("log4net.Core.LoggingEvent", "log4net");
					Class6.Log4NetLogger.s_createLoggingEvent = Class6.Log4NetLogger.GetCreateLoggingEvent(parameterExpression, unaryExpression, parameterExpression2, unaryExpression2, type3);
					Class6.Log4NetLogger.s_logDelegate = Class6.Log4NetLogger.GetLogDelegate(type2, type3, unaryExpression, parameterExpression);
					Class6.Log4NetLogger.s_loggingEventPropertySetter = Class6.Log4NetLogger.GetLoggingEventPropertySetter(type3);
					return true;
				}
				catch (Exception ex)
				{
					Class6.Log4NetLogger.s_initializeException = ex;
					flag = false;
				}
				return flag;
			}

			private static Action<object, object> GetLogDelegate(Type loggerType, Type loggingEventType, object instanceCast, object instanceParam)
			{
				MethodInfo method = loggerType.GetMethod("Log", new Type[] { loggingEventType });
				ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "loggingEvent");
				UnaryExpression unaryExpression = Expression.Convert(parameterExpression, loggingEventType);
				return Expression.Lambda<Action<object, object>>(Expression.Call(instanceCast, method, new Expression[] { unaryExpression }), new ParameterExpression[] { instanceParam, parameterExpression }).Compile();
			}

			private static Func<object, Type, object, string, Exception, object> GetCreateLoggingEvent(object instanceParam, object instanceCast, object levelParam, object levelCast, Type loggingEventType)
			{
				ParameterExpression parameterExpression = Expression.Parameter(typeof(Type));
				ParameterExpression parameterExpression2 = Expression.Parameter(typeof(string));
				ParameterExpression parameterExpression3 = Expression.Parameter(typeof(Exception));
				PropertyInfo property = loggingEventType.GetProperty("Repository");
				PropertyInfo property2 = loggingEventType.GetProperty("Level");
				return Expression.Lambda<Func<object, Type, object, string, Exception, object>>(Expression.New(loggingEventType.GetConstructorPortable(new Type[]
				{
					typeof(Type),
					property.PropertyType,
					typeof(string),
					property2.PropertyType,
					typeof(object),
					typeof(Exception)
				}), new Expression[]
				{
					parameterExpression,
					Expression.Property(instanceCast, "Repository"),
					Expression.Property(instanceCast, "Name"),
					levelCast,
					parameterExpression2,
					parameterExpression3
				}), new ParameterExpression[] { instanceParam, parameterExpression, levelParam, parameterExpression2, parameterExpression3 }).Compile();
			}

			private static Func<object, object, bool> GetIsEnabledFor(Type loggerType, Type logEventLevelType, object instanceCast, object levelCast, object instanceParam, object levelParam)
			{
				MethodInfo method = loggerType.GetMethod("IsEnabledFor", new Type[] { logEventLevelType });
				return Expression.Lambda<Func<object, object, bool>>(Expression.Call(instanceCast, method, new Expression[] { levelCast }), new ParameterExpression[] { instanceParam, levelParam }).Compile();
			}

			private static Action<object, string, object> GetLoggingEventPropertySetter(Type loggingEventType)
			{
				ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "loggingEvent");
				ParameterExpression parameterExpression2 = Expression.Parameter(typeof(string), "key");
				ParameterExpression parameterExpression3 = Expression.Parameter(typeof(object), "value");
				PropertyInfo property = loggingEventType.GetProperty("Properties");
				PropertyInfo property2 = property.PropertyType.GetProperty("Item");
				return Expression.Lambda<Action<object, string, object>>(Expression.Assign(Expression.Property(Expression.Property(Expression.Convert(parameterExpression, loggingEventType), property), property2, new Expression[] { parameterExpression2 }), parameterExpression3), new ParameterExpression[] { parameterExpression, parameterExpression2, parameterExpression3 }).Compile();
			}

			public bool Log(LogLevel logLevel, Func<string> messageFunc, Exception exception, params object[] formatParameters)
			{
				if (!Class6.Log4NetLogger.Initialized.Value)
				{
					throw new LibLogException("Unable to log due to problem initializing the log provider. See inner exception for details.", Class6.Log4NetLogger.s_initializeException);
				}
				if (messageFunc == null)
				{
					return this.IsLogLevelEnable(logLevel);
				}
				if (!this.IsLogLevelEnable(logLevel))
				{
					return false;
				}
				IEnumerable<string> enumerable;
				string text = LogMessageFormatter.FormatStructuredMessage(messageFunc(), formatParameters, out enumerable);
				Type type = typeof(Class6.Log4NetLogger);
				Type declaringType = messageFunc.Method.DeclaringType;
				if (!(declaringType == typeof(LogExtensions)) && (!(declaringType != null) || !(declaringType.DeclaringType == typeof(LogExtensions))))
				{
					if (declaringType == typeof(LoggerExecutionWrapper) || (declaringType != null && declaringType.DeclaringType == typeof(LoggerExecutionWrapper)))
					{
						type = typeof(LoggerExecutionWrapper);
					}
				}
				else
				{
					type = typeof(LogExtensions);
				}
				object obj = this.TranslateLevel(logLevel);
				object obj2 = Class6.Log4NetLogger.s_createLoggingEvent(this._logger, type, obj, text, exception);
				this.PopulateProperties(obj2, enumerable, formatParameters);
				Class6.Log4NetLogger.s_logDelegate(this._logger, obj2);
				return true;
			}

			private void PopulateProperties(object loggingEvent, IEnumerable<string> patternMatches, IEnumerable<object> formatParameters)
			{
				string[] array = (patternMatches as string[]) ?? patternMatches.ToArray<string>();
				if (array.Any<string>())
				{
					foreach (KeyValuePair<string, object> keyValuePair in array.Zip(formatParameters, (string key, object value) => new KeyValuePair<string, object>(key, value)))
					{
						Class6.Log4NetLogger.s_loggingEventPropertySetter(loggingEvent, keyValuePair.Key, keyValuePair.Value);
					}
				}
			}

			private bool IsLogLevelEnable(LogLevel logLevel)
			{
				object obj = this.TranslateLevel(logLevel);
				return Class6.Log4NetLogger.s_isEnabledForDelegate(this._logger, obj);
			}

			private object TranslateLevel(LogLevel logLevel)
			{
				switch (logLevel)
				{
				case LogLevel.Trace:
					return Class6.Log4NetLogger.s_levelAll;
				case LogLevel.Debug:
					return Class6.Log4NetLogger.s_levelDebug;
				case LogLevel.Info:
					return Class6.Log4NetLogger.s_levelInfo;
				case LogLevel.Warn:
					return Class6.Log4NetLogger.s_levelWarn;
				case LogLevel.Error:
					return Class6.Log4NetLogger.s_levelError;
				case LogLevel.Fatal:
					return Class6.Log4NetLogger.s_levelFatal;
				default:
					throw new ArgumentOutOfRangeException("logLevel", logLevel, null);
				}
			}

			private static object s_levelAll;

			private static object s_levelDebug;

			private static object s_levelInfo;

			private static object s_levelWarn;

			private static object s_levelError;

			private static object s_levelFatal;

			private static Func<object, object, bool> s_isEnabledForDelegate;

			private static Action<object, object> s_logDelegate;

			private static Func<object, Type, object, string, Exception, object> s_createLoggingEvent;

			private static Action<object, string, object> s_loggingEventPropertySetter;

			private static readonly Lazy<bool> Initialized = new Lazy<bool>(new Func<bool>(Class6.Log4NetLogger.Initialize), LazyThreadSafetyMode.ExecutionAndPublication);

			private static Exception s_initializeException;

			private readonly object _logger;
		}
	}
}
