package com.intellij.lang.javascript.flex.projectStructure.model.impl;
import com.intellij.lang.javascript.flex.build.FlexCompilerHandler;
import com.intellij.flex.model.bc.CompilerOptionInfo;
import com.intellij.lang.javascript.flex.projectStructure.model.CompilerOptionsListener;
import com.intellij.lang.javascript.flex.projectStructure.model.ModifiableCompilerOptions;
import com.intellij.lang.javascript.flex.projectStructure.model.ModuleOrProjectCompilerOptions;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.EventDispatcher;
import com.intellij.util.xmlb.annotations.MapAnnotation;
import com.intellij.util.xmlb.annotations.Property;
import com.intellij.util.xmlb.annotations.Tag;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
class CompilerOptionsImpl implements ModifiableCompilerOptions, ModuleOrProjectCompilerOptions {
private final Project myProject;
private final boolean myResetHighlightingOnCommit;
private final EventDispatcher<CompilerOptionsListener> myDispatcher = EventDispatcher.create(CompilerOptionsListener.class);
private final Map<String, String> myOptions = new THashMap<>();
private @NotNull ResourceFilesMode myResourceFilesMode = ResourceFilesMode.All;
private @NotNull String myFilesToIncludeInSWC = "";
private @NotNull String myAdditionalConfigFilePath = "";
private @NotNull String myAdditionalOptions = "";
CompilerOptionsImpl() {
this(null, false);
}
// todo introduce modifiable model with highlighting reset on commit instead of myResetHighlightingOnCommit, move listeners notification to committing method
CompilerOptionsImpl(final Project project, final boolean resetHighlightingOnCommit) {
myProject = project;
myResetHighlightingOnCommit = resetHighlightingOnCommit;
}
public void addOptionsListener(CompilerOptionsListener listener, Disposable parentDisposable) {
myDispatcher.addListener(listener, parentDisposable);
}
@Override
@Nullable
public String getOption(@NotNull String name) {
return myOptions.get(name);
}
@Override
public Map<String, String> getAllOptions() {
return Collections.unmodifiableMap(myOptions);
}
@Override
public void setAllOptions(Map<String, String> newOptions) {
myOptions.clear();
myOptions.putAll(newOptions);
if (myResetHighlightingOnCommit) {
FlexCompilerHandler.getInstance(myProject).getCompilerDependenciesCache().clear();
ApplicationManager.getApplication().runWriteAction(() -> FlexBuildConfigurationManagerImpl.resetHighlighting(myProject));
myDispatcher.getMulticaster().optionsInTableChanged();
}
}
public void setResourceFilesMode(@NotNull final ResourceFilesMode mode) {
myResourceFilesMode = mode;
}
@NotNull
public ResourceFilesMode getResourceFilesMode() {
return myResourceFilesMode;
}
@Override
public Collection<String> getFilesToIncludeInSWC() {
if (myFilesToIncludeInSWC.isEmpty()) return Collections.emptyList();
return StringUtil.split(myFilesToIncludeInSWC, CompilerOptionInfo.LIST_ENTRIES_SEPARATOR);
}
@Override
public void setFilesToIncludeInSWC(@NotNull Collection<String> filesToIncludeInSWC) {
myFilesToIncludeInSWC =
filesToIncludeInSWC.isEmpty() ? "" : StringUtil.join(filesToIncludeInSWC, CompilerOptionInfo.LIST_ENTRIES_SEPARATOR);
}
public void setAdditionalConfigFilePath(@NotNull final String path) {
myAdditionalConfigFilePath = path;
if (myResetHighlightingOnCommit) {
// module and project level settings don't have config file field
assert myAdditionalConfigFilePath.equals(path);
}
}
@NotNull
public String getAdditionalConfigFilePath() {
return myAdditionalConfigFilePath;
}
public void setAdditionalOptions(@NotNull final String options) {
myAdditionalOptions = options;
if (myResetHighlightingOnCommit) {
FlexCompilerHandler.getInstance(myProject).getCompilerDependenciesCache().clear();
ApplicationManager.getApplication().runWriteAction(() -> FlexBuildConfigurationManagerImpl.resetHighlighting(myProject));
myDispatcher.getMulticaster().additionalOptionsChanged();
}
}
@NotNull
public String getAdditionalOptions() {
return myAdditionalOptions;
}
public CompilerOptionsImpl getCopy() {
CompilerOptionsImpl copy = new CompilerOptionsImpl();
applyTo(copy);
return copy;
}
void applyTo(ModifiableCompilerOptions copy) {
copy.setAllOptions(myOptions);
copy.setResourceFilesMode(myResourceFilesMode);
((CompilerOptionsImpl)copy).myFilesToIncludeInSWC = myFilesToIncludeInSWC;
copy.setAdditionalConfigFilePath(myAdditionalConfigFilePath);
copy.setAdditionalOptions(myAdditionalOptions);
}
public State getState(final @Nullable ComponentManager componentManager) {
State state = new State();
putOptionsCollapsingPaths(myOptions, state.options, componentManager);
state.resourceFilesMode = myResourceFilesMode;
state.filesToIncludeInSWC = FlexBuildConfigurationImpl.collapsePaths(componentManager, myFilesToIncludeInSWC);
state.additionalConfigFilePath = myAdditionalConfigFilePath;
state.additionalOptions = myAdditionalOptions;
return state;
}
private static void putOptionsCollapsingPaths(final Map<String, String> fromMap,
final Map<String, String> toMap,
final @Nullable ComponentManager componentManager) {
for (Map.Entry<String, String> entry : fromMap.entrySet()) {
toMap.put(entry.getKey(), FlexBuildConfigurationImpl.collapsePaths(componentManager, entry.getValue()));
}
}
public void loadState(State state) {
myOptions.clear();
// filter out options that are not known in current IDEA version
for (Map.Entry<String, String> entry : state.options.entrySet()) {
if (CompilerOptionInfo.idExists(entry.getKey())) {
// no need in expanding paths, it is done automatically even if macros is not in the beginning of the string
myOptions.put(entry.getKey(), entry.getValue());
}
}
myResourceFilesMode = state.resourceFilesMode;
myFilesToIncludeInSWC = state.filesToIncludeInSWC;
myAdditionalConfigFilePath = state.additionalConfigFilePath;
myAdditionalOptions = state.additionalOptions;
}
public boolean isEqual(CompilerOptionsImpl other) {
return myOptions.equals(other.myOptions) &&
myResourceFilesMode == other.myResourceFilesMode &&
myFilesToIncludeInSWC.equals(other.myFilesToIncludeInSWC) &&
myAdditionalConfigFilePath.equals(other.myAdditionalConfigFilePath) &&
myAdditionalOptions.equals(other.myAdditionalOptions);
}
@Tag("compiler-options")
public static class State {
@Property(surroundWithTag = false)
@MapAnnotation(surroundKeyWithTag = false, surroundValueWithTag = false)
public Map<String, String> options = new THashMap<>();
public ResourceFilesMode resourceFilesMode = ResourceFilesMode.All;
public String filesToIncludeInSWC = "";
public String additionalConfigFilePath = "";
public String additionalOptions = "";
}
}