using System;
using System.IO;
using System.Runtime.InteropServices;

namespace Wayne.Lib.Log
{
    internal class GlobalLogEntryCounter : IDisposable
    {
        #region Win32 Semaphore APIs

        [DllImport("kernel32", EntryPoint = "CreateSemaphore", SetLastError = true, CharSet = CharSet.Unicode)]
        private static extern uint CreateSemaphore(int auth, int initialCount, int maximumCount, string name);

        [DllImport("kernel32", EntryPoint = "OpenSemaphore", SetLastError = true, CharSet = CharSet.Unicode)]
        private static extern uint OpenSemaphore(int auth, bool bInheritHandle, string name);

        [DllImport("kernel32", EntryPoint = "ReleaseSemaphore", SetLastError = true, CharSet = CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.VariantBool)]
        private static extern bool ReleaseSemaphore(uint hHandle, int lReleaseCount, out int lpPreviousCount);

        [DllImport("kernel32", EntryPoint = "CloseHandle", SetLastError = true, CharSet = CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.VariantBool)]
        private static extern bool CloseHandle(uint hHandle);

        #endregion

        #region Fields

        private const string GlobalName = "Wayne.Lib.Log.GlobalLogEntryCounter";

        private bool disposed;
        private readonly bool fullWindows;
        private uint fullWindowsSemaphoreHandle;

        #endregion

        #region Construction

        /// <summary>
        /// Constructor.
        /// </summary>
        public GlobalLogEntryCounter()
        {
            fullWindows = Directory.Exists(@"C:\");
            if (fullWindows)
            {
                int suffix = 0;
                do
                {
                    suffix++;
                    var wayneLibLogGloballogentrycounter = GlobalName + "." + suffix;
                    fullWindowsSemaphoreHandle = OpenSemaphore(0, true, wayneLibLogGloballogentrycounter);
                    if (fullWindowsSemaphoreHandle == 0)
                        fullWindowsSemaphoreHandle = CreateSemaphore(0, 1, int.MaxValue, wayneLibLogGloballogentrycounter);
                } while (fullWindowsSemaphoreHandle == 0);
            }
        }

        /// <summary>
        /// Finalizer.
        /// </summary>
        ~GlobalLogEntryCounter()
        {
            Dispose(false);
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Releases all resources used by this object.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                disposed = true;
                if (disposing)
                {
                    // Dispose managed resources here!
                }

                if (fullWindowsSemaphoreHandle != 0)
                {
                    CloseHandle(fullWindowsSemaphoreHandle);
                    fullWindowsSemaphoreHandle = 0;
                }
            }
        }

        #endregion

        #region Methods

        public UInt64 GetNextValue()
        {
            if (fullWindows)
            {
                if (fullWindowsSemaphoreHandle != 0)
                {
                    int lastCount;
                    if (ReleaseSemaphore(fullWindowsSemaphoreHandle, 1, out lastCount))
                        return (UInt64)lastCount;
                }
            }
            return 0;
        }

        #endregion
    }
}