/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.compiler;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.Closeables;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.io.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
public class FileDependencyCache {
private final Map<VirtualFile, FileDependencyInfo> cache = Maps.newHashMap();
private final Map<VirtualFile, Set<VirtualFile>> dependsOnCache = Maps.newHashMap();
private final Map<String, Set<VirtualFile>> displayKeyDependsOnCache = Maps.newHashMap();
private final Map<VirtualFile, Set<String>> displayKeys = Maps.newHashMap();
public int size() {
return cache.size();
}
public FileDependencyInfo get(VirtualFile file) {
return cache.get(checkNotNull(file));
}
public Set<VirtualFile> keySet() {
return cache.keySet();
}
public Collection<FileDependencyInfo> values() {
return cache.values();
}
public FileDependencyInfo put(@NotNull FileDependencyInfo info) {
checkNotNull(info);
final VirtualFile file = info.getFile();
for (VirtualFile fileDependency : info.getDependencies()) {
getDependentsOn(fileDependency).add(file);
}
for (String keyDependency : info.getDisplayKeys()) {
getDependentsOnByDisplayKey(keyDependency).add(file);
}
if ("display.properties".equals(file.getName())) {
handleDisplayKeys(file);
}
return cache.put(file, info);
}
public void remove(VirtualFile file) {
final FileDependencyInfo info = cache.remove(file);
if (info != null) {
for (VirtualFile fileDependency : info.getDependencies()) {
getDependentsOn(fileDependency).remove(file);
}
for (String keyDependency : info.getDisplayKeys()) {
getDependentsOnByDisplayKey(keyDependency).remove(file);
}
}
}
public void clear() {
cache.clear();
dependsOnCache.clear();
displayKeyDependsOnCache.clear();
displayKeys.clear();
}
public long getFingerprint(VirtualFile file) {
final FileDependencyInfo info = get(file);
return info != null ? info.getFingerprint() : 0;
}
public Set<VirtualFile> getDependencies(VirtualFile file) {
final FileDependencyInfo info = get(file);
return info != null ? info.getDependencies() : Collections.<VirtualFile>emptySet();
}
public Set<VirtualFile> getDependentsOn(VirtualFile file) {
Set<VirtualFile> virtualFiles = dependsOnCache.get(file);
if (virtualFiles == null) {
virtualFiles = Sets.newHashSet();
dependsOnCache.put(file, virtualFiles);
}
return virtualFiles;
}
public Set<VirtualFile> getDependentsOnByDisplayKey(String key) {
Set<VirtualFile> virtualFiles = displayKeyDependsOnCache.get(key);
if (virtualFiles == null) {
virtualFiles = Sets.newHashSet();
displayKeyDependsOnCache.put(key, virtualFiles);
}
return virtualFiles;
}
public Set<String> getDisplayKeys(VirtualFile file) {
Set<String> keys = displayKeys.get(file);
if (keys == null) {
keys = Sets.newHashSet();
displayKeys.put(file, keys);
}
return keys;
}
public void save(@NotNull File file) throws IOException {
FileUtil.createParentDirs(file);
DataOutputStream out = null;
try {
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
// Size
out.writeInt(size());
// Values
for (FileDependencyInfo info : cache.values()) {
FileDependencyInfo.write(info, out);
}
} finally {
Closeables.closeQuietly(out);
}
}
public void load(@NotNull Project project, File file) throws IOException {
DataInputStream in = null;
try {
in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
final int size = in.readInt();
for (int i = 0; i < size; ++i) {
final FileDependencyInfo info = FileDependencyInfo.read(in);
if (info != null) {
put(info);
}
}
} finally {
Closeables.closeQuietly(in);
}
}
private void handleDisplayKeys(VirtualFile file) {
final Set<String> keys = getDisplayKeys(file);
keys.clear();
try (InputStream inputStream = file.getInputStream()) {
PropertyKeys props = new PropertyKeys(keys);
props.load(new InputStreamReader(inputStream));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private class PropertyKeys extends Properties {
Set<String> keys;
public PropertyKeys(Set<String> keys) {
this.keys = keys;
}
@Override
public synchronized Object put(Object key, Object value) {
keys.add((String) key);
return null;
}
}
}