using System;
using System.Runtime.InteropServices;

namespace DMX2
{
	public static partial class AlsaSeqLib
	{
		class SeqHandleWrapper : IDisposable
		{
			IntPtr _seq = IntPtr.Zero;

			public IntPtr Handle {
				get {
					return _seq;
				}
			}

			public SeqHandleWrapper ()
			{
				Invoke.snd_seq_open (out _seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
				Invoke.snd_seq_set_client_name (_seq, "Loupiottes");
			}

			~SeqHandleWrapper ()
			{
				Dispose ();
			}			
			#region IDisposable implementation
			public void Dispose ()
			{
				if (_seq != IntPtr.Zero) {
					Invoke.snd_seq_close (_seq);
				}
				_seq = IntPtr.Zero;
			}
			#endregion

		}

		internal class PointerWrapper : IDisposable
		{
			public IntPtr Pointer { get; private set; }

			public PointerWrapper (int pointerSize)
			{
				Pointer = Marshal.AllocHGlobal (pointerSize);
			}

			public PointerWrapper (IntPtr ptr)
			{
				Pointer = ptr;
			}

			~PointerWrapper ()
			{
				Dispose (false);
			}

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

			protected virtual void Dispose (bool disposing)
			{	
				if (Pointer != IntPtr.Zero) {
					Marshal.FreeHGlobal (Pointer);
				}
			}
		}
		public static snd_seq_addr_t PtrToSndSeqAddr (this IntPtr ptr)
		{
			try {
				return (snd_seq_addr_t)Marshal.PtrToStructure (
							ptr,
							typeof(snd_seq_addr_t)
				);
			} catch (Exception e) {
#if DEBUG
Console.WriteLine (e.Message);
#endif
				return new snd_seq_addr_t ();
			}
		}

		public static IntPtr SndSeqAddrToPtr (this snd_seq_addr_t addr)
		{
			IntPtr ptr = typeof(snd_seq_addr_t).Malloc ();
			Marshal.StructureToPtr (addr, ptr, false);
			return ptr;
		}

		static IntPtr Malloc (this Type type)
		{
			return Marshal.AllocHGlobal (Marshal.SizeOf (type));
		}

		public static string PtrToString (this IntPtr p)
		{
			if (p == IntPtr.Zero) {
				return null;
			}
			return Marshal.PtrToStringAnsi (p);
		}

	}
}