package com.jetbrains.lang.dart.util;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;
public class DotPackagesFileUtil {
public static final String DOT_PACKAGES = ".packages";
private static final Key<Pair<Long, Map<String, String>>> MOD_STAMP_TO_PACKAGES_MAP = Key.create("MOD_STAMP_TO_PACKAGES_MAP");
@Nullable
public static Map<String, String> getPackagesMap(@NotNull final VirtualFile dotPackagesFile) {
Pair<Long, Map<String, String>> data = dotPackagesFile.getUserData(MOD_STAMP_TO_PACKAGES_MAP);
final Long currentTimestamp = dotPackagesFile.getModificationCount();
final Long cachedTimestamp = data == null ? null : data.first;
if (cachedTimestamp == null || !cachedTimestamp.equals(currentTimestamp)) {
data = null;
dotPackagesFile.putUserData(MOD_STAMP_TO_PACKAGES_MAP, null);
final Map<String, String> packagesMap = loadPackagesMap(dotPackagesFile);
if (packagesMap != null) {
data = Pair.create(currentTimestamp, packagesMap);
dotPackagesFile.putUserData(MOD_STAMP_TO_PACKAGES_MAP, data);
}
}
return data == null ? null : data.second;
}
@Nullable
private static Map<String, String> loadPackagesMap(@NotNull final VirtualFile dotPackagesFile) {
try {
final List<String> lines;
if (ApplicationManager.getApplication().isUnitTestMode()) {
lines = StringUtil.split(new String(dotPackagesFile.contentsToByteArray(), "UTF-8"), "\n");
}
else {
lines = FileUtil.loadLines(dotPackagesFile.getPath(), "UTF-8");
}
final Map<String, String> result = new THashMap<>();
for (String line : lines) {
if (line.trim().isEmpty() || line.startsWith("#")) continue;
final int colonIndex = line.indexOf(':');
if (colonIndex > 0 && colonIndex < line.length() - 1) {
final String packageName = line.substring(0, colonIndex).trim();
final String encodedUri = line.substring(colonIndex + 1).trim();
// need to protect '+' chars because URLDecoder.decode replaces '+' with space
final String encodedUriWithoutPluses = StringUtil.replace(encodedUri, "+", "%2B");
final String uri = URLDecoder.decode(encodedUriWithoutPluses, "UTF-8");
final String packageUri = getAbsolutePackageRootPath(dotPackagesFile.getParent(), uri);
if (!packageName.isEmpty() && packageUri != null) {
result.put(packageName, packageUri);
}
}
}
return result;
}
catch (IOException e) {
return null;
}
}
@Nullable
private static String getAbsolutePackageRootPath(@NotNull final VirtualFile baseDir, @NotNull final String uri) {
if (uri.startsWith("file:/")) {
final String pathAfterSlashes = StringUtil.trimEnd(StringUtil.trimLeading(StringUtil.trimStart(uri, "file:/"), '/'), "/");
if (SystemInfo.isWindows && !ApplicationManager.getApplication().isUnitTestMode()) {
if (pathAfterSlashes.length() > 2 && Character.isLetter(pathAfterSlashes.charAt(0)) && ':' == pathAfterSlashes.charAt(1)) {
return pathAfterSlashes;
}
}
else {
return "/" + pathAfterSlashes;
}
}
else {
return FileUtil.toCanonicalPath(baseDir.getPath() + "/" + uri);
}
return null;
}
}