@Override
    public R pre(final Transfer.Type type, final Map<TransferItem, TransferStatus> files, final ConnectionCallback callback) throws BackgroundException {
        final Map<TransferItem, TransferStatus> encrypted = new HashMap<>(files.size());
        final ArrayList<Map.Entry<TransferItem, TransferStatus>> sorted = new ArrayList<>(files.entrySet());
        // Sort with folder first in list
        sorted.sort(new Comparator<Map.Entry<TransferItem, TransferStatus>>() {
            @Override
            public int compare(final Map.Entry<TransferItem, TransferStatus> o1, final Map.Entry<TransferItem, TransferStatus> o2) {
                return new PathPriorityComparator().compare(o1.getKey().remote, o2.getKey().remote);
            }
        });
        for(Map.Entry<TransferItem, TransferStatus> entry : sorted) {
            final Path file = entry.getKey().remote;
            final Local local = entry.getKey().local;
            final TransferStatus status = entry.getValue();
            if(null == status.getHeader()) {
                // Write header to be reused in writer
                final FileHeader header = cryptomator.getFileHeaderCryptor().create();
                status.setHeader(cryptomator.getFileHeaderCryptor().encryptHeader(header));
            }
            if(null == status.getNonces()) {
                status.setNonces(status.getLength() == TransferStatus.UNKNOWN_LENGTH ?
                        new RandomNonceGenerator(cryptomator.getNonceSize()) :
                        new RotatingNonceGenerator(cryptomator.getNonceSize(), cryptomator.numberOfChunks(status.getLength())));
            }
            if(file.isDirectory()) {
                if(!status.isExists()) {
                    switch(type) {
                        case upload:
                            // Preset directory ID for new folders to avert lookup with not found failure in directory ID provider
                            final String directoryId = random.random();
                            encrypted.put(new TransferItem(cryptomator.encrypt(session, file, directoryId, false), local), status);
                            break;
                        default:
                            encrypted.put(new TransferItem(cryptomator.encrypt(session, file), local), status);
                            break;
                    }
                }
                else {
                    encrypted.put(new TransferItem(cryptomator.encrypt(session, file), local), status);
                }
            }
            else {
                encrypted.put(new TransferItem(cryptomator.encrypt(session, file), local), status);
            }
        }
        return delegate.pre(type, encrypted, callback);
    }
@Test
    public void testPreDirectoryId() throws Exception {
        final Path vault = new Path("/vault", EnumSet.of(Path.Type.directory));
        final NullSession session = new NullSession(new Host(new TestProtocol())) {
            @Override
            @SuppressWarnings("unchecked")
            public <T> T _getFeature(final Class<T> type) {
                if(type == Directory.class) {
                    return (T) new Directory() {
                        @Override
                        public Path mkdir(final Path folder, final TransferStatus status) {
                            return folder;
                        }

                        @Override
                        public Directory withWriter(final Write writer) {
                            return this;
                        }
                    };
                }
                return super._getFeature(type);
            }
        };
        final CryptoVault cryptomator = new CryptoVault(vault);
        cryptomator.create(session, null, new VaultCredentials("test"));
        final CryptoBulkFeature<Map<TransferItem, TransferStatus>> bulk = new CryptoBulkFeature<Map<TransferItem, TransferStatus>>(session, new Bulk<Map<TransferItem, TransferStatus>>() {
            @Override
            public Map<TransferItem, TransferStatus> pre(final Transfer.Type type, final Map<TransferItem, TransferStatus> files, final ConnectionCallback callback) {
                return files;
            }

            @Override
            public void post(final Transfer.Type type, final Map<TransferItem, TransferStatus> files, final ConnectionCallback callback) {
                //
            }

            @Override
            public Bulk<Map<TransferItem, TransferStatus>> withDelete(final Delete delete) {
                return this;
            }

        }, new Delete() {
            @Override
            public void delete(final Map<Path, TransferStatus> files, final PasswordCallback prompt, final Callback callback) {
                throw new UnsupportedOperationException();
            }

            @Override
            public boolean isRecursive() {
                throw new UnsupportedOperationException();
            }
        }, cryptomator);
        final HashMap<TransferItem, TransferStatus> files = new HashMap<>();
        final Path directory = new Path("/vault/directory", EnumSet.of(Path.Type.directory));
        files.put(new TransferItem(directory, new Local("/tmp/vault/directory")), new TransferStatus().exists(false));
        files.put(new TransferItem(new Path(directory, "file1", EnumSet.of(Path.Type.file)), new Local("/tmp/vault/directory/file1")), new TransferStatus().exists(false));
        files.put(new TransferItem(new Path(directory, "file2", EnumSet.of(Path.Type.file)), new Local("/tmp/vault/directory/file2")), new TransferStatus().exists(false));
        final Map<TransferItem, TransferStatus> pre = bulk.pre(Transfer.Type.upload, files, new DisabledConnectionCallback());
        assertEquals(3, pre.size());
        final Path encryptedDirectory = pre.keySet().stream().filter(new Predicate<TransferItem>() {
            @Override
            public boolean test(final TransferItem item) {
                return item.remote.isDirectory();
            }
        }).findFirst().get().remote;
        final String directoryId = encryptedDirectory.attributes().getDirectoryId();
        assertNotNull(directoryId);
        for(TransferItem file : pre.keySet().stream().filter(new Predicate<TransferItem>() {
            @Override
            public boolean test(final TransferItem item) {
                return item.remote.isFile();
            }
        }).collect(Collectors.toSet())) {
            assertEquals(encryptedDirectory, file.remote.getParent());
            assertEquals(directoryId, file.remote.getParent().attributes().getDirectoryId());
        }
    }