package jetbrains.mps.ide.platform.watching;
/*Generated by MPS */
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;
import java.util.Map;
import jetbrains.mps.vfs.FileSystemListener;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import java.util.HashMap;
import java.util.Queue;
import jetbrains.mps.internal.collections.runtime.QueueSequence;
import java.util.LinkedList;
import jetbrains.mps.ide.vfs.IdeaFileSystem;
import jetbrains.mps.vfs.FileSystemExtPoint;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import jetbrains.mps.internal.collections.runtime.Sequence;
import org.jetbrains.mps.openapi.util.SubProgressKind;
import java.util.Set;
import java.util.LinkedHashSet;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import com.intellij.openapi.vfs.VirtualFile;
import jetbrains.mps.fileTypes.MPSFileTypesManager;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.ide.vfs.IdeaFile;
import jetbrains.mps.internal.collections.runtime.IVisitor;
import jetbrains.mps.internal.collections.runtime.ISelector;
import jetbrains.mps.InternalFlag;
import jetbrains.mps.vfs.FileSystemEvent;
import java.util.HashSet;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public class FileProcessor extends ReloadParticipant {
private static final Logger LOG = LogManager.getLogger(FileProcessor.class);
private FileSystemListenersContainer listenersContainer;
private Map<FileSystemListener, FileProcessor.ListenerData> dataMap = MapSequence.fromMap(new HashMap<FileSystemListener, FileProcessor.ListenerData>());
private Queue<FileSystemListener> postNotify = QueueSequence.fromQueue(new LinkedList<FileSystemListener>());
private static final IdeaFileSystem FS = ((IdeaFileSystem) FileSystemExtPoint.getFS());
public FileProcessor() {
listenersContainer = FS.getListenersContainer();
}
@Override
public void update(ProgressMonitor monitor) {
if (MapSequence.fromMap(dataMap).isEmpty()) {
return;
}
monitor.start("", MapSequence.fromMap(dataMap).count() + 1);
long updateStartTime = System.currentTimeMillis();
try {
for (FileSystemListener listener : Sequence.fromIterable(sortedListeners())) {
FileProcessor.ListenerData data = MapSequence.fromMap(dataMap).get(listener);
if (!(listenersContainer.contains(listener))) {
monitor.advance(1);
continue;
}
long listenerUpdateStartTime = System.currentTimeMillis();
listener.update(monitor.subTask(1, SubProgressKind.AS_COMMENT), data);
printStat("update:" + listener, listenerUpdateStartTime);
data.isNotified = true;
}
long postNotifyBeginTime = System.currentTimeMillis();
FileSystemListener listener;
while ((listener = QueueSequence.fromQueue(postNotify).removeFirstElement()) != null) {
FileProcessor.ListenerData data = MapSequence.fromMap(dataMap).get(listener);
if (data.isNotified) {
continue;
}
listener.update(monitor.subTask(0, SubProgressKind.AS_COMMENT), data);
data.isNotified = true;
}
printStat("post-notify", postNotifyBeginTime);
} finally {
printStat("update", updateStartTime);
monitor.done();
}
}
private void notify(FileSystemListener listener, FileProcessor.ListenerData source) {
FileProcessor.ListenerData data = MapSequence.fromMap(dataMap).get(listener);
if (data == null) {
data = new FileProcessor.ListenerData();
MapSequence.fromMap(dataMap).put(listener, data);
QueueSequence.fromQueue(postNotify).addLastElement(listener);
} else if (data.isNotified) {
return;
}
data.added.addAll(source.added);
data.changed.addAll(source.changed);
data.removed.addAll(source.removed);
}
private Iterable<FileSystemListener> sortedListeners() {
Set<FileSystemListener> result = new LinkedHashSet<FileSystemListener>(MapSequence.fromMap(dataMap).count());
for (FileSystemListener l : SetSequence.fromSet(MapSequence.fromMap(dataMap).keySet())) {
visit(l, result);
}
return result;
}
private void visit(FileSystemListener listener, Set<FileSystemListener> result) {
if (result.contains(listener)) {
return;
}
result.add(listener);
Iterable<FileSystemListener> dependencies = listener.getListenerDependencies();
if (dependencies == null) {
return;
}
boolean readd = false;
for (FileSystemListener dep : dependencies) {
if (MapSequence.fromMap(dataMap).containsKey(dep) && !(result.contains(dep))) {
visit(dep, result);
readd = true;
}
}
if (readd) {
result.remove(listener);
result.add(listener);
}
}
protected boolean accepts(VirtualFile file) {
return !(MPSFileTypesManager.isFileIgnored(file.getPath()));
}
protected void processDelete(VirtualFile file) {
final IFile ifile = new IdeaFile(FS, file);
Sequence.fromIterable(get(ifile.getPath())).visitAll(new IVisitor<FileProcessor.ListenerData>() {
public void visit(FileProcessor.ListenerData it) {
it.removed.add(ifile);
}
});
}
protected void processCreate(VirtualFile file) {
String path = file.getPath();
final IFile ifile = FS.getFile(path);
Sequence.fromIterable(get(path)).visitAll(new IVisitor<FileProcessor.ListenerData>() {
public void visit(FileProcessor.ListenerData it) {
it.added.add(ifile);
}
});
}
protected void processContentChanged(VirtualFile file) {
String path = file.getPath();
final IFile ifile = FS.getFile(path);
Sequence.fromIterable(get(path)).visitAll(new IVisitor<FileProcessor.ListenerData>() {
public void visit(FileProcessor.ListenerData it) {
it.changed.add(ifile);
}
});
}
@Override
public boolean isEmpty() {
return MapSequence.fromMap(dataMap).isEmpty();
}
public Iterable<FileProcessor.ListenerData> get(String path) {
return Sequence.fromIterable(listenersContainer.listeners(path)).select(new ISelector<FileSystemListener, FileProcessor.ListenerData>() {
public FileProcessor.ListenerData select(FileSystemListener it) {
FileProcessor.ListenerData data = MapSequence.fromMap(dataMap).get(it);
if (data == null) {
data = new FileProcessor.ListenerData();
MapSequence.fromMap(dataMap).put(it, data);
}
return data;
}
});
}
private void printStat(String name, long beginTime) {
// todo: ideal for AOP in MPS!
if (InternalFlag.isInternalMode()) {
if (LOG.isDebugEnabled()) {
LOG.debug("FileProcessor: " + name + " -> " + (System.currentTimeMillis() - beginTime) / 1000.0 + "s");
}
}
}
private class ListenerData implements FileSystemEvent {
private Set<IFile> added = new HashSet<IFile>();
private Set<IFile> removed = new HashSet<IFile>();
private Set<IFile> changed = new HashSet<IFile>();
private boolean isNotified;
private ListenerData() {
}
@Override
public Set<IFile> getCreated() {
return added;
}
@Override
public Set<IFile> getRemoved() {
return removed;
}
@Override
public Set<IFile> getChanged() {
return changed;
}
@Override
public void notify(FileSystemListener listener) {
FileProcessor.this.notify(listener, this);
}
@Override
public String toString() {
return String.format("[added: %s; removed: %s; changed: %s.", setToString(added), setToString(removed), setToString(changed));
}
@NotNull
private String setToString(Set<?> set) {
return Arrays.toString(set.toArray());
}
}
}