// Copyright 2016 Eivind Vegsundvåg
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ninja.eivind.hotsreplayuploader.files.tempwatcher;
import javafx.concurrent.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.util.function.Consumer;
import static java.nio.file.StandardWatchEventKinds.*;
public class RecursiveTempWatcher extends TempWatcher {
private static final Logger logger = LoggerFactory.getLogger(RecursiveTempWatcher.class);
private final BattleLobbyTempDirectories tempDirectories;
private final File newRoot;
private final String firstChild;
private final TempWatcher child;
public RecursiveTempWatcher(BattleLobbyTempDirectories tempDirectories) {
this.tempDirectories = tempDirectories;
final File root = tempDirectories.getRoot();
final File remainder = tempDirectories.getRemainder();
String relativeRemainder = getRelativeRemainder(root, remainder);
if (relativeRemainder.startsWith(File.separator)) {
relativeRemainder = relativeRemainder.substring(1);
}
final String remainderRegex = getRemainderRegex();
String[] splitRemainder = relativeRemainder.split(remainderRegex);
firstChild = splitRemainder[0];
newRoot = new File(root, firstChild);
child = getChild(relativeRemainder, firstChild, newRoot);
}
@Override
public void start() {
if (child.isRunning()) {
child.cancel();
}
super.start();
if (newRoot.exists()) {
child.start();
}
}
@Override
protected Task<Void> createTask() {
return new WatcherTask();
}
protected String getRemainderRegex() {
final String remainderRegex;
if (File.separator.equals("\\")) {
remainderRegex = File.separator + File.separator;
} else {
remainderRegex = File.separator;
}
return remainderRegex;
}
private TempWatcher getChild(String relativeRemainder, String firstChild, File newRoot) {
if (relativeRemainder.contains(File.separator)) {
final String remainingChildren = relativeRemainder.replace(firstChild + File.separator, "");
final File newRemainder = new File(newRoot, remainingChildren);
return new RecursiveTempWatcher(new BattleLobbyTempDirectories(newRoot, newRemainder));
} else {
return new BattleLobbyWatcher(newRoot);
}
}
@Override
public boolean cancel() {
return child.cancel() && super.cancel();
}
@Override
public int getChildCount() {
return child.getChildCount() + 1;
}
@Override
public Consumer<File> getCallback() {
return child.getCallback();
}
@Override
public void setCallback(Consumer<File> callback) {
child.setCallback(callback);
}
protected TempWatcher getChild() {
return child;
}
private String getRelativeRemainder(File root, File remainder) {
String remainderString = remainder.toString().replace(root.toString(), "");
if (remainderString.startsWith(File.pathSeparator)) {
return remainderString.replace(File.pathSeparator, "");
}
return remainderString;
}
private class WatcherTask extends Task<Void> {
@Override
protected Void call() throws Exception {
final File root = tempDirectories.getRoot();
logger.info("Starting watch for {} in {}", firstChild, root);
final Path path = root.toPath();
try {
Thread.sleep(50L);
try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
path.register(watchService, ENTRY_CREATE, ENTRY_DELETE);
while (true) {
WatchKey key = watchService.take();
key.pollEvents().forEach(event -> {
WatchEvent.Kind<?> kind = event.kind();
if (kind == OVERFLOW) {
return;
}
@SuppressWarnings("unchecked")
final WatchEvent<Path> pathEvent = (WatchEvent<Path>) event;
final Path pathName = pathEvent.context();
if (pathName.toString().equals(firstChild.replaceAll(File.pathSeparator, ""))) {
if (kind == ENTRY_CREATE) {
child.start();
} else if (kind == ENTRY_DELETE) {
child.cancel();
}
}
});
if (!key.reset()) {
break;
}
}
} catch (IOException e) {
logger.error("Watcher threw exception", e);
}
} catch (InterruptedException e) {
logger.info("Watcher for {} in {} interrupted", firstChild, root);
}
return null;
}
}
}