/// <summary>
        /// Perform backup on the specified media
        /// </summary>
        public void Backup(BackupMedia media, String password = null)
        {
            // Make a determination that the user is allowed to perform this action
            if (AuthenticationContext.Current.Principal != AuthenticationContext.SystemPrincipal)
            {
                new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, PermissionPolicyIdentifiers.ExportClinicalData).Demand();
            }

            // Get the output medium
            var    directoryName = this.GetBackupDirectory(media);
            string fileName      = Path.Combine(directoryName, $"sdbdc-{DateTime.Now.ToString("yyyy-MM-dd-HH-mm")}.tar");

            // Confirm if the user really really wants to backup
            if (String.IsNullOrEmpty(password) &&
                !ApplicationContext.Current.Confirm(Strings.locale_backup_confirm))
            {
                return;
            }

            // TODO: Audit the backup to the data to the central server
            AuditUtil.AuditDataExport();

            // Try to backup the data
            try
            {
                this.m_tracer.TraceInfo("Beginning backup to {0}..", fileName);
                ApplicationContext.Current?.SetProgress(Strings.locale_backup, 0.25f);
                // Backup folders first
                var sourceDirectory = ApplicationContext.Current.ConfigurationPersister.ApplicationDataDirectory;
                try
                {
                    using (var fs = File.Create(fileName))
                        using (var writer = new SharpCompress.Writers.Tar.TarWriter(fs, new TarWriterOptions(SharpCompress.Common.CompressionType.None, true)))
                        {
                            this.BackupDirectory(writer, sourceDirectory, sourceDirectory);

                            var appInfo = new DiagnosticReport()
                            {
                                ApplicationInfo = new DiagnosticApplicationInfo(AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(o => o.DefinedTypes.Any(t => t.Name == "Program" || t.Name == "SplashActivity")) ?? typeof(SanteDBConfiguration).Assembly)
                            };

                            // Output appInfo
                            using (var ms = new MemoryStream())
                            {
                                XmlSerializer xsz = XmlModelSerializerFactory.Current.CreateSerializer(appInfo.GetType());
                                xsz.Serialize(ms, appInfo);
                                ms.Flush();
                                ms.Seek(0, SeekOrigin.Begin);
                                writer.Write(".appinfo.xml", ms, DateTime.Now);
                            }

                            // Output declaration statement
                            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes($"User {(AuthenticationContext.Current?.Principal?.Identity?.Name ?? "SYSTEM")} created this backup on {DateTime.Now}. The end user was asked to confirm this decision to backup and acknolwedges all responsibilities for guarding this file.")))
                                writer.Write("DISCLAIMER.TXT", ms, DateTime.Now);

                            // Output databases
                            var dcc = ApplicationServiceContext.Current.GetService <IDataManagementService>();
                            var dbBackupLocation = dcc.Backup("");
                            this.BackupDirectory(writer, dbBackupLocation, dbBackupLocation);
                            try
                            {
                                Directory.Delete(dbBackupLocation, true);
                            }
                            catch { }

                            // Now include the configuration file
                            // HACK: This is a total hack to support restore in place
                            if (!String.IsNullOrEmpty(password))
                            {
                                using (var ms = new MemoryStream())
                                {
                                    ApplicationServiceContext.Current.GetService <IConfigurationManager>().Configuration.Save(ms);
                                    ms.Seek(0, SeekOrigin.Begin);
                                    var config = SanteDBConfiguration.Load(ms); /// Load a new copy off the stream
                                    // Set the security system not to encrypt the device secret
                                    config.GetSection <SecurityConfigurationSection>().PlainTextSecret = true;
                                    using (var oms = new MemoryStream())
                                    {
                                        config.Save(oms);
                                        oms.Flush();
                                        oms.Seek(0, SeekOrigin.Begin);
                                        writer.Write("santedb.config", oms, DateTime.Now);
                                    }
                                }
                            }
                        }

                    this.m_tracer.TraceInfo("Beginning compression {0}..", fileName);

                    using (var fileStream = File.Create(Path.ChangeExtension(fileName, "sdbk")))
                    {
                        Stream outStream = fileStream;
                        try
                        {
                            // Write header
                            fileStream.Write(MAGIC, 0, MAGIC.Length);

                            // Encrypt
                            if (!String.IsNullOrEmpty(password))
                            {
                                fileStream.WriteByte(1);

                                var cryptProvider = AesCryptoServiceProvider.Create();
                                var passKey       = ASCIIEncoding.ASCII.GetBytes(password);
                                passKey           = Enumerable.Range(0, 32).Select(o => passKey.Length > o ? passKey[o] : (byte)0).ToArray();
                                cryptProvider.Key = passKey;

                                cryptProvider.GenerateIV();
                                fileStream.Write(BitConverter.GetBytes(cryptProvider.IV.Length), 0, 4);
                                fileStream.Write(cryptProvider.IV, 0, cryptProvider.IV.Length);
                                outStream = new CryptoStream(fileStream, cryptProvider.CreateEncryptor(), CryptoStreamMode.Write);
                            }
                            else
                            {
                                fileStream.WriteByte(0);
                            }
                            using (var fs = File.OpenRead(fileName))
                                using (var gzs = new GZipStream(outStream, CompressionMode.Compress))
                                {
                                    fs.CopyTo(gzs);
                                }
                        }
                        finally
                        {
                            if (outStream != fileStream)
                            {
                                outStream.Close();
                            }
                        }
                    }
                }
                finally
                {
                    File.Delete(fileName);
                }
            }
            catch (Exception ex)
            {
                this.m_tracer.TraceError("Error backing up to {0}: {1}", fileName, ex);
                throw;
            }
        }