package com.jetbrains.lang.dart.fixes;
import com.intellij.CommonBundle;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PathUtil;
import com.jetbrains.lang.dart.DartBundle;
import com.jetbrains.lang.dart.assists.AssistUtils;
import com.jetbrains.lang.dart.assists.DartSourceEditException;
import com.jetbrains.lang.dart.ide.annotator.DartProblemGroup;
import org.dartlang.analysis.server.protocol.SourceChange;
import org.dartlang.analysis.server.protocol.SourceFileEdit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
public final class DartQuickFix implements IntentionAction, Comparable<IntentionAction> {
@NotNull private final DartQuickFixSet myQuickFixSet;
private final int myIndex;
@Nullable private SourceChange mySourceChange;
@Nullable private DartProblemGroup.DartSuppressAction mySuppressActionDelegate;
public DartQuickFix(@NotNull final DartQuickFixSet quickFixSet, final int index) {
myIndex = index;
myQuickFixSet = quickFixSet;
}
@NotNull
@Override
public String getFamilyName() {
if (mySuppressActionDelegate != null) {
//noinspection DialogTitleCapitalization
return mySuppressActionDelegate.getFamilyName();
}
return getText();
}
@NotNull
@Override
public String getText() {
myQuickFixSet.ensureInitialized();
if (mySuppressActionDelegate != null) {
return mySuppressActionDelegate.getText();
}
return mySourceChange == null ? "" : mySourceChange.getMessage();
}
@Override
public int compareTo(IntentionAction o) {
if (o instanceof DartQuickFix) {
return myIndex - ((DartQuickFix)o).myIndex;
}
return 0;
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
if (mySuppressActionDelegate != null) {
mySuppressActionDelegate.invoke(project, editor, file);
}
if (mySourceChange == null) return;
final SourceFileEdit fileEdit = mySourceChange.getEdits().get(0);
final String filePath = FileUtil.toSystemIndependentName(fileEdit.getFile());
final VirtualFile virtualFile;
// Create the file if it does not exist.
if (fileEdit.getFileStamp() == -1) {
try {
final String directoryPath = PathUtil.getParentPath(filePath);
if (directoryPath.isEmpty()) throw new IOException("empty folder path");
final VirtualFile directory = VfsUtil.createDirectoryIfMissing(directoryPath);
if (directory == null) throw new IOException("failed to create folder " + FileUtil.toSystemDependentName(directoryPath));
virtualFile = directory.createChildData(this, PathUtil.getFileName(filePath));
}
catch (IOException e) {
final String message = DartBundle.message("failed.to.create.file.0.1", FileUtil.toSystemDependentName(filePath), e.getMessage());
CommonRefactoringUtil.showErrorHint(project, editor, message, CommonBundle.getErrorTitle(), null);
return;
}
}
else {
virtualFile = LocalFileSystem.getInstance().findFileByPath(filePath);
}
if (virtualFile == null) return;
if (!FileModificationService.getInstance().prepareVirtualFilesForWrite(project, Collections.singletonList(virtualFile))) return;
final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document == null) return;
try {
AssistUtils.applySourceChange(project, mySourceChange, true);
}
catch (DartSourceEditException e) {
CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(), CommonBundle.getErrorTitle(), null);
}
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
myQuickFixSet.ensureInitialized();
if (mySuppressActionDelegate != null) {
return mySuppressActionDelegate.isAvailable(project, editor, file);
}
if (mySourceChange == null) return false;
final List<SourceFileEdit> fileEdits = mySourceChange.getEdits();
if (fileEdits.size() != 1) return false;
final SourceFileEdit fileEdit = fileEdits.get(0);
final VirtualFile virtualFile = AssistUtils.findVirtualFile(fileEdit);
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
if (fileEdit.getFileStamp() != -1) {
if (virtualFile == null || !fileIndex.isInContent(virtualFile)) return false;
}
return true;
}
void setSourceChange(@Nullable final SourceChange sourceChange) {
mySourceChange = sourceChange;
}
void setSuppressActionDelegate(@Nullable final DartProblemGroup.DartSuppressAction suppressActionDelegate) {
mySuppressActionDelegate = suppressActionDelegate;
}
@Override
public boolean startInWriteAction() {
return true;
}
}