package com.intellij.javascript.karma.server.watch;
import com.google.common.collect.ImmutableList;
import com.intellij.javascript.karma.server.KarmaServer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.vfs.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author Sergey Simonchik
*/
public class KarmaWatchSession {
public static final char SEPARATOR_CHAR = '/';
public static final String SEPARATOR = String.valueOf(SEPARATOR_CHAR);
private final KarmaChangedFilesManager myChangedFilesManager;
private final LocalFileSystem myFileSystem;
private final ImmutableList<KarmaWatchPattern> myWatchPatterns;
private final MyVirtualFileListener myVfsListener = new MyVirtualFileListener();
public KarmaWatchSession(@NotNull KarmaServer server, @NotNull final List<String> paths) {
myChangedFilesManager = new KarmaChangedFilesManager(server);
myFileSystem = LocalFileSystem.getInstance();
final List<KarmaWatchPattern> watchPatterns = ContainerUtil.newArrayList();
ApplicationManager.getApplication().runReadAction(() -> {
for (String path : paths) {
KarmaWatchPattern watchPattern = new KarmaWatchPattern(myFileSystem, myChangedFilesManager, path);
watchPatterns.add(watchPattern);
}
myFileSystem.addVirtualFileListener(myVfsListener);
});
myWatchPatterns = ImmutableList.copyOf(watchPatterns);
}
@Nullable
private String findWatchedOriginalPath(@NotNull VirtualFile file) {
for (KarmaWatchPattern watchPattern : myWatchPatterns) {
String watchedPath = watchPattern.findWatchedOriginalPath(file);
if (watchedPath != null) {
return watchedPath;
}
}
return null;
}
private void updateWatchPatterns() {
for (KarmaWatchPattern pattern : myWatchPatterns) {
pattern.update(true);
}
}
public void stop() {
ApplicationManager.getApplication().runReadAction(() -> {
for (KarmaWatchPattern watchPattern : myWatchPatterns) {
watchPattern.stopWatching();
}
myFileSystem.removeVirtualFileListener(myVfsListener);
});
}
public void flush() {
myChangedFilesManager.flush();
}
@NotNull
public static String join(@NotNull String path, @NotNull String subPath) {
if (path.endsWith(SEPARATOR)) {
path = path.substring(0, path.length() - 1);
}
if (subPath.startsWith(SEPARATOR)) {
subPath = subPath.substring(1);
}
return path + SEPARATOR + subPath;
}
private class MyVirtualFileListener implements VirtualFileListener {
@Override
public void propertyChanged(@NotNull VirtualFilePropertyEvent event) {
updateWatchPatterns();
if ("name".equals(event.getPropertyName())) {
VirtualFile parent = event.getParent();
if (parent != null) {
String parentWatchedPath = findWatchedOriginalPath(parent);
if (parentWatchedPath != null) {
String oldPath = join(parentWatchedPath, event.getOldValue().toString());
String newPath = join(parentWatchedPath, event.getNewValue().toString());
myChangedFilesManager.onFileRemoved(oldPath);
myChangedFilesManager.onFileAdded(newPath);
}
}
}
}
@Override
public void contentsChanged(@NotNull VirtualFileEvent event) {
VirtualFile file = event.getFile();
String watchedPath = findWatchedOriginalPath(file);
if (watchedPath != null) {
myChangedFilesManager.onFileChanged(watchedPath);
}
}
@Override
public void fileCreated(@NotNull VirtualFileEvent event) {
updateWatchPatterns();
VirtualFile file = event.getFile();
String watchedPath = findWatchedOriginalPath(file);
if (watchedPath != null) {
myChangedFilesManager.onFileAdded(watchedPath);
}
}
@Override
public void fileDeleted(@NotNull VirtualFileEvent event) {
updateWatchPatterns();
VirtualFile file = event.getFile();
String watchedPath = findWatchedOriginalPath(file);
if (watchedPath != null) {
myChangedFilesManager.onFileRemoved(watchedPath);
}
}
@Override
public void fileMoved(@NotNull VirtualFileMoveEvent event) {
updateWatchPatterns();
String fileName = event.getFileName();
VirtualFile oldParent = event.getOldParent();
String oldParentWatchedPath = findWatchedOriginalPath(oldParent);
if (oldParentWatchedPath != null) {
String oldPath = join(oldParentWatchedPath, fileName);
myChangedFilesManager.onFileRemoved(oldPath);
}
VirtualFile newParent = event.getNewParent();
String newParentWatchedPath = findWatchedOriginalPath(newParent);
if (newParentWatchedPath != null) {
String newPath = join(newParentWatchedPath, fileName);
myChangedFilesManager.onFileAdded(newPath);
}
}
@Override
public void fileCopied(@NotNull VirtualFileCopyEvent event) {
updateWatchPatterns();
VirtualFile file = event.getFile();
String watchedPath = findWatchedOriginalPath(file);
if (watchedPath != null) {
myChangedFilesManager.onFileAdded(watchedPath);
}
}
}
}