using CPF.Mac.Foundation;
using CPF.Mac.ObjCRuntime;
using System;
using System.Runtime.InteropServices;

namespace CPF.Mac.CoreGraphics
{
	public class CGPattern : INativeObject, IDisposable
	{
		public delegate void DrawPattern(CGContext ctx);

		internal IntPtr handle;

		private DrawPattern draw_pattern;

		private CGPatternCallbacks callbacks;

		private GCHandle gch;

		private IntPtr last_cgcontext_ptr;

		private WeakReference last_cgcontext;

		public IntPtr Handle => handle;

		public CGPattern(IntPtr handle)
		{
			this.handle = handle;
			CGPatternRetain(this.handle);
		}

		[Preserve(Conditional = true)]
		internal CGPattern(IntPtr handle, bool owns)
		{
			this.handle = handle;
			if (!owns)
			{
				CGPatternRetain(this.handle);
			}
		}

		[DllImport("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")]
		private static extern IntPtr CGPatternCreate(IntPtr info, CGRect bounds, CGAffineTransform matrix, double xStep, double yStep, CGPatternTiling tiling, bool isColored, ref CGPatternCallbacks callbacks);

		public CGPattern(CGRect bounds, CGAffineTransform matrix, double xStep, double yStep, CGPatternTiling tiling, bool isColored, DrawPattern drawPattern)
		{
			if (drawPattern == null)
			{
				throw new ArgumentNullException("drawPattern");
			}
			callbacks.draw = DrawCallback;
			callbacks.release = ReleaseCallback;
			callbacks.version = 0u;
			draw_pattern = drawPattern;
			gch = GCHandle.Alloc(this);
			handle = CGPatternCreate(GCHandle.ToIntPtr(gch), bounds, matrix, xStep, yStep, tiling, isColored, ref callbacks);
		}

		private static void DrawCallback(IntPtr voidptr, IntPtr cgcontextptr)
		{
			CGPattern cGPattern = (CGPattern)GCHandle.FromIntPtr(voidptr).Target;
			CGContext cGContext = null;
			if (cgcontextptr == cGPattern.last_cgcontext_ptr)
			{
				cGContext = (cGPattern.last_cgcontext.Target as CGContext);
			}
			if (cGContext == null)
			{
				cGContext = new CGContext(cgcontextptr);
				cGPattern.last_cgcontext = new WeakReference(cGContext);
				cGPattern.last_cgcontext_ptr = cgcontextptr;
			}
			cGPattern.draw_pattern(cGContext);
		}

		private static void ReleaseCallback(IntPtr voidptr)
		{
			GCHandle.FromIntPtr(voidptr).Free();
		}

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

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

		[DllImport("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")]
		private static extern void CGPatternRelease(IntPtr handle);

		[DllImport("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")]
		private static extern void CGPatternRetain(IntPtr handle);

		protected virtual void Dispose(bool disposing)
		{
			if (handle != IntPtr.Zero)
			{
				CGPatternRelease(handle);
				handle = IntPtr.Zero;
			}
			last_cgcontext = null;
		}
	}
}
