#region  --------------- Copyright Dresser Wayne Pignone -------------
/*
 * $Log: /Wrk/WayneLibraries/Wrk/Log/EventLogStorage/FileSystemStorage.cs $
 * 
 * 3     08-03-19 9:05 roger.månsson
 * Exchange illegal file name characters with '_' in event file name, and
 * also exchange '\' characters with '_'.
 * 
 * 2     08-02-13 9:24 Mattias.larsson
 * FxCop fixes.
 */
#endregion

using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using Wayne.Lib.IO;

namespace Wayne.Lib.Log
{
    /// <summary>
    /// The FileSystemStorage event storage class stores the events in the file system which
    /// enables them to survive a system restart.
    /// </summary>
    internal class FileSystemStorage : ISubscriptionStorage
    {
        #region Fields

        private object dbLock = new object();
        private string basePath;

        #endregion

        #region Construction

        public FileSystemStorage()
        {
            basePath = Paths.Combine("EventStorage", System.AppDomain.CurrentDomain.FriendlyName);
            FileSupport.EnsureDirectoryExists(basePath);
        }

        #endregion

        #region Methods

        public void Remove(string eventSubscriberId, EventLogEntry eventLogEntry)
        {
            GetAndCreateSubscriberDir(eventSubscriberId);
            lock (dbLock)
            {
                string fileName = Path.Combine(basePath, Path.Combine(eventSubscriberId, CreateFileName(eventLogEntry)));
                if (File.Exists(fileName))
                    File.Delete(fileName);
            }
        }

        public EventLogEntry[] GetStoredEvents(string eventSubscriberId)
        {
            GetAndCreateSubscriberDir(eventSubscriberId);

            lock (dbLock)
            {
                List<EventLogEntry> eventLogEntryList = new List<EventLogEntry>();

                string[] filePaths = Directory.GetFiles(Path.Combine(basePath, eventSubscriberId));

                XmlDocument xmlDoc = new XmlDocument();
                foreach (string filePath in filePaths)
                {
                    FileSupport.LoadXml(xmlDoc, filePath);
                    EventLogEntry entry = EventLogEntry.Deserialize(xmlDoc["LogEntry", EventLogXml.Ns]);
                    if (entry != null)
                        eventLogEntryList.Add(entry);

                }
                return eventLogEntryList.ToArray();
            }
        }

        public void Add(string eventSubscriberId, EventLogEntry eventLogEntry)
        {
            GetAndCreateSubscriberDir(eventSubscriberId);

            lock (dbLock)
            {
                string subscriberPath = GetAndCreateSubscriberDir(eventSubscriberId);

                string eventFileName = CreateFileName(eventLogEntry);


                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Encoding = Encoding.UTF8;
                settings.Indent = true;
                settings.NewLineHandling = NewLineHandling.Entitize;

                using (XmlWriter xmlWriter = XmlWriter.Create(Path.Combine(subscriberPath, eventFileName), settings))
                {
                    eventLogEntry.WriteXml(xmlWriter, "");
                }
            }
        }

        private string GetAndCreateSubscriberDir(string eventSubscriberId)
        {
            string subscriberPath = Path.Combine(basePath, eventSubscriberId);
            FileSupport.EnsureDirectoryExists(subscriberPath);
            return subscriberPath;
        }

        private static string CreateFileName(EventLogEntry eventLogEntry)
        {
            string eventFileName = eventLogEntry.EntityCategory.GetName(EntityLogKind.Entity, false) + eventLogEntry.GetDateTimeString("yyyyMMddHHmmss") + ".xml";

            foreach (char invalidChar in Path.GetInvalidPathChars())
            {
                eventFileName = eventFileName.Replace(invalidChar, '_');
            }
            eventFileName = eventFileName.Replace('\\', '_');

            return eventFileName;
        }

        #endregion
    }
}