using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Decal.Adapter.Support;
using Decal.Interop.Core;
using Decal.Interop.Net;
using Microsoft.Win32;

namespace Decal.Adapter;

/// <summary>
///
/// </summary>
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IAdapterSurrogate))]
[ProgId("DecalAdapter.Surrogate")]
[Guid("71A69713-6593-47EC-0002-0000000DECA1")]
public sealed class Surrogate : MarshalByRefObject, IAdapterSurrogate, IDecalFileSurrogate
{
	private string myAssemblyName;

	private string myPath;

	private string myTypeName;

	string IAdapterSurrogate.Version
	{
		get
		{
			CoreManager current = CoreManager.Current;
			if (current == null)
			{
				current = CoreManager.Current;
			}
			if (File.Exists(Path.Combine(myPath, myAssemblyName)))
			{
				return FileVersionInfo.GetVersionInfo(Path.Combine(myPath, myAssemblyName)).FileVersion;
			}
			return "";
		}
	}

	bool IAdapterSurrogate.FileExists => File.Exists(Path.Combine(myPath, myAssemblyName));

	string IAdapterSurrogate.FilePath => Path.Combine(myPath, myAssemblyName);

	string IDecalFileSurrogate.Description => "Decal.Adapter Extension";

	string IDecalFileSurrogate.Extension => "dll";

	IntPtr IAdapterSurrogate.CreateInstance(DecalEnum pInitData, ref Guid riid)
	{
		if (CoreManager.ServiceRunning)
		{
			CoreManager current = CoreManager.Current;
			try
			{
				myTypeName = (string)((IDecalEnum)pInitData).get_Property("Object");
				myAssemblyName = (string)((IDecalEnum)pInitData).get_Property("Assembly");
				myPath = (string)((IDecalEnum)pInitData).get_Property("Path");
				Assembly assembly = ((!(pInitData.Group == "Plugins")) ? current.Assembly(myAssemblyName, myPath) : current.Assembly(myAssemblyName, myPath, current.PluginDomain));
				Type type = assembly.GetType(myTypeName);
				if (null == type)
				{
					throw new COMHResultException(HResults.E_FAIL);
				}
				IntPtr ppv;
				if (type.IsSubclassOf(typeof(Extension)))
				{
					Extension extension = ((!type.IsSubclassOf(typeof(PluginBase))) ? ((Extension)Activator.CreateInstance(type, null)) : ((Extension)current.PluginDomain.CreateInstanceFromAndUnwrap(Path.Combine(myPath, myAssemblyName), myTypeName)));
					extension.Path = myPath;
					object obj = null;
					switch (extension.ExtensionType)
					{
					case DecalExtensionType.Service:
						if (extension is ServiceBase serviceBase)
						{
							current.AddService(serviceBase);
							obj = new ServiceProxy(serviceBase);
						}
						break;
					case DecalExtensionType.NetworkFilter:
						if (extension is FilterBase filterBase)
						{
							current.AddFilter(filterBase);
							obj = new FilterProxy(filterBase);
						}
						break;
					case DecalExtensionType.Plugin:
						if (extension is PluginBase pluginBase)
						{
							current.AddPlugin(pluginBase);
							obj = new PluginProxy(pluginBase);
						}
						break;
					}
					IntPtr pUnk = ((obj == null) ? Marshal.GetIUnknownForObject(extension) : Marshal.GetIUnknownForObject(obj));
					int num = Marshal.QueryInterface(pUnk, ref riid, out ppv);
					Marshal.Release(pUnk);
					if (num < 0)
					{
						throw new Exception();
					}
					return ppv;
				}
				object o = Activator.CreateInstance(type, null);
				if (!type.IsSubclassOf(typeof(INetworkFilter)))
				{
					type.IsSubclassOf(typeof(INetworkFilter2));
				}
				IntPtr iUnknownForObject = Marshal.GetIUnknownForObject(o);
				Marshal.QueryInterface(iUnknownForObject, ref riid, out ppv);
				Marshal.Release(iUnknownForObject);
				return ppv;
			}
			catch
			{
				throw new COMHResultException(HResults.E_FAIL);
			}
			finally
			{
				Marshal.ReleaseComObject(pInitData);
			}
		}
		Marshal.ReleaseComObject(pInitData);
		throw new COMHResultException(HResults.E_FAIL);
	}

	void IAdapterSurrogate.SetEnum(DecalEnum pInitData)
	{
		try
		{
			myTypeName = (string)((IDecalEnum)pInitData).get_Property("Object");
			myAssemblyName = (string)((IDecalEnum)pInitData).get_Property("Assembly");
			myPath = (string)((IDecalEnum)pInitData).get_Property("Path");
			Marshal.ReleaseComObject(pInitData);
		}
		catch (COMException)
		{
		}
	}

	void IDecalFileSurrogate.Register(string Filename)
	{
		bool flag = false;
		int num = 0;
		int num2 = 0;
		try
		{
			if (File.Exists(Filename))
			{
				Assembly assembly = Assembly.LoadFile(Filename);
				string text = "";
				if (Attribute.IsDefined(assembly, typeof(GuidAttribute)))
				{
					text = ((GuidAttribute)Attribute.GetCustomAttribute(assembly, typeof(GuidAttribute))).Value.ToUpper(CultureInfo.InvariantCulture);
				}
				Type[] types;
				try
				{
					types = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					types = ex.Types;
				}
				Type[] array = types;
				foreach (Type type in array)
				{
					if (null == type || !type.IsPublic)
					{
						continue;
					}
					int num3 = 0;
					if (!type.IsSubclassOf(typeof(Extension)))
					{
						continue;
					}
					string directoryName = Path.GetDirectoryName(Filename);
					string fileName = Path.GetFileName(Filename);
					string value = "";
					string value2 = "{71A69713-6593-47EC-0002-0000000DECA1}";
					string text2 = "";
					if (type.IsSubclassOf(typeof(PluginBase)))
					{
						text2 = "Plugins";
						num++;
						num3 = num;
					}
					else
					{
						if (!type.IsSubclassOf(typeof(FilterBase)))
						{
							continue;
						}
						text2 = "NetworkFilters";
						num2++;
						num3 = num2;
					}
					if (Attribute.IsDefined(type, typeof(FriendlyNameAttribute)))
					{
						value = ((FriendlyNameAttribute)Attribute.GetCustomAttribute(type, typeof(FriendlyNameAttribute))).Name;
					}
					string text3 = type.Namespace.ToString() + "." + type.Name.ToString();
					string text4 = "";
					if (Attribute.IsDefined(type, typeof(GuidAttribute)))
					{
						text4 = ((GuidAttribute)Attribute.GetCustomAttribute(type, typeof(GuidAttribute))).Value.ToString();
					}
					else if (!string.IsNullOrEmpty(text) && num3 == 1)
					{
						text4 = text;
					}
					else if (!string.IsNullOrEmpty(text))
					{
						byte[] array2 = new Guid(text).ToByteArray();
						array2[15] = (byte)(array2[15] ^ num3);
						text4 = new Guid(array2).ToString();
					}
					else
					{
						text4 = Guid.NewGuid().ToString();
					}
					text4 = text4.ToUpper(CultureInfo.InvariantCulture);
					string subkey = string.Format("SOFTWARE\\Decal\\{0}\\{1}", text2, "{" + text4 + "}");
					Util.WriteLine("Registering Decal.Adapter extension (Type:" + type.ToString() + ")");
					Util.WriteLine("Assembly Directory: " + directoryName);
					Util.WriteLine("Assembly File: " + fileName);
					Util.WriteLine("Assembly Object: " + text3);
					Util.WriteLine("Extension Registry CLSID: " + text4);
					RegistryKey registryKey = Registry.LocalMachine.CreateSubKey(subkey);
					if (registryKey != null)
					{
						registryKey.SetValue("Enabled", 0, RegistryValueKind.DWord);
						registryKey.SetValue("Assembly", fileName, RegistryValueKind.String);
						registryKey.SetValue("Path", directoryName, RegistryValueKind.String);
						registryKey.SetValue("Object", text3, RegistryValueKind.String);
						registryKey.SetValue("Surrogate", value2, RegistryValueKind.String);
						if (!string.IsNullOrEmpty(value))
						{
							registryKey.SetValue("", value, RegistryValueKind.String);
						}
						else
						{
							registryKey.SetValue("", text3, RegistryValueKind.String);
						}
						flag = true;
					}
				}
			}
		}
		catch (Exception ex2)
		{
			Util.WriteLine("Exception registering plugin: " + ex2.ToString());
			throw new COMHResultException(HResults.E_FAIL);
		}
		if (!flag)
		{
			throw new COMHResultException(HResults.E_FAIL);
		}
	}
}
