package com.redhat.ceylon.eclipse.code.refactor;
import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.getProjectPhasedUnits;
import static com.redhat.ceylon.eclipse.util.InteropUtils.toJavaString;
import static org.eclipse.ltk.core.refactoring.RefactoringStatus.createWarningStatus;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.antlr.runtime.CommonToken;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ui.IEditorPart;
import com.redhat.ceylon.compiler.java.runtime.model.TypeDescriptor;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnits;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.CompilationUnit;
import com.redhat.ceylon.eclipse.code.editor.CeylonEditor;
import com.redhat.ceylon.eclipse.code.parse.CeylonParseController;
import com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies;
import com.redhat.ceylon.eclipse.util.Nodes;
import com.redhat.ceylon.ide.common.refactoring.DefaultRegion;
import com.redhat.ceylon.ide.common.refactoring.ExtractFunctionRefactoring;
import com.redhat.ceylon.ide.common.refactoring.createExtractFunctionRefactoring_;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.TypedDeclaration;
import ceylon.interop.java.CeylonIterable;
import ceylon.language.empty_;
public class EclipseExtractFunctionRefactoring extends AbstractRefactoring implements ExtractLinkedModeEnabled {
private String newName;
private boolean explicitType;
private TypedDeclaration resultDeclaration;
private Type returnType;
private Tree.Declaration target;
private ExtractFunctionRefactoring refactoring;
private CeylonEditor ce;
public EclipseExtractFunctionRefactoring(IEditorPart editor) {
super(editor);
if (rootNode!=null) {
if (editor instanceof CeylonEditor) {
CeylonEditor ce = (CeylonEditor) editor;
if (ce.getSelectionProvider()!=null) {
this.ce = ce;
selection = ce.getSelection();
}
}
if (resultDeclaration!=null) {
newName = resultDeclaration.getName();
}
else {
newName = Nodes.nameProposals(node)[0];
if ("it".equals(newName)) {
newName = "do";
}
}
}
init();
}
public EclipseExtractFunctionRefactoring(CeylonEditor editor,
Tree.Declaration target) {
this(editor);
this.target = target;
init();
}
private void init() {
if (newName == null) {
newName = "do";
}
CeylonParseController parseController =
ce.getParseController();
PhasedUnits projectPhasedUnits =
getProjectPhasedUnits(project);
refactoring = createExtractFunctionRefactoring_
.createExtractFunctionRefactoring(
Java2CeylonProxies.correctJ2C()
.newDocument(document),
selection.getOffset(),
selection.getOffset()
+ selection.getLength(),
parseController.getTypecheckedRootNode(),
parseController.getTokens(),
target,
projectPhasedUnits==null ?
(ceylon.language.Iterable)
empty_.get_() :
new CeylonIterable<PhasedUnit>(
TypeDescriptor.klass(PhasedUnit.class),
projectPhasedUnits.getPhasedUnits()),
parseController
.getLastPhasedUnit()
.getUnitFile(),
new ceylon.language.String(newName));
}
@Override
public boolean getEnabled() {
if (refactoring != null) {
return refactoring.getEnabled();
}
return sourceFile!=null &&
getEditable() &&
!sourceFile.getName()
.equals("module.ceylon") &&
!sourceFile.getName()
.equals("package.ceylon");
}
public String getName() {
return "Extract Function";
}
public boolean forceWizardMode() {
return refactoring.getForceWizardMode();
}
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
throws CoreException, OperationCanceledException {
String str = toJavaString(refactoring.checkInitialConditions());
if (str != null) {
return createWarningStatus(str);
}
return new RefactoringStatus();
}
public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
throws CoreException, OperationCanceledException {
Declaration existing =
node.getScope()
.getMemberOrParameter(node.getUnit(),
newName, null, false);
if (null!=existing) {
return createWarningStatus(
"An existing declaration named '" +
newName +
"' already exists in the same scope");
}
return new RefactoringStatus();
}
@Override
public IRegion getTypeRegion() {
return refactoring == null ? null : toRegion(refactoring.getTypeRegion());
}
@Override
public IRegion getDecRegion() {
return refactoring == null ? null : toRegion(refactoring.getDecRegion());
}
@Override
public IRegion getRefRegion() {
return refactoring == null ? null : toRegion(refactoring.getRefRegion());
}
private Region toRegion(DefaultRegion reg) {
if (reg == null) {
return null;
}
return new Region((int) reg.getStart(), (int) reg.getLength());
}
private boolean canBeInferred;
private IRegion selection;
public Change createChange(IProgressMonitor pm)
throws CoreException,
OperationCanceledException {
return Java2CeylonProxies.platformJ2C().getNativeChange(
refactoring.build());
}
public void setNewName(String text) {
newName = text;
refactoring.setNewName(newName);
}
public String getNewName() {
return newName;
}
public void setExplicitType() {
this.explicitType = !explicitType;
}
public Boolean getExplicitType() {
return explicitType;
}
Type getType() {
return returnType;
}
public String[] getNameProposals() {
return Nodes.nameProposals(node);
}
public boolean canBeInferred() {
return canBeInferred;
}
@Override
protected boolean isAffectingOtherFiles() {
return false;
}
public List<IRegion> getDupeRegions() {
if (refactoring != null) {
List<IRegion> regions = new ArrayList<>();
ceylon.language.List<? extends DefaultRegion> dupeRegions
= refactoring.getDupeRegions();
for (int i=0; i<dupeRegions.getSize(); i++) {
regions.add(toRegion(dupeRegions.getFromFirst(i)));
}
return regions;
}
return Collections.emptyList();
}
@Override
void refactorInFile(TextChange textChange, CompositeChange compositChange,
CompilationUnit rootNode, List<CommonToken> tokens) {
// not used
}
}