using System;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Decal.Adapter.Support;
using Decal.Interop.Core;
using Decal.Interop.Inject;

namespace Decal.Adapter.Wrappers;

[CLSCompliant(true)]
public class ViewWrapper : MarshalByRefObject, IDisposable
{
	private View myView;

	private ViewControls myControls;

	private bool isDisposed;

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public View Underlying => myView;

	public bool Activated
	{
		get
		{
			return myView.Activated;
		}
		set
		{
			myView.Activated = value;
		}
	}

	public int Alpha
	{
		get
		{
			return myView.Alpha;
		}
		set
		{
			myView.Alpha = value;
		}
	}

	public string Title
	{
		get
		{
			return myView.Title;
		}
		set
		{
			myView.Title = value;
		}
	}

	public bool Transparent
	{
		get
		{
			return myView.Transparent;
		}
		set
		{
			myView.Transparent = value;
		}
	}

	[CLSCompliant(false)]
	public IControl this[string controlName]
	{
		get
		{
			return ((IView)myView).get_Control(controlName);
		}
		set
		{
			((IView)myView).set_Control(controlName, value);
		}
	}

	public ViewControls Controls => myControls;

	public Rectangle Position
	{
		get
		{
			return Util.toRectangle(myView.Position);
		}
		set
		{
			tagRECT pVal = Util.toTagRECT(value);
			myView.Position = ref pVal;
		}
	}

	internal ViewWrapper(View vw)
	{
		myView = vw;
		myControls = new ViewControls(this);
	}

	~ViewWrapper()
	{
		Dispose(disposing: false);
	}

	public void Dispose()
	{
		Dispose(disposing: true);
		GC.SuppressFinalize(this);
	}

	private void Dispose(bool disposing)
	{
		if (!isDisposed)
		{
		}
		if (myView != null)
		{
			myControls.Dispose();
			Marshal.ReleaseComObject(myView);
			myView = null;
		}
		isDisposed = true;
	}

	public void Activate()
	{
		myView.Activate();
	}

	public void Alert()
	{
		myView.Alert();
	}

	public void Deactivate()
	{
		myView.Deactivate();
	}

	[CLSCompliant(false)]
	public int LoadControl(Layer parent, int id, object xmlSource)
	{
		return myView.LoadControl(parent, id, xmlSource);
	}

	public void LoadSchema(string xmlSchema)
	{
		myView.LoadSchema(xmlSchema);
	}

	public void SetIcon(int icon, object iconLibrary)
	{
		myView.SetIcon(icon, iconLibrary);
	}

	/// <summary>
	/// Reads the class's view attributes and loads the requested views
	/// </summary>
	/// <param name="handler">handler to scan</param>
	/// <returns>True when views are created, False otherwise</returns>
	internal static bool ScanViews(IViewHandler handler)
	{
		Type type = handler.GetType();
		bool result = false;
		object[] customAttributes = type.GetCustomAttributes(typeof(ViewAttribute), inherit: false);
		foreach (object obj in customAttributes)
		{
			try
			{
				ViewAttribute viewAttribute = (ViewAttribute)obj;
				handler.LoadView(viewAttribute.ViewName, viewAttribute.Resource);
				result = true;
			}
			catch (Exception ex)
			{
				Util.WriteLine("ScanViews Exception: " + ex.Message);
			}
		}
		return result;
	}

	/// <summary>
	/// Reads the class for ControlEvents and hooks them up
	/// </summary>
	/// <param name="handler">handler to scan</param>
	internal static void ScanControls(IViewHandler handler)
	{
		MethodInfo[] methods = handler.GetType().GetMethods(handler.BindingFlags);
		foreach (MethodInfo methodInfo in methods)
		{
			object[] customAttributes = methodInfo.GetCustomAttributes(typeof(ControlEventAttribute), inherit: false);
			foreach (object obj in customAttributes)
			{
				try
				{
					ControlEventAttribute controlEventAttribute = (ControlEventAttribute)obj;
					IControlWrapper controlWrapper = handler.GetView(controlEventAttribute.ViewName).Controls[controlEventAttribute.Control];
					EventInfo eventInfo = controlWrapper.GetType().GetEvent(controlEventAttribute.EventName);
					eventInfo.AddEventHandler(controlWrapper, Delegate.CreateDelegate(eventInfo.EventHandlerType, handler, methodInfo.Name));
				}
				catch (Exception ex)
				{
					Util.WriteLine("ScanControls Exception: " + ex.Message);
				}
			}
		}
	}

	/// <summary>
	/// Reads the class for ControlReferences and adds them
	/// </summary>
	/// <param name="handler">handler to scan</param>
	internal static void ScanReferences(IViewHandler handler)
	{
		Type type = handler.GetType();
		Type typeFromHandle = typeof(AccessedThroughPropertyAttribute);
		Type typeFromHandle2 = typeof(ControlReferenceAttribute);
		Type typeFromHandle3 = typeof(ControlReferenceArrayAttribute);
		FieldInfo[] fields = type.GetFields(handler.BindingFlags);
		foreach (FieldInfo fieldInfo in fields)
		{
			try
			{
				IControlWrapper controlWrapper = null;
				if (!fieldInfo.FieldType.IsArray && Attribute.IsDefined(fieldInfo, typeFromHandle2))
				{
					ControlReferenceAttribute controlReferenceAttribute = (ControlReferenceAttribute)Attribute.GetCustomAttribute(fieldInfo, typeFromHandle2);
					controlWrapper = handler.GetView(controlReferenceAttribute.ViewName).Controls[controlReferenceAttribute.Control];
					if (!(controlWrapper.GetType() != fieldInfo.FieldType))
					{
						object value = Convert.ChangeType(controlWrapper, fieldInfo.FieldType);
						if (Attribute.IsDefined(fieldInfo, typeFromHandle))
						{
							AccessedThroughPropertyAttribute accessedThroughPropertyAttribute = (AccessedThroughPropertyAttribute)Attribute.GetCustomAttribute(fieldInfo, typeFromHandle);
							type.GetProperty(accessedThroughPropertyAttribute.PropertyName, handler.BindingFlags).SetValue(handler, value, null);
						}
						else
						{
							fieldInfo.SetValue(handler, value);
						}
					}
				}
				else
				{
					if (!Attribute.IsDefined(fieldInfo, typeFromHandle3))
					{
						continue;
					}
					ControlReferenceArrayAttribute controlReferenceArrayAttribute = (ControlReferenceArrayAttribute)Attribute.GetCustomAttribute(fieldInfo, typeFromHandle3);
					ViewWrapper view = handler.GetView(controlReferenceArrayAttribute.ViewName);
					Type elementType = fieldInfo.FieldType.GetElementType();
					Array array = Array.CreateInstance(elementType, controlReferenceArrayAttribute.Controls.Count);
					for (int j = 0; j < controlReferenceArrayAttribute.Controls.Count; j++)
					{
						controlWrapper = view.Controls[controlReferenceArrayAttribute.Controls[j]];
						if (elementType.IsAssignableFrom(controlWrapper.GetType()))
						{
							array.SetValue(controlWrapper, j);
						}
					}
					fieldInfo.SetValue(handler, array);
					continue;
				}
			}
			catch (Exception ex)
			{
				Util.WriteLine("ScanReferences Exception: " + ex.Message);
			}
		}
	}
}
