using System.IO;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
using System.Threading;
namespace MediaBrowser.Common.Implementations.Configuration
{
    /// 
    /// Class BaseConfigurationManager
    /// 
    public abstract class BaseConfigurationManager : IConfigurationManager
    {
        /// 
        /// Gets the type of the configuration.
        /// 
        /// The type of the configuration.
        protected abstract Type ConfigurationType { get; }
        /// 
        /// Occurs when [configuration updated].
        /// 
        public event EventHandler ConfigurationUpdated;
        /// 
        /// Gets the logger.
        /// 
        /// The logger.
        protected ILogger Logger { get; private set; }
        /// 
        /// Gets the XML serializer.
        /// 
        /// The XML serializer.
        protected IXmlSerializer XmlSerializer { get; private set; }
        /// 
        /// Gets or sets the application paths.
        /// 
        /// The application paths.
        public IApplicationPaths CommonApplicationPaths { get; private set; }
        /// 
        /// The _configuration loaded
        /// 
        private bool _configurationLoaded;
        /// 
        /// The _configuration sync lock
        /// 
        private object _configurationSyncLock = new object();
        /// 
        /// The _configuration
        /// 
        private BaseApplicationConfiguration _configuration;
        /// 
        /// Gets the system configuration
        /// 
        /// The configuration.
        public BaseApplicationConfiguration CommonConfiguration
        {
            get
            {
                // Lazy load
                LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => (BaseApplicationConfiguration)ConfigurationHelper.GetXmlConfiguration(ConfigurationType, CommonApplicationPaths.SystemConfigurationFilePath, XmlSerializer));
                return _configuration;
            }
            protected set
            {
                _configuration = value;
                _configurationLoaded = value != null;
            }
        }
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// The application paths.
        /// The log manager.
        /// The XML serializer.
        protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer)
        {
            CommonApplicationPaths = applicationPaths;
            XmlSerializer = xmlSerializer;
            Logger = logManager.GetLogger(GetType().Name);
            UpdateCachePath();
        }
        /// 
        /// The _save lock
        /// 
        private readonly object _configurationSaveLock = new object();
        /// 
        /// Saves the configuration.
        /// 
        public void SaveConfiguration()
        {
            var path = CommonApplicationPaths.SystemConfigurationFilePath;
            Directory.CreateDirectory(Path.GetDirectoryName(path));
            lock (_configurationSaveLock)
            {
                XmlSerializer.SerializeToFile(CommonConfiguration, path);
            }
            OnConfigurationUpdated();
        }
        /// 
        /// Called when [configuration updated].
        /// 
        protected virtual void OnConfigurationUpdated()
        {
            UpdateCachePath();
            EventHelper.QueueEventIfNotNull(ConfigurationUpdated, this, EventArgs.Empty, Logger);
        }
        /// 
        /// Replaces the configuration.
        /// 
        /// The new configuration.
        /// newConfiguration
        public virtual void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration)
        {
            if (newConfiguration == null)
            {
                throw new ArgumentNullException("newConfiguration");
            }
            ValidateCachePath(newConfiguration);
            CommonConfiguration = newConfiguration;
            SaveConfiguration();
        }
        /// 
        /// Updates the items by name path.
        /// 
        private void UpdateCachePath()
        {
            ((BaseApplicationPaths)CommonApplicationPaths).CachePath = string.IsNullOrEmpty(CommonConfiguration.CachePath) ? 
                null : 
                CommonConfiguration.CachePath;
        }
        /// 
        /// Replaces the cache path.
        /// 
        /// The new configuration.
        /// 
        private void ValidateCachePath(BaseApplicationConfiguration newConfig)
        {
            var newPath = newConfig.CachePath;
            if (!string.IsNullOrWhiteSpace(newPath)
                && !string.Equals(CommonConfiguration.CachePath ?? string.Empty, newPath))
            {
                // Validate
                if (!Directory.Exists(newPath))
                {
                    throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
                }
            }
        }
    }
}