package com.intellij.lang.javascript.flex.run;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.configuration.EmptyRunProfileState;
import com.intellij.execution.configurations.*;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.flex.model.bc.BuildConfigurationNature;
import com.intellij.javascript.flex.resolve.ActionScriptClassResolver;
import com.intellij.lang.javascript.flex.FlexModuleType;
import com.intellij.lang.javascript.flex.FlexRefactoringListenerProvider;
import com.intellij.lang.javascript.flex.FlexUtils;
import com.intellij.lang.javascript.flex.projectStructure.model.FlexBuildConfiguration;
import com.intellij.lang.javascript.flex.sdk.FlexSdkUtils;
import com.intellij.lang.javascript.flex.sdk.FlexmojosSdkType;
import com.intellij.lang.javascript.psi.ecmal4.JSClass;
import com.intellij.lang.javascript.psi.ecmal4.JSPackage;
import com.intellij.lang.javascript.psi.ecmal4.JSPackageStatement;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.impl.DirectoryIndex;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDirectoryContainer;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.util.xmlb.XmlSerializer;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import static com.intellij.lang.javascript.flex.run.FlashRunnerParameters.AirMobileRunTarget;
public class FlashRunConfiguration extends LocatableConfigurationBase
implements RunProfileWithCompileBeforeLaunchOption, RefactoringListenerProvider {
private FlashRunnerParameters myRunnerParameters = new FlashRunnerParameters();
public FlashRunConfiguration(final Project project, final ConfigurationFactory factory, final String name) {
super(project, factory, name);
}
@Override
public FlashRunConfiguration clone() {
final FlashRunConfiguration clone = (FlashRunConfiguration)super.clone();
clone.myRunnerParameters = myRunnerParameters.clone();
return clone;
}
@NotNull
@Override
public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
return new FlashRunConfigurationForm(getProject());
}
@Override
public void readExternal(final Element element) throws InvalidDataException {
super.readExternal(element);
myRunnerParameters = new FlashRunnerParameters();
XmlSerializer.deserializeInto(myRunnerParameters, element);
}
@Override
public void writeExternal(final Element element) throws WriteExternalException {
super.writeExternal(element);
XmlSerializer.serializeInto(myRunnerParameters, element);
}
@Override
public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException {
final FlexBuildConfiguration config;
try {
config = myRunnerParameters.checkAndGetModuleAndBC(getProject()).second;
}
catch (RuntimeConfigurationError e) {
throw new ExecutionException(e.getMessage());
}
final BuildConfigurationNature nature = config.getNature();
if (nature.isDesktopPlatform() ||
(nature.isMobilePlatform() && myRunnerParameters.getMobileRunTarget() == AirMobileRunTarget.Emulator)) {
return new AirRunState(getProject(), env, myRunnerParameters);
}
return EmptyRunProfileState.INSTANCE;
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
myRunnerParameters.check(getProject());
myRunnerParameters.reportWarnings(getProject());
}
@NotNull
public FlashRunnerParameters getRunnerParameters() {
return myRunnerParameters;
}
@Override
@NotNull
public Module[] getModules() {
final Module module = ModuleManager.getInstance(getProject()).findModuleByName(myRunnerParameters.getModuleName());
if (module != null && ModuleType.get(module) instanceof FlexModuleType) {
return new Module[]{module};
}
else {
return Module.EMPTY_ARRAY;
}
}
@Override
public String suggestedName() {
return myRunnerParameters.suggestName();
}
@Override
public RefactoringElementListener getRefactoringElementListener(final PsiElement element) {
if (!myRunnerParameters.isOverrideMainClass()) {
return null;
}
final Module module = ModuleManager.getInstance(getProject()).findModuleByName(myRunnerParameters.getModuleName());
if (!(element instanceof PsiDirectoryContainer) && !(element instanceof JSPackage) && !(element instanceof JSPackageStatement)
&& (module == null || !module.equals(ModuleUtilCore.findModuleForPsiElement(element)))) {
return null;
}
final String currentPackage = StringUtil.getPackageName(myRunnerParameters.getOverriddenMainClass());
if ((element instanceof PsiDirectoryContainer || element instanceof JSPackage || element instanceof JSPackageStatement) &&
Comparing.strEqual(FlexRefactoringListenerProvider.getPackageName(element), currentPackage)) {
return new FlexRunConfigRefactoringListener.PackageRefactoringListener(this);
}
if (element instanceof PsiDirectory && containsClass(module, ((PsiDirectory)element), myRunnerParameters.getOverriddenMainClass())) {
return new FlexRunConfigRefactoringListener.PsiDirectoryRefactoringListener(this);
}
final JSClass jsClass = FlexRefactoringListenerProvider.getJSClass(element);
if (jsClass != null && Comparing.strEqual(jsClass.getQualifiedName(), myRunnerParameters.getOverriddenMainClass())) {
return new FlexRunConfigRefactoringListener.JSClassRefactoringListener(this);
}
return null;
}
public static boolean containsClass(final Module module, final PsiDirectory directory, final String className) {
final String packageName = DirectoryIndex.getInstance(module.getProject()).getPackageName(directory.getVirtualFile());
if (!StringUtil.getPackageName(className).equals(packageName)) return false;
final PsiElement psiElement = ActionScriptClassResolver.findClassByQNameStatic(className, GlobalSearchScope.moduleScope(module));
return psiElement instanceof JSClass && directory.equals(psiElement.getContainingFile().getParent());
}
public static class AirRunState extends CommandLineState {
private final Project myProject;
private final BCBasedRunnerParameters myRunnerParameters;
public AirRunState(final Project project, ExecutionEnvironment env, final BCBasedRunnerParameters runnerParameters) {
super(env);
myProject = project;
myRunnerParameters = runnerParameters;
}
@Override
@NotNull
protected OSProcessHandler startProcess() throws ExecutionException {
final FlexBuildConfiguration bc;
try {
bc = myRunnerParameters.checkAndGetModuleAndBC(myProject).second;
}
catch (RuntimeConfigurationError e) {
throw new ExecutionException(e.getMessage());
}
final Sdk sdk = bc.getSdk();
assert sdk != null;
final boolean needToRemoveAirRuntimeDir;
final VirtualFile airRuntimeDirForFlexmojosSdk;
if (sdk.getSdkType() instanceof FlexmojosSdkType) {
final Pair<VirtualFile, Boolean> airRuntimeDirInfo;
try {
airRuntimeDirInfo = FlexSdkUtils.getAirRuntimeDirInfoForFlexmojosSdk(sdk);
}
catch (IOException e) {
throw new ExecutionException(e.getMessage());
}
needToRemoveAirRuntimeDir = airRuntimeDirInfo.second;
airRuntimeDirForFlexmojosSdk = airRuntimeDirInfo.first;
}
else {
needToRemoveAirRuntimeDir = false;
airRuntimeDirForFlexmojosSdk = null;
}
final String airRuntimePath = airRuntimeDirForFlexmojosSdk == null ? null : airRuntimeDirForFlexmojosSdk.getPath();
final OSProcessHandler processHandler =
JavaCommandLineStateUtil.startProcess(FlexBaseRunner.createAdlCommandLine(myProject, myRunnerParameters, bc, airRuntimePath));
if (needToRemoveAirRuntimeDir && airRuntimeDirForFlexmojosSdk != null) {
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(final ProcessEvent event) {
FlexUtils.removeFileLater(airRuntimeDirForFlexmojosSdk);
}
});
}
return processHandler;
}
}
}