using Emby.Common.Implementations.Serialization;
using Emby.Dlna;
using Emby.Dlna.ConnectionManager;
using Emby.Dlna.ContentDirectory;
using Emby.Dlna.Main;
using Emby.Dlna.MediaReceiverRegistrar;
using Emby.Dlna.Ssdp;
using Emby.Drawing;
using Emby.Photos;
using Emby.Server.Implementations.Activity;
using Emby.Server.Implementations.Archiving;
using Emby.Server.Implementations.Channels;
using Emby.Server.Implementations.Collections;
using Emby.Server.Implementations.Configuration;
using Emby.Server.Implementations.Cryptography;
using Emby.Server.Implementations.Data;
using Emby.Server.Implementations.Devices;
using Emby.Server.Implementations.Diagnostics;
using Emby.Server.Implementations.Dto;
using Emby.Server.Implementations.FFMpeg;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.Security;
using Emby.Server.Implementations.IO;
using Emby.Server.Implementations.Library;
using Emby.Server.Implementations.LiveTv;
using Emby.Server.Implementations.Localization;
using Emby.Server.Implementations.MediaEncoder;
using Emby.Server.Implementations.Net;
using Emby.Server.Implementations.Notifications;
using Emby.Server.Implementations.Playlists;
using Emby.Server.Implementations.Reflection;
using Emby.Server.Implementations.ScheduledTasks;
using Emby.Server.Implementations.Security;
using Emby.Server.Implementations.Serialization;
using Emby.Server.Implementations.Session;
using Emby.Server.Implementations.Social;
using Emby.Server.Implementations.Threading;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates;
using Emby.Server.Implementations.Xml;
using Emby.Server.MediaEncoding.Subtitles;
using MediaBrowser.Api;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Progress;
using MediaBrowser.Common.Security;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Connect;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Notifications;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Controller.Sync;
using MediaBrowser.Controller.TV;
using MediaBrowser.LocalMetadata.Savers;
using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.News;
using MediaBrowser.Model.Reflection;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.Social;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Text;
using MediaBrowser.Model.Threading;
using MediaBrowser.Model.Updates;
using MediaBrowser.Model.Xml;
using MediaBrowser.Providers.Chapters;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.Subtitles;
using MediaBrowser.WebDashboard.Api;
using MediaBrowser.XbmcMetadata.Providers;
using OpenSubtitlesHandler;
using ServiceStack;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
namespace Emby.Server.Implementations
{
    /// 
    /// Class CompositionRoot
    /// 
    public abstract class ApplicationHost : IServerApplicationHost, IDependencyContainer, IDisposable
    {
        /// 
        /// Gets a value indicating whether this instance can self restart.
        /// 
        /// true if this instance can self restart; otherwise, false.
        public abstract bool CanSelfRestart { get; }
        /// 
        /// Gets or sets a value indicating whether this instance can self update.
        /// 
        /// true if this instance can self update; otherwise, false.
        public virtual bool CanSelfUpdate
        {
            get
            {
                return false;
            }
        }
        /// 
        /// Occurs when [has pending restart changed].
        /// 
        public event EventHandler HasPendingRestartChanged;
        /// 
        /// Occurs when [application updated].
        /// 
        public event EventHandler> ApplicationUpdated;
        /// 
        /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
        /// 
        /// true if this instance has pending application restart; otherwise, false.
        public bool HasPendingRestart { get; private set; }
        public bool IsShuttingDown { get; private set; }
        /// 
        /// Gets or sets the logger.
        /// 
        /// The logger.
        protected ILogger Logger { get; set; }
        /// 
        /// Gets or sets the plugins.
        /// 
        /// The plugins.
        public IPlugin[] Plugins { get; protected set; }
        /// 
        /// Gets or sets the log manager.
        /// 
        /// The log manager.
        public ILogManager LogManager { get; protected set; }
        /// 
        /// Gets the application paths.
        /// 
        /// The application paths.
        protected ServerApplicationPaths ApplicationPaths { get; set; }
        /// 
        /// Gets assemblies that failed to load
        /// 
        /// The failed assemblies.
        public List FailedAssemblies { get; protected set; }
        /// 
        /// Gets all concrete types.
        /// 
        /// All concrete types.
        public Type[] AllConcreteTypes { get; protected set; }
        /// 
        /// The disposable parts
        /// 
        protected readonly List DisposableParts = new List();
        /// 
        /// Gets a value indicating whether this instance is first run.
        /// 
        /// true if this instance is first run; otherwise, false.
        public bool IsFirstRun { get; private set; }
        /// 
        /// Gets the configuration manager.
        /// 
        /// The configuration manager.
        protected IConfigurationManager ConfigurationManager { get; set; }
        public IFileSystem FileSystemManager { get; set; }
        protected IEnvironmentInfo EnvironmentInfo { get; set; }
        private IBlurayExaminer BlurayExaminer { get; set; }
        public PackageVersionClass SystemUpdateLevel
        {
            get
            {
#if BETA
                return PackageVersionClass.Beta;
#endif
                return PackageVersionClass.Release;
            }
        }
        public virtual string OperatingSystemDisplayName
        {
            get { return EnvironmentInfo.OperatingSystemName; }
        }
        /// 
        /// The container
        /// 
        protected readonly SimpleInjector.Container Container = new SimpleInjector.Container();
        protected ISystemEvents SystemEvents { get; set; }
        protected IMemoryStreamFactory MemoryStreamFactory { get; set; }
        /// 
        /// Gets the server configuration manager.
        /// 
        /// The server configuration manager.
        public IServerConfigurationManager ServerConfigurationManager
        {
            get { return (IServerConfigurationManager)ConfigurationManager; }
        }
        /// 
        /// Gets the configuration manager.
        /// 
        /// IConfigurationManager.
        protected IConfigurationManager GetConfigurationManager()
        {
            return new ServerConfigurationManager(ApplicationPaths, LogManager, XmlSerializer, FileSystemManager);
        }
        /// 
        /// Gets or sets the server manager.
        /// 
        /// The server manager.
        private IServerManager ServerManager { get; set; }
        /// 
        /// Gets or sets the user manager.
        /// 
        /// The user manager.
        public IUserManager UserManager { get; set; }
        /// 
        /// Gets or sets the library manager.
        /// 
        /// The library manager.
        internal ILibraryManager LibraryManager { get; set; }
        /// 
        /// Gets or sets the directory watchers.
        /// 
        /// The directory watchers.
        private ILibraryMonitor LibraryMonitor { get; set; }
        /// 
        /// Gets or sets the provider manager.
        /// 
        /// The provider manager.
        private IProviderManager ProviderManager { get; set; }
        /// 
        /// Gets or sets the HTTP server.
        /// 
        /// The HTTP server.
        private IHttpServer HttpServer { get; set; }
        private IDtoService DtoService { get; set; }
        public IImageProcessor ImageProcessor { get; set; }
        /// 
        /// Gets or sets the media encoder.
        /// 
        /// The media encoder.
        private IMediaEncoder MediaEncoder { get; set; }
        private ISubtitleEncoder SubtitleEncoder { get; set; }
        private IConnectManager ConnectManager { get; set; }
        private ISessionManager SessionManager { get; set; }
        private ILiveTvManager LiveTvManager { get; set; }
        public ILocalizationManager LocalizationManager { get; set; }
        private IEncodingManager EncodingManager { get; set; }
        private IChannelManager ChannelManager { get; set; }
        private ISyncManager SyncManager { get; set; }
        /// 
        /// Gets or sets the user data repository.
        /// 
        /// The user data repository.
        private IUserDataManager UserDataManager { get; set; }
        private IUserRepository UserRepository { get; set; }
        internal IDisplayPreferencesRepository DisplayPreferencesRepository { get; set; }
        internal IItemRepository ItemRepository { get; set; }
        private INotificationsRepository NotificationsRepository { get; set; }
        private INotificationManager NotificationManager { get; set; }
        private ISubtitleManager SubtitleManager { get; set; }
        private IChapterManager ChapterManager { get; set; }
        private IDeviceManager DeviceManager { get; set; }
        internal IUserViewManager UserViewManager { get; set; }
        private IAuthenticationRepository AuthenticationRepository { get; set; }
        private ITVSeriesManager TVSeriesManager { get; set; }
        private ICollectionManager CollectionManager { get; set; }
        private IMediaSourceManager MediaSourceManager { get; set; }
        private IPlaylistManager PlaylistManager { get; set; }
        /// 
        /// Gets or sets the installation manager.
        /// 
        /// The installation manager.
        protected IInstallationManager InstallationManager { get; private set; }
        /// 
        /// Gets the security manager.
        /// 
        /// The security manager.
        protected ISecurityManager SecurityManager { get; private set; }
        /// 
        /// Gets or sets the zip client.
        /// 
        /// The zip client.
        protected IZipClient ZipClient { get; private set; }
        protected IAuthService AuthService { get; private set; }
        protected readonly StartupOptions StartupOptions;
        protected readonly string ReleaseAssetFilename;
        internal IPowerManagement PowerManagement { get; private set; }
        internal IImageEncoder ImageEncoder { get; private set; }
        protected IProcessFactory ProcessFactory { get; private set; }
        protected ITimerFactory TimerFactory { get; private set; }
        protected ICryptoProvider CryptographyProvider = new CryptographyProvider();
        protected readonly IXmlSerializer XmlSerializer;
        protected ISocketFactory SocketFactory { get; private set; }
        protected ITaskManager TaskManager { get; private set; }
        public IHttpClient HttpClient { get; private set; }
        protected INetworkManager NetworkManager { get; set; }
        public IJsonSerializer JsonSerializer { get; private set; }
        protected IIsoManager IsoManager { get; private set; }
        /// 
        /// Initializes a new instance of the  class.
        /// 
        public ApplicationHost(ServerApplicationPaths applicationPaths,
            ILogManager logManager,
            StartupOptions options,
            IFileSystem fileSystem,
            IPowerManagement powerManagement,
            string releaseAssetFilename,
            IEnvironmentInfo environmentInfo,
            IImageEncoder imageEncoder,
            ISystemEvents systemEvents,
            INetworkManager networkManager)
        {
            // hack alert, until common can target .net core
            BaseExtensions.CryptographyProvider = CryptographyProvider;
            XmlSerializer = new MyXmlSerializer(fileSystem, logManager.GetLogger("XmlSerializer"));
            NetworkManager = networkManager;
            EnvironmentInfo = environmentInfo;
            SystemEvents = systemEvents;
            MemoryStreamFactory = new MemoryStreamProvider();
            FailedAssemblies = new List();
            ApplicationPaths = applicationPaths;
            LogManager = logManager;
            FileSystemManager = fileSystem;
            ConfigurationManager = GetConfigurationManager();
            // Initialize this early in case the -v command line option is used
            Logger = LogManager.GetLogger("App");
            StartupOptions = options;
            ReleaseAssetFilename = releaseAssetFilename;
            PowerManagement = powerManagement;
            ImageEncoder = imageEncoder;
            SetBaseExceptionMessage();
            fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
        }
        private Version _version;
        /// 
        /// Gets the current application version
        /// 
        /// The application version.
        public Version ApplicationVersion
        {
            get
            {
                return _version ?? (_version = GetAssembly(GetType()).GetName().Version);
            }
        }
        private DeviceId _deviceId;
        public string SystemId
        {
            get
            {
                if (_deviceId == null)
                {
                    _deviceId = new DeviceId(ApplicationPaths, LogManager.GetLogger("SystemId"), FileSystemManager);
                }
                return _deviceId.Value;
            }
        }
        /// 
        /// Gets the name.
        /// 
        /// The name.
        public string Name
        {
            get
            {
                return "Emby Server";
            }
        }
        private Assembly GetAssembly(Type type)
        {
            return type.GetTypeInfo().Assembly;
        }
        public virtual bool SupportsAutoRunAtStartup
        {
            get
            {
                return EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows;
            }
        }
        /// 
        /// Creates an instance of type and resolves all constructor dependancies
        /// 
        /// The type.
        /// System.Object.
        public object CreateInstance(Type type)
        {
            try
            {
                return Container.GetInstance(type);
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error creating {0}", ex, type.FullName);
                throw;
            }
        }
        /// 
        /// Creates the instance safe.
        /// 
        /// The type.
        /// System.Object.
        protected object CreateInstanceSafe(Type type)
        {
            try
            {
                return Container.GetInstance(type);
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error creating {0}", ex, type.FullName);
                // Don't blow up in release mode
                return null;
            }
        }
        /// 
        /// Registers the specified obj.
        /// 
        /// 
        /// The obj.
        /// if set to true [manage lifetime].
        protected void RegisterSingleInstance(T obj, bool manageLifetime = true)
            where T : class
        {
            Container.RegisterSingleton(obj);
            if (manageLifetime)
            {
                var disposable = obj as IDisposable;
                if (disposable != null)
                {
                    DisposableParts.Add(disposable);
                }
            }
        }
        /// 
        /// Registers the single instance.
        /// 
        /// 
        /// The func.
        protected void RegisterSingleInstance(Func func)
            where T : class
        {
            Container.RegisterSingleton(func);
        }
        /// 
        /// Resolves this instance.
        /// 
        /// 
        /// ``0.
        public T Resolve()
        {
            return (T)Container.GetRegistration(typeof(T), true).GetInstance();
        }
        /// 
        /// Resolves this instance.
        /// 
        /// 
        /// ``0.
        public T TryResolve()
        {
            var result = Container.GetRegistration(typeof(T), false);
            if (result == null)
            {
                return default(T);
            }
            return (T)result.GetInstance();
        }
        /// 
        /// Loads the assembly.
        /// 
        /// The file.
        /// Assembly.
        protected Assembly LoadAssembly(string file)
        {
            try
            {
                return Assembly.Load(File.ReadAllBytes(file));
            }
            catch (Exception ex)
            {
                FailedAssemblies.Add(file);
                Logger.ErrorException("Error loading assembly {0}", ex, file);
                return null;
            }
        }
        /// 
        /// Gets the export types.
        /// 
        /// 
        /// IEnumerable{Type}.
        public IEnumerable GetExportTypes()
        {
            var currentType = typeof(T);
            return AllConcreteTypes.Where(currentType.IsAssignableFrom);
        }
        /// 
        /// Gets the exports.
        /// 
        /// 
        /// if set to true [manage liftime].
        /// IEnumerable{``0}.
        public IEnumerable GetExports(bool manageLiftime = true)
        {
            var parts = GetExportTypes()
                .Select(CreateInstanceSafe)
                .Where(i => i != null)
                .Cast()
                .ToList();
            if (manageLiftime)
            {
                lock (DisposableParts)
                {
                    DisposableParts.AddRange(parts.OfType());
                }
            }
            return parts;
        }
        private void SetBaseExceptionMessage()
        {
            var builder = GetBaseExceptionMessage(ApplicationPaths);
            builder.Insert(0, string.Format("Version: {0}{1}", ApplicationVersion, Environment.NewLine));
            builder.Insert(0, "*** Error Report ***" + Environment.NewLine);
            LogManager.ExceptionMessagePrefix = builder.ToString();
        }
        /// 
        /// Runs the startup tasks.
        /// 
        public async Task RunStartupTasks()
        {
            Resolve().AddTasks(GetExports(false));
            ConfigureAutorun();
            ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
            await MediaEncoder.Init().ConfigureAwait(false);
            if (string.IsNullOrWhiteSpace(MediaEncoder.EncoderPath))
            {
                if (ServerConfigurationManager.Configuration.IsStartupWizardCompleted)
                {
                    ServerConfigurationManager.Configuration.IsStartupWizardCompleted = false;
                    ServerConfigurationManager.SaveConfiguration();
                }
            }
            Logger.Info("ServerId: {0}", SystemId);
            Logger.Info("Core startup complete");
            HttpServer.GlobalResponse = null;
            Logger.Info("Post-init migrations complete");
            foreach (var entryPoint in GetExports().ToList())
            {
                var name = entryPoint.GetType().FullName;
                Logger.Info("Starting entry point {0}", name);
                var now = DateTime.UtcNow;
                try
                {
                    entryPoint.Run();
                }
                catch (Exception ex)
                {
                    Logger.ErrorException("Error in {0}", ex, name);
                }
                Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture), "ImageInfos");
            }
            Logger.Info("All entry points have started");
            LogManager.RemoveConsoleOutput();
        }
        /// 
        /// Configures the autorun.
        /// 
        private void ConfigureAutorun()
        {
            try
            {
                ConfigureAutoRunAtStartup(ConfigurationManager.CommonConfiguration.RunAtStartup);
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error configuring autorun", ex);
            }
        }
        private IJsonSerializer CreateJsonSerializer()
        {
            try
            {
                // https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Web.config#L4
                Licensing.RegisterLicense("1001-e1JlZjoxMDAxLE5hbWU6VGVzdCBCdXNpbmVzcyxUeXBlOkJ1c2luZXNzLEhhc2g6UHVNTVRPclhvT2ZIbjQ5MG5LZE1mUTd5RUMzQnBucTFEbTE3TDczVEF4QUNMT1FhNXJMOWkzVjFGL2ZkVTE3Q2pDNENqTkQyUktRWmhvUVBhYTBiekJGUUZ3ZE5aZHFDYm9hL3lydGlwUHI5K1JsaTBYbzNsUC85cjVJNHE5QVhldDN6QkE4aTlvdldrdTgyTk1relY2eis2dFFqTThYN2lmc0JveHgycFdjPSxFeHBpcnk6MjAxMy0wMS0wMX0=");
            }
            catch
            {
                // Failing under mono
            }
            return new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer"));
        }
        public async Task Init(IProgress progress)
        {
            HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
            HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
            // Safeguard against invalid configuration
            if (HttpPort == HttpsPort)
            {
                HttpPort = ServerConfiguration.DefaultHttpPort;
                HttpsPort = ServerConfiguration.DefaultHttpsPort;
            }
            progress.Report(1);
            JsonSerializer = CreateJsonSerializer();
            OnLoggerLoaded(true);
            LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false);
            IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted;
            progress.Report(2);
            LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging
                ? LogSeverity.Debug
                : LogSeverity.Info;
            progress.Report(3);
            DiscoverTypes();
            progress.Report(14);
            SetHttpLimit();
            progress.Report(15);
            var innerProgress = new ActionableProgress();
            innerProgress.RegisterAction(p => progress.Report(.8 * p + 15));
            await RegisterResources(innerProgress).ConfigureAwait(false);
            FindParts();
            progress.Report(95);
            await InstallIsoMounters(CancellationToken.None).ConfigureAwait(false);
            progress.Report(100);
        }
        protected virtual void OnLoggerLoaded(bool isFirstLoad)
        {
            Logger.Info("Application version: {0}", ApplicationVersion);
            if (!isFirstLoad)
            {
                LogEnvironmentInfo(Logger, ApplicationPaths, false);
            }
            // Put the app config in the log for troubleshooting purposes
            var configJson = new StringBuilder(JsonSerializer.SerializeToString(ConfigurationManager.CommonConfiguration));
            if (!string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.CertificatePassword))
            {
                configJson = configJson.Replace(ServerConfigurationManager.Configuration.CertificatePassword, "####");
            }
            Logger.LogMultiline("Application configuration:", LogSeverity.Info, configJson);
            if (Plugins != null)
            {
                var pluginBuilder = new StringBuilder();
                foreach (var plugin in Plugins)
                {
                    pluginBuilder.AppendLine(string.Format("{0} {1}", plugin.Name, plugin.Version));
                }
                Logger.LogMultiline("Plugins:", LogSeverity.Info, pluginBuilder);
            }
        }
        protected abstract IConnectManager CreateConnectManager();
        protected abstract ISyncManager CreateSyncManager();
        
        protected virtual IHttpClient CreateHttpClient()
        {
            return new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory, GetDefaultUserAgent);
        }
        /// 
        /// Registers resources that classes will depend on
        /// 
        protected async Task RegisterResources(IProgress progress)
        {
            RegisterSingleInstance(ConfigurationManager);
            RegisterSingleInstance(this);
            RegisterSingleInstance(ApplicationPaths);
            RegisterSingleInstance(JsonSerializer);
            RegisterSingleInstance(MemoryStreamFactory);
            RegisterSingleInstance(SystemEvents);
            RegisterSingleInstance(LogManager, false);
            RegisterSingleInstance(Logger);
            RegisterSingleInstance(EnvironmentInfo);
            RegisterSingleInstance(FileSystemManager);
            HttpClient = CreateHttpClient();
            RegisterSingleInstance(HttpClient);
            RegisterSingleInstance(NetworkManager);
            IsoManager = new IsoManager();
            RegisterSingleInstance(IsoManager);
            TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, LogManager.GetLogger("TaskManager"), FileSystemManager, SystemEvents);
            RegisterSingleInstance(TaskManager);
            RegisterSingleInstance(XmlSerializer);
            ProcessFactory = new ProcessFactory();
            RegisterSingleInstance(ProcessFactory);
            TimerFactory = new TimerFactory();
            RegisterSingleInstance(TimerFactory);
            RegisterSingleInstance(CryptographyProvider);
            SocketFactory = new SocketFactory(LogManager.GetLogger("SocketFactory"));
            RegisterSingleInstance(SocketFactory);
            RegisterSingleInstance(PowerManagement);
            SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager, FileSystemManager, CryptographyProvider);
            RegisterSingleInstance(SecurityManager);
            InstallationManager = new InstallationManager(LogManager.GetLogger("InstallationManager"), this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager, CryptographyProvider, PackageRuntime);
            RegisterSingleInstance(InstallationManager);
            ZipClient = new ZipClient(FileSystemManager);
            RegisterSingleInstance(ZipClient);
            RegisterSingleInstance(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer, MemoryStreamFactory));
            RegisterSingleInstance(this);
            RegisterSingleInstance(ApplicationPaths);
            RegisterSingleInstance(ServerConfigurationManager);
            IAssemblyInfo assemblyInfo = new AssemblyInfo();
            RegisterSingleInstance(assemblyInfo);
            LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LogManager.GetLogger("LocalizationManager"), assemblyInfo, new TextLocalizer());
            StringExtensions.LocalizationManager = LocalizationManager;
            RegisterSingleInstance(LocalizationManager);
            ITextEncoding textEncoding = new TextEncoding.TextEncoding(FileSystemManager, LogManager.GetLogger("TextEncoding"), JsonSerializer);
            RegisterSingleInstance(textEncoding);
            Utilities.EncodingHelper = textEncoding;
            BlurayExaminer = new BdInfoExaminer(FileSystemManager, textEncoding);
            RegisterSingleInstance(BlurayExaminer);
            RegisterSingleInstance(new XmlReaderSettingsFactory());
            UserDataManager = new UserDataManager(LogManager, ServerConfigurationManager);
            RegisterSingleInstance(UserDataManager);
            UserRepository = GetUserRepository();
            // This is only needed for disposal purposes. If removing this, make sure to have the manager handle disposing it
            RegisterSingleInstance(UserRepository);
            var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager.GetLogger("SqliteDisplayPreferencesRepository"), JsonSerializer, ApplicationPaths, MemoryStreamFactory, FileSystemManager);
            DisplayPreferencesRepository = displayPreferencesRepo;
            RegisterSingleInstance(DisplayPreferencesRepository);
            var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager.GetLogger("SqliteItemRepository"), MemoryStreamFactory, assemblyInfo, FileSystemManager, EnvironmentInfo, TimerFactory);
            ItemRepository = itemRepo;
            RegisterSingleInstance(ItemRepository);
            AuthenticationRepository = GetAuthenticationRepository();
            RegisterSingleInstance(AuthenticationRepository);
            UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider);
            RegisterSingleInstance(UserManager);
            LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
            RegisterSingleInstance(LibraryManager);
            var musicManager = new MusicManager(LibraryManager);
            RegisterSingleInstance(new MusicManager(LibraryManager));
            LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, TimerFactory, SystemEvents, EnvironmentInfo);
            RegisterSingleInstance(LibraryMonitor);
            ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer, MemoryStreamFactory);
            RegisterSingleInstance(ProviderManager);
            RegisterSingleInstance(() => new SearchEngine(LogManager, LibraryManager, UserManager));
            CertificateInfo = GetCertificateInfo(true);
            Certificate = GetCertificate(CertificateInfo);
            HttpServer = HttpServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, NetworkManager, MemoryStreamFactory, "Emby", "web/index.html", textEncoding, SocketFactory, CryptographyProvider, JsonSerializer, XmlSerializer, EnvironmentInfo, Certificate, FileSystemManager, SupportsDualModeSockets);
            HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading");
            RegisterSingleInstance(HttpServer, false);
            progress.Report(10);
            ServerManager = new ServerManager.ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamFactory, textEncoding);
            RegisterSingleInstance(ServerManager);
            var innerProgress = new ActionableProgress();
            innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15));
            ImageProcessor = GetImageProcessor();
            RegisterSingleInstance(ImageProcessor);
            TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager);
            RegisterSingleInstance(TVSeriesManager);
            SyncManager = CreateSyncManager();
            RegisterSingleInstance(SyncManager);
            DtoService = new DtoService(LogManager.GetLogger("DtoService"), LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this, () => DeviceManager, () => MediaSourceManager, () => LiveTvManager);
            RegisterSingleInstance(DtoService);
            var encryptionManager = new EncryptionManager();
            RegisterSingleInstance(encryptionManager);
            ConnectManager = CreateConnectManager();
            RegisterSingleInstance(ConnectManager);
            var deviceRepo = new SqliteDeviceRepository(LogManager.GetLogger("DeviceManager"), ServerConfigurationManager, FileSystemManager, JsonSerializer);
            deviceRepo.Initialize();
            DeviceManager = new DeviceManager(deviceRepo, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
            RegisterSingleInstance(DeviceManager);
            var newsService = new Emby.Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
            RegisterSingleInstance(newsService);
            progress.Report(15);
            ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
            RegisterSingleInstance(ChannelManager);
            MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer, FileSystemManager, UserDataManager, TimerFactory);
            RegisterSingleInstance(MediaSourceManager);
            SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager, TimerFactory);
            RegisterSingleInstance(SessionManager);
            var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("Dlna"), JsonSerializer, this, assemblyInfo);
            RegisterSingleInstance(dlnaManager);
            var connectionManager = new ConnectionManager(dlnaManager, ServerConfigurationManager, LogManager.GetLogger("UpnpConnectionManager"), HttpClient, new XmlReaderSettingsFactory());
            RegisterSingleInstance(connectionManager);
            CollectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"), ProviderManager);
            RegisterSingleInstance(CollectionManager);
            PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager, ProviderManager);
            RegisterSingleInstance(PlaylistManager);
            LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager, SecurityManager);
            RegisterSingleInstance(LiveTvManager);
            UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
            RegisterSingleInstance(UserViewManager);
            var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory(), TVSeriesManager);
            RegisterSingleInstance(contentDirectory);
            var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager, new XmlReaderSettingsFactory());
            RegisterSingleInstance(mediaRegistrar);
            NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager);
            RegisterSingleInstance(NotificationManager);
            SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager);
            RegisterSingleInstance(SubtitleManager);
            RegisterSingleInstance(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager, SocketFactory, TimerFactory));
            ChapterManager = new ChapterManager(LibraryManager, LogManager.GetLogger("ChapterManager"), ServerConfigurationManager, ItemRepository);
            RegisterSingleInstance(ChapterManager);
            await RegisterMediaEncoder(innerProgress).ConfigureAwait(false);
            progress.Report(90);
            EncodingManager = new EncodingManager(FileSystemManager, Logger, MediaEncoder, ChapterManager, LibraryManager);
            RegisterSingleInstance(EncodingManager);
            var sharingRepo = new SharingRepository(LogManager.GetLogger("SharingRepository"), ApplicationPaths, FileSystemManager);
            sharingRepo.Initialize();
            // This is only needed for disposal purposes. If removing this, make sure to have the manager handle disposing it
            RegisterSingleInstance(sharingRepo);
            RegisterSingleInstance(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this));
            var activityLogRepo = GetActivityLogRepository();
            RegisterSingleInstance(activityLogRepo);
            RegisterSingleInstance(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo, UserManager));
            var authContext = new AuthorizationContext(AuthenticationRepository, ConnectManager);
            RegisterSingleInstance(authContext);
            RegisterSingleInstance(new SessionContext(UserManager, authContext, SessionManager));
            AuthService = new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager);
            RegisterSingleInstance(AuthService);
            SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, MemoryStreamFactory, ProcessFactory, textEncoding);
            RegisterSingleInstance(SubtitleEncoder);
            displayPreferencesRepo.Initialize();
            var userDataRepo = new SqliteUserDataRepository(LogManager.GetLogger("SqliteUserDataRepository"), ApplicationPaths, FileSystemManager);
            ((UserDataManager)UserDataManager).Repository = userDataRepo;
            itemRepo.Initialize(userDataRepo);
            ((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
            ConfigureNotificationsRepository();
            progress.Report(100);
            SetStaticProperties();
            ((UserManager)UserManager).Initialize();
        }
        public virtual string PackageRuntime
        {
            get
            {
                return "netframework";
            }
        }
        public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, bool isStartup)
        {
            logger.LogMultiline("Emby", LogSeverity.Info, GetBaseExceptionMessage(appPaths));
        }
        protected static StringBuilder GetBaseExceptionMessage(IApplicationPaths appPaths)
        {
            var builder = new StringBuilder();
            builder.AppendLine(string.Format("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs())));
            builder.AppendLine(string.Format("Operating system: {0}", Environment.OSVersion));
            builder.AppendLine(string.Format("64-Bit OS: {0}", Environment.Is64BitOperatingSystem));
            builder.AppendLine(string.Format("64-Bit Process: {0}", Environment.Is64BitProcess));
            builder.AppendLine(string.Format("User Interactive: {0}", Environment.UserInteractive));
            Type type = Type.GetType("Mono.Runtime");
            if (type != null)
            {
                MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
                if (displayName != null)
                {
                    builder.AppendLine("Mono: " + displayName.Invoke(null, null));
                }
            }
            builder.AppendLine(string.Format("Processor count: {0}", Environment.ProcessorCount));
            builder.AppendLine(string.Format("Program data path: {0}", appPaths.ProgramDataPath));
            builder.AppendLine(string.Format("Application directory: {0}", appPaths.ProgramSystemPath));
            return builder;
        }
        private void SetHttpLimit()
        {
            try
            {
                // Increase the max http request limit
                ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error setting http limit", ex);
            }
        }
        /// 
        /// Installs the iso mounters.
        /// 
        /// The cancellation token.
        /// Task.
        private async Task InstallIsoMounters(CancellationToken cancellationToken)
        {
            var list = new List();
            foreach (var isoMounter in GetExports())
            {
                try
                {
                    if (isoMounter.RequiresInstallation && !isoMounter.IsInstalled)
                    {
                        Logger.Info("Installing {0}", isoMounter.Name);
                        await isoMounter.Install(cancellationToken).ConfigureAwait(false);
                    }
                    list.Add(isoMounter);
                }
                catch (Exception ex)
                {
                    Logger.ErrorException("{0} failed to load.", ex, isoMounter.Name);
                }
            }
            IsoManager.AddParts(list);
        }
        protected string GetDefaultUserAgent()
        {
            var name = FormatAttribute(Name);
            return name + "/" + ApplicationVersion;
        }
        private string FormatAttribute(string str)
        {
            var arr = str.ToCharArray();
            arr = Array.FindAll(arr, (c => (char.IsLetterOrDigit(c)
                                                  || char.IsWhiteSpace(c))));
            var result = new string(arr);
            if (string.IsNullOrWhiteSpace(result))
            {
                result = "Emby";
            }
            return result;
        }
        protected virtual bool SupportsDualModeSockets
        {
            get
            {
                return true;
            }
        }
        private X509Certificate GetCertificate(CertificateInfo info)
        {
            var certificateLocation = info == null ? null : info.Path;
            if (string.IsNullOrWhiteSpace(certificateLocation))
            {
                return null;
            }
            try
            {
                if (!FileSystemManager.FileExists(certificateLocation))
                {
                    return null;
                }
                // Don't use an empty string password
                var password = string.IsNullOrWhiteSpace(info.Password) ? null : info.Password;
                X509Certificate2 localCert = new X509Certificate2(certificateLocation, password);
                //localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA;
                if (!localCert.HasPrivateKey)
                {
                    //throw new FileNotFoundException("Secure requested, no private key included", certificateLocation);
                    return null;
                }
                return localCert;
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error loading cert from {0}", ex, certificateLocation);
                return null;
            }
        }
        private IImageProcessor GetImageProcessor()
        {
            return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, () => LibraryManager, TimerFactory, () => MediaEncoder);
        }
        protected virtual FFMpegInstallInfo GetFfmpegInstallInfo()
        {
            var info = new FFMpegInstallInfo();
            // Windows builds: http://ffmpeg.zeranoe.com/builds/
            // Linux builds: http://johnvansickle.com/ffmpeg/
            // OS X builds: http://ffmpegmac.net/
            // OS X x64: http://www.evermeet.cx/ffmpeg/
            if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Linux)
            {
                info.FFMpegFilename = "ffmpeg";
                info.FFProbeFilename = "ffprobe";
                info.ArchiveType = "7z";
                info.Version = "20170308";
                info.DownloadUrls = GetLinuxDownloadUrls();
            }
            else if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
            {
                info.FFMpegFilename = "ffmpeg.exe";
                info.FFProbeFilename = "ffprobe.exe";
                info.Version = "20170308";
                info.ArchiveType = "7z";
                info.DownloadUrls = GetWindowsDownloadUrls();
            }
            else if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)
            {
                info.FFMpegFilename = "ffmpeg";
                info.FFProbeFilename = "ffprobe";
                info.ArchiveType = "7z";
                info.Version = "20170308";
                info.DownloadUrls = GetMacDownloadUrls();
            }
            else
            {
                // No version available - user requirement
                info.DownloadUrls = new string[] { };
            }
            return info;
        }
        private string[] GetMacDownloadUrls()
        {
            switch (EnvironmentInfo.SystemArchitecture)
            {
                case MediaBrowser.Model.System.Architecture.X64:
                    return new[]
                    {
                        "https://embydata.com/downloads/ffmpeg/osx/ffmpeg-x64-20170308.7z"
                    };
            }
            return new string[] { };
        }
        private string[] GetWindowsDownloadUrls()
        {
            switch (EnvironmentInfo.SystemArchitecture)
            {
                case MediaBrowser.Model.System.Architecture.X64:
                    return new[]
                    {
                        "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win64.7z"
                    };
                case MediaBrowser.Model.System.Architecture.X86:
                    return new[]
                    {
                        "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win32.7z"
                    };
            }
            return new string[] { };
        }
        private string[] GetLinuxDownloadUrls()
        {
            switch (EnvironmentInfo.SystemArchitecture)
            {
                case MediaBrowser.Model.System.Architecture.X64:
                    return new[]
                    {
                        "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-64bit-static.7z"
                    };
                case MediaBrowser.Model.System.Architecture.X86:
                    return new[]
                    {
                        "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-32bit-static.7z"
                    };
            }
            return new string[] { };
        }
        /// 
        /// Registers the media encoder.
        /// 
        /// Task.
        private async Task RegisterMediaEncoder(IProgress progress)
        {
            string encoderPath = null;
            string probePath = null;
            var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, GetFfmpegInstallInfo())
                .GetFFMpegInfo(StartupOptions, progress).ConfigureAwait(false);
            encoderPath = info.EncoderPath;
            probePath = info.ProbePath;
            var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase);
            var mediaEncoder = new MediaEncoding.Encoder.MediaEncoder(LogManager.GetLogger("MediaEncoder"),
                JsonSerializer,
                encoderPath,
                probePath,
                hasExternalEncoder,
                ServerConfigurationManager,
                FileSystemManager,
                LiveTvManager,
                IsoManager,
                LibraryManager,
                ChannelManager,
                SessionManager,
                () => SubtitleEncoder,
                () => MediaSourceManager,
                HttpClient,
                ZipClient,
                MemoryStreamFactory,
                ProcessFactory,
                (Environment.ProcessorCount > 2 ? 14000 : 40000),
                EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows,
                EnvironmentInfo,
                BlurayExaminer);
            MediaEncoder = mediaEncoder;
            RegisterSingleInstance(MediaEncoder);
        }
        /// 
        /// Gets the user repository.
        /// 
        /// Task{IUserRepository}.
        private IUserRepository GetUserRepository()
        {
            var repo = new SqliteUserRepository(LogManager.GetLogger("SqliteUserRepository"), ApplicationPaths, JsonSerializer, MemoryStreamFactory);
            repo.Initialize();
            return repo;
        }
        private IAuthenticationRepository GetAuthenticationRepository()
        {
            var repo = new AuthenticationRepository(LogManager.GetLogger("AuthenticationRepository"), ServerConfigurationManager.ApplicationPaths);
            repo.Initialize();
            return repo;
        }
        private IActivityRepository GetActivityLogRepository()
        {
            var repo = new ActivityRepository(LogManager.GetLogger("ActivityRepository"), ServerConfigurationManager.ApplicationPaths, FileSystemManager);
            repo.Initialize();
            return repo;
        }
        /// 
        /// Configures the repositories.
        /// 
        private void ConfigureNotificationsRepository()
        {
            var repo = new SqliteNotificationsRepository(LogManager.GetLogger("SqliteNotificationsRepository"), ServerConfigurationManager.ApplicationPaths, FileSystemManager);
            repo.Initialize();
            NotificationsRepository = repo;
            RegisterSingleInstance(NotificationsRepository);
        }
        /// 
        /// Dirty hacks
        /// 
        private void SetStaticProperties()
        {
            // For now there's no real way to inject these properly
            BaseItem.Logger = LogManager.GetLogger("BaseItem");
            BaseItem.ConfigurationManager = ServerConfigurationManager;
            BaseItem.LibraryManager = LibraryManager;
            BaseItem.ProviderManager = ProviderManager;
            BaseItem.LocalizationManager = LocalizationManager;
            BaseItem.ItemRepository = ItemRepository;
            User.XmlSerializer = XmlSerializer;
            User.UserManager = UserManager;
            Folder.UserManager = UserManager;
            BaseItem.FileSystem = FileSystemManager;
            BaseItem.UserDataManager = UserDataManager;
            BaseItem.ChannelManager = ChannelManager;
            BaseItem.LiveTvManager = LiveTvManager;
            Folder.UserViewManager = UserViewManager;
            UserView.TVSeriesManager = TVSeriesManager;
            UserView.PlaylistManager = PlaylistManager;
            BaseItem.CollectionManager = CollectionManager;
            BaseItem.MediaSourceManager = MediaSourceManager;
            CollectionFolder.XmlSerializer = XmlSerializer;
            Utilities.CryptographyProvider = CryptographyProvider;
            AuthenticatedAttribute.AuthService = AuthService;
        }
        /// 
        /// Finds the parts.
        /// 
        protected void FindParts()
        {
            if (!ServerConfigurationManager.Configuration.IsPortAuthorized)
            {
                RegisterServerWithAdministratorAccess();
                ServerConfigurationManager.Configuration.IsPortAuthorized = true;
                ConfigurationManager.SaveConfiguration();
            }
            RegisterModules();
            ConfigurationManager.AddParts(GetExports());
            Plugins = GetExports().Select(LoadPlugin).Where(i => i != null).ToArray();
            HttpServer.Init(GetExports(false));
            ServerManager.AddWebSocketListeners(GetExports(false));
            StartServer();
            LibraryManager.AddParts(GetExports(),
                GetExports(),
                GetExports(),
                GetExports(),
                GetExports(),
                GetExports());
            ProviderManager.AddParts(GetExports(),
                GetExports(),
                GetExports(),
                GetExports(),
                GetExports());
            ImageProcessor.AddParts(GetExports());
            LiveTvManager.AddParts(GetExports(), GetExports(), GetExports());
            SubtitleManager.AddParts(GetExports());
            SessionManager.AddParts(GetExports());
            ChannelManager.AddParts(GetExports());
            MediaSourceManager.AddParts(GetExports());
            NotificationManager.AddParts(GetExports(), GetExports());
            SyncManager.AddParts(GetExports());
        }
        private IPlugin LoadPlugin(IPlugin plugin)
        {
            try
            {
                var assemblyPlugin = plugin as IPluginAssembly;
                if (assemblyPlugin != null)
                {
                    var assembly = plugin.GetType().Assembly;
                    var assemblyName = assembly.GetName();
                    var assemblyFileName = assemblyName.Name + ".dll";
                    var assemblyFilePath = Path.Combine(ApplicationPaths.PluginsPath, assemblyFileName);
                    assemblyPlugin.SetAttributes(assemblyFilePath, assemblyFileName, assemblyName.Version);
                    try
                    {
                        var idAttributes = assembly.GetCustomAttributes(typeof(GuidAttribute), true);
                        if (idAttributes.Length > 0)
                        {
                            var attribute = (GuidAttribute)idAttributes[0];
                            var assemblyId = new Guid(attribute.Value);
                            assemblyPlugin.SetId(assemblyId);
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorException("Error getting plugin Id from {0}.", ex, plugin.GetType().FullName);
                    }
                }
                var isFirstRun = !File.Exists(plugin.ConfigurationFilePath);
                plugin.SetStartupInfo(isFirstRun, File.GetLastWriteTimeUtc, s => Directory.CreateDirectory(s));
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error loading plugin {0}", ex, plugin.GetType().FullName);
                return null;
            }
            return plugin;
        }
        /// 
        /// Discovers the types.
        /// 
        protected void DiscoverTypes()
        {
            FailedAssemblies.Clear();
            var assemblies = GetComposablePartAssemblies().ToList();
            foreach (var assembly in assemblies)
            {
                Logger.Info("Loading {0}", assembly.FullName);
            }
            AllConcreteTypes = assemblies
                .SelectMany(GetTypes)
                .Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType)
                .ToArray();
        }
        /// 
        /// Gets a list of types within an assembly
        /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
        /// 
        /// The assembly.
        /// IEnumerable{Type}.
        /// assembly
        protected List GetTypes(Assembly assembly)
        {
            if (assembly == null)
            {
                return new List();
            }
            try
            {
                // This null checking really shouldn't be needed but adding it due to some
                // unhandled exceptions in mono 5.0 that are a little hard to hunt down
                var types = assembly.GetTypes() ?? new Type[] { };
                return types.Where(t => t != null).ToList();
            }
            catch (ReflectionTypeLoadException ex)
            {
                if (ex.LoaderExceptions != null)
                {
                    foreach (var loaderException in ex.LoaderExceptions)
                    {
                        if (loaderException != null)
                        {
                            Logger.Error("LoaderException: " + loaderException.Message);
                        }
                    }
                }
                // If it fails we can still get a list of the Types it was able to resolve
                var types = ex.Types ?? new Type[] { };
                return types.Where(t => t != null).ToList();
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error loading types from assembly", ex);
                return new List();
            }
        }
        private CertificateInfo CertificateInfo { get; set; }
        private X509Certificate Certificate { get; set; }
        private IEnumerable GetUrlPrefixes()
        {
            var hosts = new List();
            hosts.Add("+");
            return hosts.SelectMany(i =>
            {
                var prefixes = new List
                {
                    "http://"+i+":" + HttpPort + "/"
                };
                if (CertificateInfo != null)
                {
                    prefixes.Add("https://" + i + ":" + HttpsPort + "/");
                }
                return prefixes;
            });
        }
        /// 
        /// Starts the server.
        /// 
        private void StartServer()
        {
            try
            {
                ServerManager.Start(GetUrlPrefixes().ToArray());
                return;
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error starting http server", ex);
                if (HttpPort == ServerConfiguration.DefaultHttpPort)
                {
                    throw;
                }
            }
            HttpPort = ServerConfiguration.DefaultHttpPort;
            try
            {
                ServerManager.Start(GetUrlPrefixes().ToArray());
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error starting http server", ex);
                throw;
            }
        }
        private CertificateInfo GetCertificateInfo(bool generateCertificate)
        {
            if (!string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.CertificatePath))
            {
                // Custom cert
                return new CertificateInfo
                {
                    Path = ServerConfigurationManager.Configuration.CertificatePath,
                    Password = ServerConfigurationManager.Configuration.CertificatePassword
                };
            }
            // Generate self-signed cert
            var certHost = GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns);
            var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "2").GetMD5().ToString("N") + ".pfx");
            var password = "embycert";
            //if (generateCertificate)
            //{
            //    if (!FileSystemManager.FileExists(certPath))
            //    {
            //        FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath));
            //        try
            //        {
            //            CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger);
            //        }
            //        catch (Exception ex)
            //        {
            //            Logger.ErrorException("Error creating ssl cert", ex);
            //            return null;
            //        }
            //    }
            //}
            return new CertificateInfo
            {
                Path = certPath,
                Password = password
            };
        }
        /// 
        /// Called when [configuration updated].
        /// 
        /// The sender.
        /// The  instance containing the event data.
        protected void OnConfigurationUpdated(object sender, EventArgs e)
        {
            ConfigureAutorun();
            var requiresRestart = false;
            // Don't do anything if these haven't been set yet
            if (HttpPort != 0 && HttpsPort != 0)
            {
                // Need to restart if ports have changed
                if (ServerConfigurationManager.Configuration.HttpServerPortNumber != HttpPort ||
                    ServerConfigurationManager.Configuration.HttpsPortNumber != HttpsPort)
                {
                    if (ServerConfigurationManager.Configuration.IsPortAuthorized)
                    {
                        ServerConfigurationManager.Configuration.IsPortAuthorized = false;
                        ServerConfigurationManager.SaveConfiguration();
                        requiresRestart = true;
                    }
                }
            }
            if (!HttpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
            {
                requiresRestart = true;
            }
            var currentCertPath = CertificateInfo == null ? null : CertificateInfo.Path;
            var newCertInfo = GetCertificateInfo(false);
            var newCertPath = newCertInfo == null ? null : newCertInfo.Path;
            if (!string.Equals(currentCertPath, newCertPath, StringComparison.OrdinalIgnoreCase))
            {
                requiresRestart = true;
            }
            if (requiresRestart)
            {
                Logger.Info("App needs to be restarted due to configuration change.");
                NotifyPendingRestart();
            }
        }
        /// 
        /// Notifies that the kernel that a change has been made that requires a restart
        /// 
        public void NotifyPendingRestart()
        {
            Logger.Info("App needs to be restarted.");
            var changed = !HasPendingRestart;
            HasPendingRestart = true;
            if (changed)
            {
                EventHelper.QueueEventIfNotNull(HasPendingRestartChanged, this, EventArgs.Empty, Logger);
            }
        }
        /// 
        /// Restarts this instance.
        /// 
        public void Restart()
        {
            if (!CanSelfRestart)
            {
                throw new PlatformNotSupportedException("The server is unable to self-restart. Please restart manually.");
            }
            if (IsShuttingDown)
            {
                return;
            }
            IsShuttingDown = true;
            Task.Run(async () =>
            {
                try
                {
                    await SessionManager.SendServerRestartNotification(CancellationToken.None).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Logger.ErrorException("Error sending server restart notification", ex);
                }
                Logger.Info("Calling RestartInternal");
                RestartInternal();
            });
        }
        protected abstract void RestartInternal();
        /// 
        /// Gets the composable part assemblies.
        /// 
        /// IEnumerable{Assembly}.
        protected IEnumerable GetComposablePartAssemblies()
        {
            var list = GetPluginAssemblies()
                .ToList();
            // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that
            // This will prevent the .dll file from getting locked, and allow us to replace it when needed
            // Include composable parts in the Api assembly 
            list.Add(GetAssembly(typeof(ApiEntryPoint)));
            // Include composable parts in the Dashboard assembly 
            list.Add(GetAssembly(typeof(DashboardService)));
            // Include composable parts in the Model assembly 
            list.Add(GetAssembly(typeof(SystemInfo)));
            // Include composable parts in the Common assembly 
            list.Add(GetAssembly(typeof(IApplicationHost)));
            // Include composable parts in the Controller assembly 
            list.Add(GetAssembly(typeof(IServerApplicationHost)));
            // Include composable parts in the Providers assembly 
            list.Add(GetAssembly(typeof(ProviderUtils)));
            // Include composable parts in the Photos assembly 
            list.Add(GetAssembly(typeof(PhotoProvider)));
            // Emby.Server implementations
            list.Add(GetAssembly(typeof(InstallationManager)));
            // MediaEncoding
            list.Add(GetAssembly(typeof(MediaEncoding.Encoder.MediaEncoder)));
            // Dlna 
            list.Add(GetAssembly(typeof(DlnaEntryPoint)));
            // Local metadata 
            list.Add(GetAssembly(typeof(BoxSetXmlSaver)));
            // Xbmc 
            list.Add(GetAssembly(typeof(ArtistNfoProvider)));
            list.AddRange(GetAssembliesWithPartsInternal());
            return list.ToList();
        }
        protected abstract List GetAssembliesWithPartsInternal();
        /// 
        /// Gets the plugin assemblies.
        /// 
        /// IEnumerable{Assembly}.
        private IEnumerable GetPluginAssemblies()
        {
            try
            {
                return Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly)
                    .Where(EnablePlugin)
                    .Select(LoadAssembly)
                    .Where(a => a != null)
                    .ToList();
            }
            catch (DirectoryNotFoundException)
            {
                return new List();
            }
        }
        private bool EnablePlugin(string path)
        {
            var filename = Path.GetFileName(path);
            var exclude = new[]
            {
                "mbplus.dll",
                "mbintros.dll",
                "embytv.dll",
                "Messenger.dll",
                "MediaBrowser.Plugins.TvMazeProvider.dll",
                "MBBookshelf.dll",
                "MediaBrowser.Channels.Adult.YouJizz.dll",
                "MediaBrowser.Channels.Vine-co.dll",
                "MediaBrowser.Plugins.Vimeo.dll",
                "MediaBrowser.Channels.Vevo.dll",
                "MediaBrowser.Plugins.Twitch.dll",
                "MediaBrowser.Channels.SvtPlay.dll",
                "MediaBrowser.Plugins.SoundCloud.dll",
                "MediaBrowser.Plugins.SnesBox.dll",
                "MediaBrowser.Plugins.RottenTomatoes.dll",
                "MediaBrowser.Plugins.Revision3.dll",
                "MediaBrowser.Plugins.NesBox.dll",
                "MBChapters.dll",
                "MediaBrowser.Channels.LeagueOfLegends.dll",
                "MediaBrowser.Plugins.ADEProvider.dll",
                "MediaBrowser.Channels.BallStreams.dll",
                "MediaBrowser.Channels.Adult.Beeg.dll",
                "ChannelDownloader.dll",
                "Hamstercat.Emby.EmbyBands.dll",
                "EmbyTV.dll",
                "MediaBrowser.Channels.HitboxTV.dll",
                "MediaBrowser.Channels.HockeyStreams.dll",
                "MediaBrowser.Plugins.ITV.dll",
                "MediaBrowser.Plugins.Lastfm.dll"
            };
            return !exclude.Contains(filename ?? string.Empty, StringComparer.OrdinalIgnoreCase);
        }
        /// 
        /// Gets the system status.
        /// 
        /// SystemInfo.
        public async Task GetSystemInfo()
        {
            var localAddress = await GetLocalApiUrl().ConfigureAwait(false);
            return new SystemInfo
            {
                HasPendingRestart = HasPendingRestart,
                IsShuttingDown = IsShuttingDown,
                Version = ApplicationVersion.ToString(),
                WebSocketPortNumber = HttpPort,
                FailedPluginAssemblies = FailedAssemblies.ToArray(),
                InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToArray(),
                CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(),
                Id = SystemId,
                ProgramDataPath = ApplicationPaths.ProgramDataPath,
                LogPath = ApplicationPaths.LogDirectoryPath,
                ItemsByNamePath = ApplicationPaths.ItemsByNamePath,
                InternalMetadataPath = ApplicationPaths.InternalMetadataPath,
                CachePath = ApplicationPaths.CachePath,
                MacAddress = GetMacAddress(),
                HttpServerPortNumber = HttpPort,
                SupportsHttps = SupportsHttps,
                HttpsPortNumber = HttpsPort,
                OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
                OperatingSystemDisplayName = OperatingSystemDisplayName,
                CanSelfRestart = CanSelfRestart,
                CanSelfUpdate = CanSelfUpdate,
                WanAddress = ConnectManager.WanApiAddress,
                HasUpdateAvailable = HasUpdateAvailable,
                SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
                TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
                ServerName = FriendlyName,
                LocalAddress = localAddress,
                SupportsLibraryMonitor = true,
                EncoderLocationType = MediaEncoder.EncoderLocationType,
                SystemArchitecture = EnvironmentInfo.SystemArchitecture,
                SystemUpdateLevel = SystemUpdateLevel,
                PackageName = StartupOptions.GetOption("-package")
            };
        }
        public bool EnableHttps
        {
            get
            {
                return SupportsHttps && (ServerConfigurationManager.Configuration.EnableHttps || ServerConfigurationManager.Configuration.RequireHttps);
            }
        }
        public bool SupportsHttps
        {
            get { return Certificate != null || ServerConfigurationManager.Configuration.IsBehindProxy; }
        }
        public async Task GetLocalApiUrl()
        {
            try
            {
                // Return the first matched address, if found, or the first known local address
                var address = (await GetLocalIpAddresses().ConfigureAwait(false)).FirstOrDefault(i => !i.Equals(IpAddressInfo.Loopback) && !i.Equals(IpAddressInfo.IPv6Loopback));
                if (address != null)
                {
                    return GetLocalApiUrl(address);
                }
                return null;
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error getting local Ip address information", ex);
            }
            return null;
        }
        public string GetLocalApiUrl(IpAddressInfo ipAddress)
        {
            if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
            {
                return GetLocalApiUrl("[" + ipAddress.Address + "]");
            }
            return GetLocalApiUrl(ipAddress.Address);
        }
        public string GetLocalApiUrl(string host)
        {
            return string.Format("http://{0}:{1}",
                host,
                HttpPort.ToString(CultureInfo.InvariantCulture));
        }
        public async Task> GetLocalIpAddresses()
        {
            var addresses = ServerConfigurationManager
                .Configuration
                .LocalNetworkAddresses
                .Select(NormalizeConfiguredLocalAddress)
                .Where(i => i != null)
                .ToList();
            if (addresses.Count == 0)
            {
                addresses.AddRange(NetworkManager.GetLocalIpAddresses());
                var list = new List();
                foreach (var address in addresses)
                {
                    var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false);
                    if (valid)
                    {
                        list.Add(address);
                    }
                }
                addresses = list;
            }
            return addresses;
        }
        private IpAddressInfo NormalizeConfiguredLocalAddress(string address)
        {
            var index = address.Trim('/').IndexOf('/');
            if (index != -1)
            {
                address = address.Substring(index + 1);
            }
            IpAddressInfo result;
            if (NetworkManager.TryParseIpAddress(address.Trim('/'), out result))
            {
                return result;
            }
            return null;
        }
        private readonly ConcurrentDictionary _validAddressResults = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
        private DateTime _lastAddressCacheClear;
        private async Task IsIpAddressValidAsync(IpAddressInfo address)
        {
            if (address.Equals(IpAddressInfo.Loopback) ||
                address.Equals(IpAddressInfo.IPv6Loopback))
            {
                return true;
            }
            var apiUrl = GetLocalApiUrl(address);
            apiUrl += "/system/ping";
            if ((DateTime.UtcNow - _lastAddressCacheClear).TotalMinutes >= 15)
            {
                _lastAddressCacheClear = DateTime.UtcNow;
                _validAddressResults.Clear();
            }
            bool cachedResult;
            if (_validAddressResults.TryGetValue(apiUrl, out cachedResult))
            {
                return cachedResult;
            }
            try
            {
                using (var response = await HttpClient.SendAsync(new HttpRequestOptions
                {
                    Url = apiUrl,
                    LogErrorResponseBody = false,
                    LogErrors = false,
                    LogRequest = false,
                    TimeoutMs = 30000,
                    BufferContent = false
                }, "POST").ConfigureAwait(false))
                {
                    using (var reader = new StreamReader(response.Content))
                    {
                        var result = reader.ReadToEnd();
                        var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
                        _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
                        //Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, valid);
                        return valid;
                    }
                }
            }
            catch
            {
                //Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, false);
                _validAddressResults.AddOrUpdate(apiUrl, false, (k, v) => false);
                return false;
            }
        }
        public string FriendlyName
        {
            get
            {
                return string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.ServerName)
                    ? Environment.MachineName
                    : ServerConfigurationManager.Configuration.ServerName;
            }
        }
        public int HttpPort { get; private set; }
        public int HttpsPort { get; private set; }
        /// 
        /// Gets the mac address.
        /// 
        /// System.String.
        private string GetMacAddress()
        {
            try
            {
                return NetworkManager.GetMacAddress();
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error getting mac address", ex);
                return null;
            }
        }
        /// 
        /// Shuts down.
        /// 
        public async Task Shutdown()
        {
            if (IsShuttingDown)
            {
                return;
            }
            IsShuttingDown = true;
            try
            {
                await SessionManager.SendServerShutdownNotification(CancellationToken.None).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error sending server shutdown notification", ex);
            }
            ShutdownInternal();
        }
        protected abstract void ShutdownInternal();
        /// 
        /// Registers the server with administrator access.
        /// 
        private void RegisterServerWithAdministratorAccess()
        {
            Logger.Info("Requesting administrative access to authorize http server");
            try
            {
                AuthorizeServer();
            }
            catch (NotImplementedException)
            {
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error authorizing server", ex);
            }
        }
        protected virtual void AuthorizeServer()
        {
            throw new NotImplementedException();
        }
        public event EventHandler HasUpdateAvailableChanged;
        private bool _hasUpdateAvailable;
        public bool HasUpdateAvailable
        {
            get { return _hasUpdateAvailable; }
            set
            {
                var fireEvent = value && !_hasUpdateAvailable;
                _hasUpdateAvailable = value;
                if (fireEvent)
                {
                    EventHelper.FireEventIfNotNull(HasUpdateAvailableChanged, this, EventArgs.Empty, Logger);
                }
            }
        }
        /// 
        /// Removes the plugin.
        /// 
        /// The plugin.
        public void RemovePlugin(IPlugin plugin)
        {
            var list = Plugins.ToList();
            list.Remove(plugin);
            Plugins = list.ToArray();
        }
        /// 
        /// Checks for update.
        /// 
        /// The cancellation token.
        /// The progress.
        /// Task{CheckForUpdateResult}.
        public async Task CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress progress)
        {
            var updateLevel = SystemUpdateLevel;
            var cacheLength = updateLevel == PackageVersionClass.Release ?
                TimeSpan.FromHours(12) :
                TimeSpan.FromMinutes(5);
            try
            {
                var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser",
                    "Emby",
                    ApplicationVersion,
                    updateLevel,
                    ReleaseAssetFilename,
                    "MBServer",
                    UpdateTargetFileName,
                    cacheLength,
                    cancellationToken).ConfigureAwait(false);
                HasUpdateAvailable = result.IsUpdateAvailable;
                return result;
            }
            catch (HttpException ex)
            {
                // users are overreacting to this occasionally failing
                if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.Forbidden)
                {
                    HasUpdateAvailable = false;
                    return new CheckForUpdateResult
                    {
                        IsUpdateAvailable = false
                    };
                }
                throw;
            }
        }
        protected virtual string UpdateTargetFileName
        {
            get { return "Mbserver.zip"; }
        }
        /// 
        /// Updates the application.
        /// 
        /// The package that contains the update
        /// The cancellation token.
        /// The progress.
        public async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress progress)
        {
            await InstallationManager.InstallPackage(package, false, progress, cancellationToken).ConfigureAwait(false);
            HasUpdateAvailable = false;
            OnApplicationUpdated(package);
        }
        /// 
        /// Configures the automatic run at startup.
        /// 
        /// if set to true [autorun].
        protected void ConfigureAutoRunAtStartup(bool autorun)
        {
            if (SupportsAutoRunAtStartup)
            {
                ConfigureAutoRunInternal(autorun);
            }
        }
        protected virtual void ConfigureAutoRunInternal(bool autorun)
        {
            throw new NotImplementedException();
        }
        /// 
        /// This returns localhost in the case of no external dns, and the hostname if the 
        /// dns is prefixed with a valid Uri prefix.
        /// 
        /// The external dns prefix to get the hostname of.
        /// The hostname in 
        private static string GetHostnameFromExternalDns(string externalDns)
        {
            if (string.IsNullOrWhiteSpace(externalDns))
            {
                return "localhost";
            }
            try
            {
                return new Uri(externalDns).Host;
            }
            catch
            {
                return externalDns;
            }
        }
        public void LaunchUrl(string url)
        {
            if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows &&
                EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.OSX)
            {
                throw new NotImplementedException();
            }
            var process = ProcessFactory.Create(new ProcessOptions
            {
                FileName = url,
                //EnableRaisingEvents = true,
                UseShellExecute = true,
                ErrorDialog = false
            });
            process.Exited += ProcessExited;
            try
            {
                process.Start();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error launching url: {0}", url);
                Logger.ErrorException("Error launching url: {0}", ex, url);
                throw;
            }
        }
        private static void ProcessExited(object sender, EventArgs e)
        {
            ((IProcess)sender).Dispose();
        }
        public virtual void EnableLoopback(string appName)
        {
        }
        private void RegisterModules()
        {
            var moduleTypes = GetExportTypes();
            foreach (var type in moduleTypes)
            {
                try
                {
                    var instance = Activator.CreateInstance(type) as IDependencyModule;
                    if (instance != null)
                        instance.BindDependencies(this);
                }
                catch (Exception ex)
                {
                    Logger.ErrorException("Error setting up dependency bindings for " + type.Name, ex);
                }
            }
        }
        /// 
        /// Called when [application updated].
        /// 
        /// The package.
        protected void OnApplicationUpdated(PackageVersionInfo package)
        {
            Logger.Info("Application has been updated to version {0}", package.versionStr);
            EventHelper.FireEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs
            {
                Argument = package
            }, Logger);
            NotifyPendingRestart();
        }
        private bool _disposed;
        /// 
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// 
        public void Dispose()
        {
            if (!_disposed)
            {
                _disposed = true;
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }
        /// 
        /// Releases unmanaged and - optionally - managed resources.
        /// 
        /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
        protected virtual void Dispose(bool dispose)
        {
            if (dispose)
            {
                var type = GetType();
                LogManager.AddConsoleOutput();
                Logger.Info("Disposing " + type.Name);
                var parts = DisposableParts.Distinct().Where(i => i.GetType() != type).ToList();
                DisposableParts.Clear();
                foreach (var part in parts)
                {
                    Logger.Info("Disposing " + part.GetType().Name);
                    try
                    {
                        part.Dispose();
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorException("Error disposing {0}", ex, part.GetType().Name);
                    }
                }
            }
        }
        void IDependencyContainer.RegisterSingleInstance(T obj, bool manageLifetime)
        {
            RegisterSingleInstance(obj, manageLifetime);
        }
        void IDependencyContainer.RegisterSingleInstance(Func func)
        {
            RegisterSingleInstance(func);
        }
        void IDependencyContainer.Register(Type typeInterface, Type typeImplementation)
        {
            Container.Register(typeInterface, typeImplementation);
        }
    }
    internal class CertificateInfo
    {
        public string Path { get; set; }
        public string Password { get; set; }
    }
}