class DiagnosticsReporter {

    public void dump( Set<String> classifiers, Path destination, DiagnosticsReporterProgress progress, boolean force ) throws IOException
    {
        // Collect sources
        List<DiagnosticsReportSource> sources = new ArrayList<>();
        for ( DiagnosticsOfflineReportProvider provider : providers )
        {
            sources.addAll( provider.getDiagnosticsSources( classifiers ) );
        }

        // Add additional sources
        for ( Map.Entry<String,List<DiagnosticsReportSource>> classifier : additionalSources.entrySet() )
        {
            if ( classifiers.contains( "all" ) || classifiers.contains( classifier.getKey() ) )
            {
                sources.addAll( classifier.getValue() );
            }
        }

        // Make sure target directory exists
        Path destinationFolder = destination.getParent();
        Files.createDirectories( destinationFolder );

        // Estimate an upper bound of the final size and make sure it will fit, if not, end reporting
        estimateSizeAndCheckAvailableDiskSpace( destination, progress, sources, destinationFolder, force );

        // Compress all files to destination
        Map<String, Object> env = new HashMap<>();
        env.put( "create", "true" );
        env.put( "useTempFile", Boolean.TRUE );

        // NOTE: we need the toUri() in order to handle windows file paths
        URI uri = URI.create("jar:file:" + destination.toAbsolutePath().toUri().getRawPath() );

        try ( FileSystem fs = FileSystems.newFileSystem( uri, env ) )
        {
            progress.setTotalSteps( sources.size() );
            for ( int i = 0; i < sources.size(); i++ )
            {
                DiagnosticsReportSource source = sources.get( i );
                Path path = fs.getPath( source.destinationPath() );
                if ( path.getParent() != null )
                {
                    Files.createDirectories( path.getParent() );
                }

                progress.started( i + 1, path.toString() );
                try
                {
                    source.addToArchive( path, progress );
                }
                catch ( Throwable e )
                {
                    progress.error( "Step failed", e );
                    continue;
                }
                progress.finished();
            }
        }
    }

}