using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using Decal.Adapter.Support;
using Decal.Interop.Core;
using Decal.Interop.Render;

namespace Decal.Adapter.Wrappers;

[CLSCompliant(true)]
public class HudRenderTarget : MarshalByRefObject, IDisposable
{
	private IRenderTarget myTarget;

	private bool isDisposed;

	private Rectangle areaRect;

	private bool inRender;

	private bool inText;

	public bool Lost => myTarget.Lost;

	[EditorBrowsable(EditorBrowsableState.Never)]
	public Rectangle Constraint
	{
		get
		{
			Rectangle region = Region;
			return new Rectangle(0, 0, region.Width, region.Height);
		}
	}

	public Rectangle Region
	{
		get
		{
			return Util.toRectangle(myTarget.Region);
		}
		set
		{
			tagRECT pVal = Util.toTagRECT(value);
			myTarget.Region = ref pVal;
			areaRect.Width = value.Width;
			areaRect.Height = value.Height;
		}
	}

	[EditorBrowsable(EditorBrowsableState.Never)]
	public object UnsafeSurface => myTarget.GetSurface();

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public tagRECT UnsafeRegion
	{
		get
		{
			return myTarget.Region;
		}
		set
		{
			myTarget.Region = ref value;
		}
	}

	protected bool IsDisposed => isDisposed;

	[CLSCompliant(false)]
	protected HudRenderTarget(IRenderTarget newTarget)
	{
		if (newTarget == null)
		{
			throw new ArgumentNullException("newTarget");
		}
		myTarget = newTarget;
		tagRECT region = myTarget.Region;
		areaRect = new Rectangle(0, 0, region.right - region.left, region.bottom - region.top);
	}

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

	/// <summary>
	/// Begin rendering to this object, must be paired with EndRender
	/// </summary>
	public void BeginRender()
	{
		BeginRender(enableTextureFilter: false);
	}

	/// <summary>
	/// Begin rendering to this object, must be paired with EndRender
	/// </summary>
	/// <param name="enableTextureFilter">True to enable texture filtering during rendering</param>
	public void BeginRender(bool enableTextureFilter)
	{
		if (!inRender)
		{
			myTarget.BeginRender(enableTextureFilter);
			inRender = true;
			return;
		}
		throw new RenderViolationException("Cannot call 'BeginRender' when already rendering");
	}

	/// <summary>
	/// End rendering to this object, must be paired with BeginRender
	/// </summary>
	public void EndRender()
	{
		if (inRender)
		{
			myTarget.EndRender();
			inRender = false;
			return;
		}
		throw new RenderViolationException("Cannot call 'EndRender' without a previous call to 'BeginRender'");
	}

	/// <summary>
	/// Begin writing text
	/// </summary>
	/// <param name="fontName">Name of the font to use for writing text</param>
	/// <param name="pixelHeight">Height in pixels to use when writing text</param>
	public void BeginText(string fontName, int pixelHeight)
	{
		BeginText(fontName, pixelHeight, FontWeight.Normal, italic: false);
	}

	/// <summary>
	/// Begin writing text
	/// </summary>
	/// <param name="fontName">Name of the font to use for writing text</param>
	/// <param name="pixelHeight">Height in pixels to use when writing text</param>
	/// <param name="weight">Bold, Strong, etc, indicator for text to be written</param>
	/// <param name="italic">Write text in italics?</param>
	public void BeginText(string fontName, int pixelHeight, FontWeight weight, bool italic)
	{
		UnsafeBeginText(fontName, pixelHeight, (int)weight, italic);
	}

	/// <summary>
	/// Display text,using the full rectangle of the render target as the area.
	/// This overload will draw the text in black. 
	/// </summary>
	/// <param name="text">Text to display</param>
	public void WriteText(string text)
	{
		WriteText(text, Color.Black, WriteTextFormats.None, areaRect);
	}

	/// <summary>
	/// Display text,using the full rectangle of the render target as the area.
	/// </summary>
	/// <param name="text">Text to display</param>
	/// <param name="color">Color to use to display the text. (Including alpha channel)</param>
	public void WriteText(string text, Color color)
	{
		WriteText(text, color, WriteTextFormats.None, areaRect);
	}

	/// <summary>
	/// Display text,using the full rectangle of the render target as the area.
	/// </summary>
	/// <param name="text">Text to display</param>
	/// <param name="color">Color to use to display the text. (Including alpha channel)</param>
	/// <param name="format">Format specifiers, including centered, etc.</param>
	/// <param name="region">Rectangle relative to this object to use to bound the text</param>
	public void WriteText(string text, Color color, WriteTextFormats format, Rectangle region)
	{
		UnsafeWriteText(Util.toTagRECT(region), color.ToArgb(), (int)format, text);
	}

	/// <summary>
	/// Display text,using the full rectangle of the render target as the area.
	/// </summary>
	/// <param name="text">Text to display</param>
	/// <param name="color">Color to use to display the text. (Including alpha channel)</param>
	/// <param name="format">Format specifiers, including centered, etc.</param>
	/// <param name="region">Rectangle relative to this object to use to bound the text</param>
	public void WriteText(string text, int color, WriteTextFormats format, Rectangle region)
	{
		UnsafeWriteText(Util.toTagRECT(region), color, (int)format, text);
	}

	/// <summary>
	/// End drawing of text. 
	/// </summary>
	public void EndText()
	{
		if (inRender && inText)
		{
			myTarget.EndText();
			inText = false;
			return;
		}
		throw new RenderViolationException("Cannot call 'EndText' without a previous call to 'BeginText'");
	}

	public void Clear()
	{
		Clear(areaRect);
	}

	public void Clear(Rectangle clearArea)
	{
		UnsafeClear(Util.toTagRECT(clearArea));
	}

	public void DrawPortalImage(int portalFile, Rectangle destinationArea)
	{
		UnsafeDrawPortalImage(portalFile, Util.toTagRECT(destinationArea));
	}

	public void DrawPortalImage(int portalFile, int alpha, Rectangle srcArea, Rectangle destinationArea)
	{
		UnsafeDrawPortalImage(portalFile, alpha, Util.toTagRECT(srcArea), Util.toTagRECT(destinationArea));
	}

	public void DrawPortalImage(int portalFile, Rectangle srcArea, Rectangle destinationArea)
	{
		UnsafeDrawPortalImage(portalFile, 255, Util.toTagRECT(srcArea), Util.toTagRECT(destinationArea));
	}

	public void TilePortalImage(int portalFile, Rectangle destinationArea)
	{
		UnsafeTilePortalImage(portalFile, Util.toTagRECT(destinationArea));
	}

	public void TilePortalImage(int portalFile, Rectangle srcArea, Rectangle destinationArea)
	{
		UnsafeTilePortalImage(portalFile, Util.toTagRECT(srcArea), Util.toTagRECT(destinationArea));
	}

	public void DrawImage(Image image, Rectangle destinationRegion)
	{
		DrawImage(image, destinationRegion, Color.Cyan.ToArgb());
	}

	public void DrawImage(Image image, Rectangle destinationRegion, Color colorKey)
	{
		DrawImage(image, destinationRegion, colorKey.ToArgb());
	}

	public void DrawImage(Image image, Rectangle destinationRegion, int colorKey)
	{
		if (image == null)
		{
			throw new ArgumentNullException("image");
		}
		MemoryStream memoryStream = new MemoryStream();
		image.Save(memoryStream, ImageFormat.Bmp);
		byte[] buffer = memoryStream.GetBuffer();
		IntPtr zero = IntPtr.Zero;
		int num = buffer.Length;
		zero = Marshal.AllocCoTaskMem(num);
		try
		{
			Marshal.Copy(buffer, 0, zero, num);
			if (zero != IntPtr.Zero)
			{
				UnsafeDrawImage(zero, num, Util.toTagRECT(destinationRegion), colorKey);
			}
		}
		finally
		{
			Marshal.FreeCoTaskMem(zero);
			memoryStream.Dispose();
		}
	}

	public void Fill(Color color)
	{
		Fill(areaRect, color);
	}

	public void Fill(Rectangle fillArea, Color color)
	{
		Fill(fillArea, color.ToArgb());
	}

	public void Fill(Rectangle fillArea, int color)
	{
		UnsafeFill(Util.toTagRECT(fillArea), color);
	}

	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeBeginText(string fontName, int pixelHeight, int weight, bool italic)
	{
		if (inRender && !inText)
		{
			myTarget.BeginText(fontName, pixelHeight, weight, italic);
			inText = true;
			return;
		}
		if (inRender && inText)
		{
			throw new RenderViolationException("Cannot call 'BeginText' when already rendering text");
		}
		throw new RenderViolationException("Cannot call 'BeginText' outside of a BeginRender/EndRender block");
	}

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeWriteText(tagRECT region, int color, int format, string text)
	{
		if (inRender && inText)
		{
			myTarget.WriteText(ref region, color, format, text);
			return;
		}
		throw new RenderViolationException("Cannot call 'WriteText' outside of a BeginText/EndText block");
	}

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeClear(tagRECT clearArea)
	{
		if (!inRender)
		{
			myTarget.Clear(ref clearArea);
			return;
		}
		throw new RenderViolationException("MUST call 'Clear' outside of a BeginRender/EndRender block");
	}

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeDrawPortalImage(int portalFile, tagRECT destinationArea)
	{
		if (inRender)
		{
			myTarget.DrawPortalImage(portalFile, ref destinationArea);
			return;
		}
		throw new RenderViolationException("Cannot call 'DrawPortalImage' outside of a BeginRender/EndRender block");
	}

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeDrawPortalImage(int portalFile, int alpha, tagRECT srcArea, tagRECT destinationArea)
	{
		if (inRender)
		{
			myTarget.DrawPortalImageEx(portalFile, alpha, ref srcArea, ref destinationArea);
			return;
		}
		throw new RenderViolationException("Cannot call 'DrawPortalImageEx' outside of a BeginRender/EndRender block");
	}

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeTilePortalImage(int portalFile, tagRECT destinationArea)
	{
		if (inRender)
		{
			myTarget.TilePortalImage(portalFile, ref destinationArea);
			return;
		}
		throw new RenderViolationException("Cannot call 'TilePortalImage' outside of a BeginRender/EndRender block");
	}

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeTilePortalImage(int portalFile, tagRECT srcArea, tagRECT destinationArea)
	{
		if (inRender)
		{
			myTarget.TilePortalImageEx(portalFile, ref srcArea, ref destinationArea);
			return;
		}
		throw new RenderViolationException("Cannot call 'TilePortalImageEx' outside of a BeginRender/EndRender block");
	}

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeDrawImage(IntPtr buffer, int size, tagRECT destinationRegion, int colorKey)
	{
		if (inRender)
		{
			myTarget.DrawImage((int)buffer, size, ref destinationRegion, colorKey);
			return;
		}
		throw new RenderViolationException("Cannot call 'DrawImage' outside of a BeginRender/EndRender block");
	}

	[CLSCompliant(false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeFill(tagRECT fillArea, int color)
	{
		if (!inRender)
		{
			myTarget.Fill(ref fillArea, color);
			return;
		}
		throw new RenderViolationException("MUST call 'Fill' outside of a BeginRender/EndRender block");
	}

	[EditorBrowsable(EditorBrowsableState.Never)]
	public void UnsafeSetSurface(object pSurface)
	{
		myTarget.SetSurface(pSurface);
	}

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

	protected virtual void Dispose(bool disposing)
	{
		if (!isDisposed)
		{
		}
		if (myTarget != null)
		{
			Marshal.ReleaseComObject(myTarget);
		}
		myTarget = null;
		isDisposed = true;
	}
}
