/// <summary>
        /// Save the file to a new zipfile, with the given name.
        /// </summary>
        ///
        /// <remarks>
        /// <para>
        /// This method allows the application to explicitly specify the name of the zip
        /// file when saving. Use this when creating a new zip file, or when
        /// updating a zip archive.
        /// </para>
        ///
        /// <para>
        /// An application can also save a zip archive in several places by calling this
        /// method multiple times in succession, with different filenames.
        /// </para>
        ///
        /// <para>
        /// The <c>ZipFile</c> instance is written to storage, typically a zip file in a
        /// filesystem, only when the caller calls <c>Save</c>.  The Save operation writes
        /// the zip content to a temporary file, and then renames the temporary file
        /// to the desired name. If necessary, this method will delete a pre-existing file
        /// before the rename.
        /// </para>
        ///
        /// </remarks>
        ///
        /// <exception cref="System.ArgumentException">
        /// Thrown if you specify a directory for the filename.
        /// </exception>
        ///
        /// <param name="fileName">
        /// The name of the zip archive to save to. Existing files will
        /// be overwritten with great prejudice.
        /// </param>
        ///
        /// <example>
        /// This example shows how to create and Save a zip file.
        /// <code>
        /// using (ZipFile zip = new ZipFile())
        /// {
        ///   zip.AddDirectory(@"c:\reports\January");
        ///   zip.Save("January.zip");
        /// }
        /// </code>
        ///
        /// <code lang="VB">
        /// Using zip As New ZipFile()
        ///   zip.AddDirectory("c:\reports\January")
        ///   zip.Save("January.zip")
        /// End Using
        /// </code>
        ///
        /// </example>
        ///
        /// <example>
        /// This example shows how to update a zip file.
        /// <code>
        /// using (ZipFile zip = ZipFile.Read("ExistingArchive.zip"))
        /// {
        ///   zip.AddFile("NewData.csv");
        ///   zip.Save("UpdatedArchive.zip");
        /// }
        /// </code>
        ///
        /// <code lang="VB">
        /// Using zip As ZipFile = ZipFile.Read("ExistingArchive.zip")
        ///   zip.AddFile("NewData.csv")
        ///   zip.Save("UpdatedArchive.zip")
        /// End Using
        /// </code>
        ///
        /// </example>
        public static void Save(this ZipFile zipFile, String fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException("fileName");
            }

            string fullPath = GetFullPath(fileName);

            if (FileSystem.Current.GetFolderFromPathAsync(fullPath).ExecuteSync() != null)
            {
                throw new ZipException("Bad Directory", new ArgumentException("That name specifies an existing directory. Please specify a filename.", "fileName"));
            }

            var fullDirectoryName = Path.GetDirectoryName(fullPath);
            var directoryName     = Path.GetDirectoryName(fileName);
            var folder            = FileSystem.Current.GetFolderFromPathAsync(fullDirectoryName).ExecuteSync();

            if (folder == null)
            {
                throw new ZipException("Bad Directory", new ArgumentException(string.Format("That folder ({0}) does not exist!", directoryName)));
            }

            // check up here so we may shortcut some IO operations in the future :)
            var fileExists = folder.CheckExistsAsync(fullPath).ExecuteSync() == ExistenceCheckResult.FileExists;

            // write to a temporary file so that we can read from the same zip when saving
            var tmpName = Path.GetRandomFileName();

            try
            {
                ZipSegmentedStreamManager segmentsManager = null;

                if (zipFile.MaxOutputSegmentSize != 0)
                {
                    // save segmented files using the segments manager
                    var manager = new FileSystemZipSegmentedStreamManager(fullPath);
                    segmentsManager = manager;
                    zipFile.Save(segmentsManager);
                    tmpName = manager.TemporaryName;
                }
                else
                {
                    // save
                    var tmpFile = folder.CreateFileAsync(tmpName, CreationCollisionOption.ReplaceExisting).ExecuteSync();
                    tmpName = tmpFile.Path;
                    using (var tmpStream = tmpFile.OpenAsync(FileAccess.ReadAndWrite).ExecuteSync())
                    {
                        zipFile.Save(tmpStream);
                    }
                }

                // if it wasn't canceled
                if (!zipFile.IsSaveOperationCanceled())
                {
                    // disconnect from the stream
                    zipFile.SetUnderlyingZipStream(null);
                    // move the temporary file into position
                    zipFile.OnSaveEvent(ZipProgressEventType.Saving_BeforeRenameTempArchive);
                    ZipEntryExtensions.MoveFileInPlace(fileExists, fullPath, tmpName);
                    zipFile.OnSaveEvent(ZipProgressEventType.Saving_AfterRenameTempArchive);
                    // and now set the read stream to be that of the new file
                    var targetFile = FileSystem.Current.GetFileFromPathAsync(fullPath).ExecuteSync();
                    var fileStream = targetFile.OpenAsync(FileAccess.Read).ExecuteSync();
                    zipFile.SetUnderlyingZipSegmentedStreamManager(segmentsManager);
                    zipFile.SetUnderlyingZipStream(fileStream);
                    zipFile.SetShouldDisposeReadStream(true);
                    zipFile.Name = fullPath;

                    // so we can shortcut the existance checks
                    tmpName = null;
                }
            }
            finally
            {
                // An exception has occurred. If the file exists, check
                // to see if it existed before we tried extracting.  If
                // it did not, attempt to remove the target file. There
                // is a small possibility that the existing file has
                // been extracted successfully, overwriting a previously
                // existing file, and an exception was thrown after that
                // but before final completion (setting times, etc). In
                // that case the file will remain, even though some
                // error occurred.  Nothing to be done about it.
                if (tmpName != null)
                {
                    var tmpFile = folder.GetFileAsync(tmpName).ExecuteSync();
                    tmpFile.DeleteAsync();
                }
            }
        }