package com.intellij.lang.javascript.flex.sdk;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkAdditionalData;
import com.intellij.openapi.util.JDOMUtil;
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.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FlexmojosSdkAdditionalData implements SdkAdditionalData {
private static final String COMPILER_CLASSPATH_ELEMENT_NAME = "CompilerClassPath";
private static final String CLASSPATH_ENTRY_ELEMENT_NAME = "ClassPathEntry";
private static final String ADL_PATH_ELEMENT_NAME = "AdlPath";
private static final String AIR_RUNTIME_PATH_ELEMENT_NAME = "AirRuntimePath";
private static final String COMPILER_POM_NAME_BEGINNING = "compiler-";
private static final String DOT_POM = ".pom";
private static final String ADL_ARTIFACT_PATTERN = "{0}/com/adobe/flex/adl/{1}/adl-{1}.{2}";
private static final String AIR_RUNTIME_ARTIFACT_PATTERN = "{0}/com/adobe/air/runtime/{1}/runtime-{1}-{2}.{3}";
private Collection<String> myFlexCompilerClasspath = new ArrayList<>();
private String myAdlPath = "";
private String myAirRuntimePath = "";
@Override
public Object clone() throws CloneNotSupportedException {
final FlexmojosSdkAdditionalData copy = (FlexmojosSdkAdditionalData)super.clone();
copy.myFlexCompilerClasspath = new ArrayList<>(myFlexCompilerClasspath);
return copy;
}
public Collection<String> getFlexCompilerClasspath() {
return Collections.unmodifiableCollection(myFlexCompilerClasspath);
}
public void addFlexCompilerClasspathEntryIfNotPresentAndRemoveDifferentVersionOfThisJar(final Pattern jarNamePattern,
final String jarPath) {
final Iterator<String> iterator = myFlexCompilerClasspath.iterator();
while (iterator.hasNext()) {
final String classpathEntry = iterator.next();
final String jarName = classpathEntry.substring(classpathEntry.lastIndexOf("/") + 1);
final Matcher matcher = jarNamePattern.matcher(jarName);
if (matcher.find() && matcher.start() == 0) {
// jar name starts with jarNamePattern
iterator.remove();
}
}
myFlexCompilerClasspath.add(jarPath);
}
public String getAdlPath() {
return myAdlPath;
}
public void setAdlPath(final String adlPath) {
myAdlPath = adlPath;
}
public String getAirRuntimePath() {
return myAirRuntimePath;
}
public void setAirRuntimePath(final String airRuntimePath) {
myAirRuntimePath = airRuntimePath;
}
void setup(final VirtualFile compilerPomFile) {
final String compilerPomPath = compilerPomFile.getPath();
final String repositoryRootPath;
if (compilerPomPath.matches(FlexmojosSdkType.COMPILER_POM_PATTERN_1)) {
repositoryRootPath = compilerPomPath.substring(0, compilerPomPath.indexOf("/com/adobe/flex/compiler"));
}
else if (compilerPomPath.matches(FlexmojosSdkType.COMPILER_POM_PATTERN_2)) {
repositoryRootPath = compilerPomPath.substring(0, compilerPomPath.indexOf("/org/apache/flex/compiler"));
}
else {
return;
}
setupFlexCompilerClasspath(compilerPomFile, repositoryRootPath);
final int i = compilerPomPath.lastIndexOf(COMPILER_POM_NAME_BEGINNING);
final String version = compilerPomPath.substring(i + COMPILER_POM_NAME_BEGINNING.length(), compilerPomPath.lastIndexOf(DOT_POM));
setupAirPaths(repositoryRootPath, version);
}
void setupFlexCompilerClasspath(final VirtualFile compilerPomFile, final String repositoryRootPath) {
myFlexCompilerClasspath.clear();
try {
final Element rootElement = JDOMUtil.load(compilerPomFile.getInputStream());
if (!rootElement.getName().equals("project")) return;
for (final Object dependenciesElement : rootElement.getChildren("dependencies", rootElement.getNamespace())) {
for (final Object dependencyElement : ((Element)dependenciesElement).getChildren("dependency", rootElement.getNamespace())) {
final String groupId = ((Element)dependencyElement).getChildText("groupId", rootElement.getNamespace());
final String artifactId = ((Element)dependencyElement).getChildText("artifactId", rootElement.getNamespace());
final String version = ((Element)dependencyElement).getChildText("version", rootElement.getNamespace());
addClasspathEntry(repositoryRootPath, groupId, artifactId, version);
}
}
}
catch (IOException ignored) {/*ignore*/}
catch (JDOMException ignored) {/*ignore*/}
}
private void setupAirPaths(final String repositoryRootPath, final String version) {
if (StringUtil.isNotEmpty(myAdlPath) && StringUtil.isNotEmpty(myAirRuntimePath)) {
return;
}
final String exeType = SystemInfo.isWindows ? "exe" : "uexe";
final String adlPath = FileUtil.toSystemIndependentName(
MessageFormat.format(ADL_ARTIFACT_PATTERN, repositoryRootPath, version, exeType));
final VirtualFile adlFile = LocalFileSystem.getInstance().findFileByPath(adlPath);
if (adlFile != null && !adlFile.isDirectory()) {
myAdlPath = adlPath;
final String classifier = SystemInfo.isWindows ? "win" : "mac";
final String zipType = "zip";
myAirRuntimePath = FileUtil
.toSystemIndependentName(MessageFormat.format(AIR_RUNTIME_ARTIFACT_PATTERN, repositoryRootPath, version, classifier, zipType));
}
else {
final Sdk sdk = findSimilarSdk(version);
if (sdk != null) {
myAdlPath = FileUtil.toSystemIndependentName(sdk.getHomePath() + FlexSdkUtils.ADL_RELATIVE_PATH);
myAirRuntimePath = FileUtil.toSystemIndependentName(sdk.getHomePath() + FlexSdkUtils.AIR_RUNTIME_RELATIVE_PATH);
}
}
}
@Nullable
private static Sdk findSimilarSdk(final String version) {
final int firstDotIndex = version.indexOf('.');
final int secondDotIndex = version.indexOf('.', firstDotIndex + 1);
final int thirdDotIndex = version.indexOf('.', secondDotIndex + 1);
if (firstDotIndex <= 0) return null;
final String major = version.substring(0, firstDotIndex);
final String minor = secondDotIndex > firstDotIndex ? version.substring(firstDotIndex + 1, secondDotIndex) : "";
final String revision = thirdDotIndex > secondDotIndex ? version.substring(secondDotIndex + 1, thirdDotIndex) : "";
final String build = thirdDotIndex > 0 ? version.substring(thirdDotIndex + 1) : "";
Sdk matchingMajorMinorRevisionBuild = null;
Sdk matchingMajorMinorRevision = null;
Sdk matchingMajorMinor = null;
Sdk latestSdk = null;
for (Sdk sdk : FlexSdkUtils.getFlexSdks()) {
final String candidateVersion = sdk.getVersionString();
if (candidateVersion == null) continue;
if (candidateVersion.startsWith(major + "." + minor + "." + revision) && candidateVersion.endsWith(build)) {
matchingMajorMinorRevisionBuild = sdk;
break;
}
if (candidateVersion.startsWith(major + "." + minor + "." + revision)) matchingMajorMinorRevision = sdk;
if (candidateVersion.startsWith(major + "." + minor)) matchingMajorMinor = sdk;
if (latestSdk == null || StringUtil.compareVersionNumbers(candidateVersion, latestSdk.getVersionString()) > 0) {
latestSdk = sdk;
}
}
if (matchingMajorMinorRevisionBuild != null) return matchingMajorMinorRevisionBuild;
if (matchingMajorMinorRevision != null) return matchingMajorMinorRevision;
if (matchingMajorMinor != null) return matchingMajorMinor;
return latestSdk;
}
private void addClasspathEntry(final String repositoryRootPath, final String groupId, final String artifactId, final String version) {
if (StringUtil.isNotEmpty(repositoryRootPath) &&
StringUtil.isNotEmpty(groupId) &&
StringUtil.isNotEmpty(artifactId) &&
StringUtil.isNotEmpty(version)) {
myFlexCompilerClasspath.add(repositoryRootPath + '/' + groupId.replace('.', '/') + '/' + artifactId + '/' + version + '/' + artifactId + '-' + version + ".jar");
}
}
void save(final Element element) {
final Element compilerClasspathElement = new Element(COMPILER_CLASSPATH_ELEMENT_NAME);
for (final String classpathEntry : myFlexCompilerClasspath) {
final Element classpathEntryElement = new Element(CLASSPATH_ENTRY_ELEMENT_NAME);
classpathEntryElement.setText(classpathEntry);
compilerClasspathElement.addContent(classpathEntryElement);
}
element.addContent(compilerClasspathElement);
final Element adlPathElement = new Element(ADL_PATH_ELEMENT_NAME);
adlPathElement.setText(myAdlPath);
element.addContent(adlPathElement);
final Element airRuntimePathElement = new Element(AIR_RUNTIME_PATH_ELEMENT_NAME);
airRuntimePathElement.setText(myAirRuntimePath);
element.addContent(airRuntimePathElement);
}
void load(final Element element) {
myFlexCompilerClasspath.clear();
final Element compilerClasspathElement = element.getChild(COMPILER_CLASSPATH_ELEMENT_NAME);
if (compilerClasspathElement != null) {
for (Object classpathEntryElement : compilerClasspathElement.getChildren(CLASSPATH_ENTRY_ELEMENT_NAME)) {
myFlexCompilerClasspath.add(((Element)classpathEntryElement).getText());
}
}
final String adlPath = element.getChildText(ADL_PATH_ELEMENT_NAME);
myAdlPath = adlPath == null ? "" : FileUtil.toSystemIndependentName(adlPath);
final String airRuntimePath = element.getChildText(AIR_RUNTIME_PATH_ELEMENT_NAME);
myAirRuntimePath = airRuntimePath == null ? "" : FileUtil.toSystemIndependentName(airRuntimePath);
}
}