package aQute.bnd.main.testrules;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.junit.rules.TemporaryFolder;

import aQute.lib.io.IO;

/**
 * The Class WatchedTemporaryFolder.
 */
public class WatchedTemporaryFolder extends TemporaryFolder implements WatchedFolder {

	private Map<Path, String>		snapshotData	= Collections.unmodifiableMap(new HashMap<>());

	private Function<Path, String>	snapshotFunc	= p -> "";

	public WatchedTemporaryFolder() {
		super(getParent());
	}

	private static File getParent() {
		File parent = IO.getFile("generated/tmp/test");
		try {
			IO.mkdirs(parent);
		} catch (IOException e) {
			throw new UncheckedIOException(e);
		}
		return parent;
	}

	@Override
	public Path getRootPath() {
		return getRoot().toPath();
	}

	@Override
	public WatchedFolder copyDataFrom(Path p) throws IOException {
		IO.copy(p.toFile()
			.getAbsoluteFile(), getRoot());

		return this;
	}

	@Override
	public void snapshot(Function<Path, String> func) throws RuntimeException {
		snapshot(func, 0);
	}

	@Override
	public void snapshot(Function<Path, String> func, long delay) throws RuntimeException {
		try {
		snapshotFunc = func;
		snapshotData = Collections.unmodifiableMap(Files.walk(getRootPath())
			.collect(Collectors.toMap((Path p) -> p, p -> func.apply(p))));
			Thread.sleep(delay);
		} catch (InterruptedException | IOException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public WatchedFolder.FileStatus checkFile(Path relPath) {
		return computeFileStatus(getRootPath().resolve(relPath));
	}

	@Override
	public File getFile(String relPath) {
		return getRootPath().resolve(relPath)
			.toFile();
	}

	@Override
	public void print(PrintStream printStream, boolean relativize) throws IOException {
		Files.walk(getRootPath())
			.forEach(p -> printStream.println(relativize ? getRootPath().relativize(p) : p));
	}

	@Override
	public Map<Path, FileStatus> createFileStatistic(boolean relativize) throws IOException {
		// walk over all files (created, modified, unmodified)
		Map<Path, FileStatus> result = Files.walk(getRootPath())
			.collect(Collectors.toMap((Path p) -> (relativize ? getRootPath().relativize(p) : p),
				p -> computeFileStatus(p)));

		// add deleted files
		Map<Path, FileStatus> deleted = snapshotData.keySet()
			.stream()
			.map(p -> getRootPath().relativize(p))
			.filter(p -> !result.containsKey(p))
			.collect(Collectors.toMap((Path p) -> p, p -> FileStatus.DELETED));

		result.putAll(deleted);

		return result;
	}

	private WatchedFolder.FileStatus computeFileStatus(final Path p) {
		final boolean snapshotFound = snapshotData.containsKey(p);

		if (Files.exists(p)) {
			if (!snapshotFound) {
				return FileStatus.CREATED;
			}

			return snapshotData.get(p)
				.equals(snapshotFunc.apply(p)) ? FileStatus.UNMODIFIED_EXISTS : FileStatus.MODIFIED;
		}

		return snapshotFound ? FileStatus.DELETED : FileStatus.UNMODIFIED_NOT_EXISTS;
	}
}

@@ -24,24 +24,77 @@
 testrules;%0A%0A
+import static java.util.function.Function.identity;%0A%0A
 import java.
@@ -1177,39 +1177,8 @@
 py(p
-.toFile()%0A%09%09%09.getAbsoluteFile()
 , ge
@@ -1182,22 +1182,25 @@
  getRoot
+Path
 ());%0A
-%0A
 %09%09return
@@ -1275,32 +1275,8 @@
 unc)
- throws RuntimeException
  %7B%0A%09
@@ -1376,32 +1376,8 @@
 lay)
- throws RuntimeException
  %7B%0A%09
@@ -1383,16 +1383,17 @@
 %09%09try %7B%0A
+%09
 %09%09snapsh
@@ -1407,16 +1407,17 @@
 = func;%0A
+%09
 %09%09snapsh
@@ -1474,32 +1474,33 @@
 tRootPath())%0A%09%09%09
+%09
 .collect(Collect
@@ -1513,41 +1513,32 @@
 Map(
-(Path p) -%3E p, p -%3E func.apply(p)
+identity(), snapshotFunc
 )));
@@ -1993,16 +1993,104 @@
 ption %7B%0A
+%09%09Function%3CPath, Path%3E keyMapper = relativize ? getRootPath()::relativize : identity();%0A
 %09%09Files.
@@ -2105,24 +2105,43 @@
 RootPath())%0A
+%09%09%09.map(keyMapper)%0A
 %09%09%09.forEach(
@@ -2140,21 +2140,16 @@
 forEach(
-p -%3E 
 printStr
@@ -2155,62 +2155,17 @@
 ream
-.
+::
 println
-(relativize ? getRootPath().relativize(p) : p)
 );%0A%09
@@ -2269,16 +2269,104 @@
 ption %7B%0A
+%09%09Function%3CPath, Path%3E keyMapper = relativize ? getRootPath()::relativize : identity();%0A
 %09%09// wal
@@ -2506,77 +2506,25 @@
 Map(
-(Path p) -%3E (relativize ? getRootPath().relativize(p) : p),%0A%09%09%09%09p -%3E 
+keyMapper, this::
 comp
@@ -2536,19 +2536,16 @@
 leStatus
-(p)
 ));%0A%0A%09%09/
@@ -2645,40 +2645,17 @@
 map(
-p -%3E getRootPath().relativize(p)
+keyMapper
 )%0A%09%09
@@ -2725,21 +2725,18 @@
 Map(
-(Path p) -%3E p
+identity()
 , p 
@@ -2861,22 +2861,16 @@
 eStatus(
-final 
 Path p) 
@@ -2932,17 +2932,16 @@
 Key(p);%0A
-%0A
 %09%09if (Fi
@@ -3018,17 +3018,16 @@
 D;%0A%09%09%09%7D%0A
-%0A
 %09%09%09retur
@@ -3141,17 +3141,16 @@
 ED;%0A%09%09%7D%0A
-%0A
 %09%09return

Clean up lambda expressions in test class