package com.intellij.flex.model.bc;
import com.intellij.flex.FlexCommonUtils;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.StringUtil;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class CompilerOptionInfo {
public enum OptionType {Group, Boolean, String, Int, File, List, IncludeClasses, IncludeFiles}
public enum ListElementType {String, File, FileOrFolder, Class, Boolean, Locale}
public static class ListElement {
public final String NAME;
public final String DISPLAY_NAME;
public final ListElementType LIST_ELEMENT_TYPE;
public @Nullable final String[] FILE_EXTENSIONS;
public final String DEFAULT_VALUE;
private ListElement(final String name) {
this(name, "", ListElementType.String, null, "");
}
private ListElement(final String name, final String displayName, final ListElementType listElementType,
final @Nullable String[] fileExtensions, final String defaultValue) {
NAME = name;
DISPLAY_NAME = displayName;
LIST_ELEMENT_TYPE = listElementType;
FILE_EXTENSIONS = fileExtensions;
DEFAULT_VALUE = defaultValue;
}
}
public static final String LIST_ENTRIES_SEPARATOR = "\n";
public static final String LIST_ENTRY_PARTS_SEPARATOR = "\t"; // if list entry contains several values, e.g. uri and manifest
public static final String FLEX_SDK_MACRO_NAME = "FLEX_SDK";
public static final String FLEX_SDK_MACRO = "${" + FLEX_SDK_MACRO_NAME + "}";
private static final String SPECIAL_DEFAULT_VALUE = "SPECIAL";
private static final Logger LOG = Logger.getInstance(CompilerOptionInfo.class.getName());
private static volatile CompilerOptionInfo[] ourRootInfos;
private static final Map<String, CompilerOptionInfo> ourIdToInfoMap = new THashMap<>(50);
private static final Collection<CompilerOptionInfo> ourOptionsWithSpecialValues = new LinkedList<>();
public static final CompilerOptionInfo DEBUG_INFO =
new CompilerOptionInfo("compiler.debug", "fake", OptionType.Boolean, null, null, false, null, true, true, true, true, "");
public static final CompilerOptionInfo EXTERNAL_LIBRARY_INFO =
new CompilerOptionInfo("compiler.external-library-path", "fake", OptionType.List, null,
new ListElement[]{new ListElement("path-element")}, false, null, true, true, true, true, "");
public static final CompilerOptionInfo LIBRARY_PATH_INFO =
new CompilerOptionInfo("compiler.library-path", "fake", OptionType.List, null,
new ListElement[]{new ListElement("path-element")}, false, null, true, true, true, true, "");
public static final CompilerOptionInfo INCLUDE_LIBRARY_INFO =
new CompilerOptionInfo("compiler.include-libraries", "fake", OptionType.List, null,
new ListElement[]{new ListElement("library")}, false, null, true, true, true, true, "");
public static final CompilerOptionInfo SOURCE_PATH_INFO =
new CompilerOptionInfo("compiler.source-path", "fake", OptionType.List, null,
new ListElement[]{new ListElement("path-element")}, false, null, true, true, true, true, "");
public static final CompilerOptionInfo INCLUDE_CLASSES_INFO =
new CompilerOptionInfo("include-classes", "fake", OptionType.List, null,
new ListElement[]{new ListElement("class")},
false, null, true, true, true, true, "");
public static final CompilerOptionInfo RSL_ONE_URL_PATH_INFO =
new CompilerOptionInfo("runtime-shared-library-path", "fake", OptionType.List, null,
new ListElement[]{
new ListElement("path-element"),
new ListElement("rsl-url"),
new ListElement("policy-file-url")
}, false, null, true, true, true, true, "");
public static final CompilerOptionInfo RSL_TWO_URLS_PATH_INFO =
new CompilerOptionInfo("runtime-shared-library-path", "fake", OptionType.List, null,
new ListElement[]{
new ListElement("path-element"),
new ListElement("rsl-url"),
new ListElement("policy-file-url"),
new ListElement("rsl-url"),
new ListElement("policy-file-url")
}, false, null, true, true, true, true, "");
public static final CompilerOptionInfo MOBILE_INFO =
new CompilerOptionInfo("compiler.mobile", "fake", OptionType.Boolean, null, null, false, null, true, true, true, true, "");
public static final CompilerOptionInfo TARGET_PLAYER_INFO =
new CompilerOptionInfo("target-player", "fake", OptionType.String, null, null, false, null, true, true, true, true, "");
public static final CompilerOptionInfo MAIN_CLASS_INFO =
new CompilerOptionInfo("file-specs.path-element", "fake", OptionType.String, null, null, false, null, true, true, true, true, "");
public static final CompilerOptionInfo OUTPUT_PATH_INFO =
new CompilerOptionInfo("output", "fake", OptionType.String, null, null, false, null, true, true, true, true, "");
public static final CompilerOptionInfo ACCESSIBLE_INFO =
new CompilerOptionInfo("compiler.accessible", "fake", OptionType.Boolean, null, null, false, null, true, true, true, true, "");
public static final CompilerOptionInfo PRELOADER_INFO =
new CompilerOptionInfo("compiler.preloader", "fake", OptionType.String, null, null, false, "4.5", true, true, true, true, "");
public static final CompilerOptionInfo WARN_NO_CONSTRUCTOR_INFO =
new CompilerOptionInfo("compiler.warn-no-constructor", "fake", OptionType.Boolean, null, null, false, null, true, true, true, true, "");
public static final CompilerOptionInfo LINK_REPORT_INFO =
new CompilerOptionInfo("link-report", "fake", OptionType.File, "xml", null, false, null, true, true, true, true, "");
public static final CompilerOptionInfo LOAD_EXTERNS_INFO =
new CompilerOptionInfo("load-externs", "fake", OptionType.File, "xml", null, false, null, true, true, true, true, "");
public static final CompilerOptionInfo FONT_MANAGERS_INFO =
new CompilerOptionInfo("compiler.fonts.managers", "fake", OptionType.List, null,
new ListElement[]{new ListElement("manager-class")},
false, null, true, true, true, true, "");
public static final CompilerOptionInfo SWF_VERSION_INFO =
new CompilerOptionInfo("swf-version", "fake", OptionType.String, null, null, false, "4.5", true, true, true, true, "");
public static final CompilerOptionInfo STATIC_RSLS_INFO =
new CompilerOptionInfo("static-link-runtime-shared-libraries", "fake", OptionType.Boolean, null, null, false, null, true, true, true,
true, "");
public static final CompilerOptionInfo INCLUDE_NAMESPACES_INFO =
new CompilerOptionInfo("include-namespaces", "fake", OptionType.List, null,
new ListElement[]{new ListElement("uri")},
false, null, true, true, true, true, "");
public static final CompilerOptionInfo RLMS_INFO_FOR_UI =
new CompilerOptionInfo("rlm.list.fake", "fake", OptionType.List, null,
new ListElement[]{
new ListElement("fake", "Main Class", ListElementType.Class, null, ""),
new ListElement("fake", "Output File", ListElementType.String, null, ""),
new ListElement("fake", "Optimize", ListElementType.Boolean, null, "true")},
false, null, true, true, true, true, "");
public static final CompilerOptionInfo CSS_FILES_INFO_FOR_UI =
new CompilerOptionInfo("css.files.list.fake", "fake", OptionType.List, null,
new ListElement[]{new ListElement("fake", "CSS Files", ListElementType.File, new String[]{"css"}, "")},
false, null, true, true, true, true, "");
public static final CompilerOptionInfo INCLUDE_FILE_INFO_FOR_UI =
new CompilerOptionInfo("files.to.include.in.swc.fake", "fake", OptionType.List, null,
new ListElement[]{new ListElement("fake", "Files And Folders", ListElementType.FileOrFolder, null, "")},
false, null, true, true, true, true, "");
public static final CompilerOptionInfo INCLUDE_FILE_INFO =
new CompilerOptionInfo("include-file", "fake", OptionType.List, null,
new ListElement[]{new ListElement("name"), new ListElement("path")},
false, null, true, true, true, true, "");
public final String ID;
public final String DISPLAY_NAME;
public final OptionType TYPE;
public final @Nullable String FILE_EXTENSION; // for options with TYPE=OptionType.File
public final ListElement[] LIST_ELEMENTS; // for options with TYPE=OptionType.List
public final boolean ADVANCED;
private final CompilerOptionInfo[] myChildOptionInfos;
private final @Nullable String mySinceVersion;
private final boolean myOkForAir;
private final boolean myOkForPureAS;
private final boolean myOkForSwf;
private final boolean myOkForSwc;
private final String myDefaultValue;
private CompilerOptionInfo(final @NotNull String id,
final @NotNull String displayName,
final @NotNull OptionType optionType,
final @Nullable String fileExtension,
final @Nullable ListElement[] listElements,
final boolean advanced,
final @Nullable String sinceVersion,
final boolean okForAir,
final boolean okForPureAS,
final boolean okForSwf,
final boolean okForSwc,
final String defaultValue) {
assert optionType != OptionType.Group;
ID = id;
DISPLAY_NAME = displayName;
TYPE = optionType;
FILE_EXTENSION = fileExtension;
LIST_ELEMENTS = listElements;
ADVANCED = advanced;
mySinceVersion = sinceVersion;
myOkForAir = okForAir;
myOkForPureAS = okForPureAS;
myOkForSwf = okForSwf;
myOkForSwc = okForSwc;
myDefaultValue = defaultValue;
myChildOptionInfos = null;
}
private CompilerOptionInfo(final @NotNull String groupDisplayName,
final boolean advanced,
final @Nullable String sinceVersion,
final boolean okForAir,
final boolean okForPureAS,
final boolean okForSwf,
final boolean okForSwc,
final CompilerOptionInfo[] childOptionInfos) {
ID = null;
DISPLAY_NAME = groupDisplayName;
TYPE = OptionType.Group;
FILE_EXTENSION = null;
LIST_ELEMENTS = null;
ADVANCED = advanced;
mySinceVersion = sinceVersion;
myOkForAir = okForAir;
myOkForPureAS = okForPureAS;
myOkForSwf = okForSwf;
myOkForSwc = okForSwc;
myDefaultValue = null;
myChildOptionInfos = childOptionInfos;
}
public boolean isGroup() {
return TYPE == OptionType.Group;
}
public boolean isApplicable(final String sdkVersion, final BuildConfigurationNature nature) {
if (mySinceVersion != null &&
!sdkVersion.startsWith(FlexCommonUtils.AIR_SDK_VERSION_PREFIX) &&
StringUtil.compareVersionNumbers(sdkVersion, mySinceVersion) < 0) {
return false;
}
if (!myOkForPureAS && nature.pureAS) return false;
if (!myOkForSwf && !nature.isLib()) return false;
if (!myOkForSwc && nature.isLib()) return false;
return true;
}
public CompilerOptionInfo[] getChildOptionInfos() {
assert TYPE == OptionType.Group;
return myChildOptionInfos;
}
public static CompilerOptionInfo[] getRootInfos() {
ensureLoaded();
return ourRootInfos;
}
public static CompilerOptionInfo getOptionInfo(final String id) {
ensureLoaded();
final CompilerOptionInfo info = ourIdToInfoMap.get(id);
assert info != null : id;
return info;
}
public static boolean idExists(final String id) {
ensureLoaded();
return ourIdToInfoMap.get(id) != null;
}
public String getDefaultValue(final String sdkVersion, final BuildConfigurationNature nature, final ComponentSet componentSet) {
assert !isGroup() : DISPLAY_NAME;
if (SPECIAL_DEFAULT_VALUE.equals(myDefaultValue)) {
if (ID.startsWith("compiler.debug")) {
return "true";
}
if ("compiler.locale".equals(ID)) {
return "en_US";
}
else if ("compiler.theme".equals(ID)) {
if (!nature.pureAS &&
!nature.isDesktopPlatform() &&
!sdkVersion.startsWith(FlexCommonUtils.AIR_SDK_VERSION_PREFIX) &&
StringUtil.compareVersionNumbers(sdkVersion, "4") >= 0) {
if (nature.isMobilePlatform()) return FLEX_SDK_MACRO + "/frameworks/themes/Mobile/mobile.swc";
if (StringUtil.compareVersionNumbers(sdkVersion, "4") >= 0 && componentSet == ComponentSet.MxOnly) {
return FLEX_SDK_MACRO + "/frameworks/themes/Halo/halo.swc";
}
else {
return FLEX_SDK_MACRO + "/frameworks/themes/Spark/spark.css";
}
}
return "";
}
/*
else if ("compiler.accessible".equals(ID)) {
return nature.isMobilePlatform() ? "false"
: StringUtil.compareVersionNumbers(sdkVersion, "4") >= 0 ? "true" : "false";
}
else if ("compiler.preloader".equals(ID)) {
return nature.isMobilePlatform() ? "spark.preloaders.SplashScreen" : "";
}
else if ("swf-version".equals(ID)) {
return StringUtil.compareVersionNumbers(sdkVersion, "4.6") >= 0 ? "14" : "11";
}
else if ("compiler.fonts.managers".equals(ID)) {
return sdkVersion != null && StringUtil.compareVersionNumbers(sdkVersion, "4") >= 0
? "flash.fonts.JREFontManager" + LIST_ENTRIES_SEPARATOR +
"flash.fonts.BatikFontManager" + LIST_ENTRIES_SEPARATOR +
"flash.fonts.AFEFontManager" + LIST_ENTRIES_SEPARATOR +
"flash.fonts.CFFFontManager"
: "flash.fonts.JREFontManager" + LIST_ENTRIES_SEPARATOR +
"flash.fonts.AFEFontManager" + LIST_ENTRIES_SEPARATOR +
"flash.fonts.BatikFontManager";
}
else if ("static-link-runtime-shared-libraries".equals(ID)) {
return "false";
}
else if ("compiler.warn-no-constructor".equals(ID)) {
return "false";
}
*/
assert false : ID;
}
return myDefaultValue;
}
public static Collection<CompilerOptionInfo> getOptionsWithSpecialValues() {
ensureLoaded();
return ourOptionsWithSpecialValues;
}
private static void ensureLoaded() {
if (ourRootInfos == null) {
synchronized (CompilerOptionInfo.class) {
if (ourRootInfos == null) {
loadInfo();
}
}
}
}
private static void loadInfo() {
try {
final List<CompilerOptionInfo> infos = new ArrayList<>(30);
final Element rootElement = JDOMUtil.load(CompilerOptionInfo.class.getResourceAsStream("flex-compiler-options.xml"));
assert rootElement != null;
assert "options".equals(rootElement.getName());
//noinspection unchecked
for (Element element : rootElement.getChildren()) {
final CompilerOptionInfo info;
if ("group".equals(element.getName())) {
info = loadGroup(element);
}
else {
assert "option".equals(element.getName());
info = loadOption(element);
}
infos.add(info);
}
ourRootInfos = infos.toArray(new CompilerOptionInfo[infos.size()]);
}
catch (Exception e) {
LOG.error(e);
}
}
private static CompilerOptionInfo loadGroup(final Element groupElement) {
final String displayName = groupElement.getAttributeValue("displayName");
assert StringUtil.isNotEmpty(displayName);
final String advancedValue = groupElement.getAttributeValue("advanced");
final boolean advanced = advancedValue != null && "true".equals(advancedValue);
final String since = groupElement.getAttributeValue("since");
final String okForAirValue = groupElement.getAttributeValue("okForAir");
final boolean okForAir = okForAirValue == null || "false".equals(okForAirValue);
final String okForPureASValue = groupElement.getAttributeValue("okForPureAS");
final boolean okForPureAS = okForPureASValue == null || "false".equals(okForPureASValue);
final String okForSWFValue = groupElement.getAttributeValue("okForSWF");
final boolean okForSWF = okForSWFValue == null || "false".equals(okForSWFValue);
final String okForSWCValue = groupElement.getAttributeValue("okForSWC");
final boolean okForSWC = okForSWCValue == null || "false".equals(okForSWCValue);
final List<CompilerOptionInfo> infos = new ArrayList<>();
//noinspection unchecked
for (final Element element : groupElement.getChildren()) {
final CompilerOptionInfo info;
if ("group".equals(element.getName())) {
info = loadGroup(element);
}
else {
assert "option".equals(element.getName());
info = loadOption(element);
}
infos.add(info);
}
final CompilerOptionInfo[] infosArray = infos.toArray(new CompilerOptionInfo[infos.size()]);
return new CompilerOptionInfo(displayName, advanced, since, okForAir, okForPureAS, okForSWF, okForSWC, infosArray);
}
private static CompilerOptionInfo loadOption(final Element element) {
final String id = element.getAttributeValue("id");
assert StringUtil.isNotEmpty(id);
final String displayName = element.getAttributeValue("displayName");
assert StringUtil.isNotEmpty(displayName);
final String typeValue = element.getAttributeValue("type");
final OptionType type = OptionType.valueOf(typeValue);
assert type != OptionType.Group;
final String fileExtension = type == OptionType.File ? element.getAttributeValue("fileExtension") : null;
final ListElement[] listElements = type == OptionType.List ? readListElements(element) : null;
final String advancedValue = element.getAttributeValue("advanced");
final boolean advanced = advancedValue != null && "true".equals(advancedValue);
final String since = element.getAttributeValue("since");
final String okForAirValue = element.getAttributeValue("okForAir");
final boolean okForAir = okForAirValue == null || "true".equals(okForAirValue);
final String okForPureASValue = element.getAttributeValue("okForPureAS");
final boolean okForPureAS = okForPureASValue == null || "true".equals(okForPureASValue);
final String okForSWFValue = element.getAttributeValue("okForSWF");
final boolean okForSWF = okForSWFValue == null || "true".equals(okForSWFValue);
final String okForSWCValue = element.getAttributeValue("okForSWC");
final boolean okForSWC = okForSWCValue == null || "true".equals(okForSWCValue);
final String defaultValue = StringUtil.notNullize(element.getAttributeValue("default"));
final CompilerOptionInfo info = new CompilerOptionInfo(id, displayName, type, fileExtension, listElements, advanced, since, okForAir,
okForPureAS, okForSWF, okForSWC, defaultValue);
if (SPECIAL_DEFAULT_VALUE.equals(defaultValue)) {
ourOptionsWithSpecialValues.add(info);
}
ourIdToInfoMap.put(id, info);
return info;
}
private static ListElement[] readListElements(final Element element) {
final List<ListElement> result = new LinkedList<>();
//noinspection unchecked
for (final Element childElement : element.getChildren("listElement")) {
final String name = childElement.getAttributeValue("name");
final String displayName = childElement.getAttributeValue("displayName");
assert name != null : element.getName();
final ListElementType listElementType = ListElementType.valueOf(childElement.getAttributeValue("type"));
final String fileExtensionRaw = childElement.getAttributeValue("fileExtensions");
final String[] fileExtensions = fileExtensionRaw == null ? null : fileExtensionRaw.split(",");
final String defaultValue = StringUtil.notNullize(childElement.getAttributeValue("default"));
result.add(new ListElement(name, displayName, listElementType, fileExtensions, defaultValue));
}
assert !result.isEmpty() : element.getName();
return result.toArray(new ListElement[result.size()]);
}
public String toString() {
return ID;
}
}