package com.redhat.ceylon.eclipse.code.correct;
import static com.redhat.ceylon.eclipse.code.correct.ImportProposals.importProposals;
import static com.redhat.ceylon.eclipse.code.correct.SpecifyTypeArgumentsProposal.addSpecifyTypeArgumentsProposal;
import static com.redhat.ceylon.eclipse.code.correct.TypeProposal.getTypeProposals;
import static com.redhat.ceylon.eclipse.ui.CeylonResources.REVEAL;
import static com.redhat.ceylon.eclipse.util.EditorUtil.getCurrentEditor;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.isTypeUnknown;
import static org.eclipse.jface.text.link.LinkedPositionGroup.NO_STOP;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedNamesAssistProposal.DeleteBlockingExitPolicy;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension6;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.link.ProposalPosition;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IEditorPart;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.eclipse.code.editor.CeylonEditor;
import com.redhat.ceylon.eclipse.platform.platformJ2C;
import com.redhat.ceylon.eclipse.util.Highlights;
import com.redhat.ceylon.eclipse.util.LinkedMode;
import com.redhat.ceylon.ide.common.platform.ReplaceEdit;
import com.redhat.ceylon.ide.common.platform.TextChange;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Type;
@Deprecated
public class SpecifyTypeProposal implements ICompletionProposal,
ICompletionProposalExtension6 {
private final Type infType;
private final String desc;
private final Tree.Type typeNode;
private CeylonEditor editor;
private final Tree.CompilationUnit rootNode;
private Point selection;
private SpecifyTypeProposal(String desc, Tree.Type type,
Tree.CompilationUnit cu, Type infType,
CeylonEditor editor) {
this.desc = desc;
this.typeNode = type;
this.rootNode = cu;
this.infType = rootNode.getUnit().denotableType(infType);
this.editor = editor;
}
@Override
public void apply(IDocument document) {
int offset = typeNode.getStartIndex();
int length = typeNode.getDistance();
if (editor==null) {
IEditorPart ed = getCurrentEditor();
if (ed instanceof CeylonEditor) {
editor = (CeylonEditor) ed;
}
}
if (editor==null) {
if (typeNode instanceof Tree.LocalModifier) {
TextChange change = new platformJ2C().newChange("Specify Type", document);
change.initMultiEdit();
HashSet<Declaration> decs = new HashSet<Declaration>();
importProposals().importType(decs, infType, rootNode);
int il = (int) importProposals().applyImports(change, decs, rootNode, change.getDocument());
String typeName =
infType.asSourceCodeString(rootNode.getUnit());
change.addEdit(new ReplaceEdit(offset, length, typeName));
change.apply();
offset += il;
length = typeName.length();
selection = new Point(offset, length);
}
}
else {
LinkedModeModel linkedModeModel = new LinkedModeModel();
ProposalPosition linkedPosition =
getTypeProposals(document, offset, length,
infType, rootNode, null);
try {
LinkedMode.addLinkedPosition(linkedModeModel, linkedPosition);
LinkedMode.installLinkedMode(editor, document, linkedModeModel,
this, new DeleteBlockingExitPolicy(document), NO_STOP, -1);
}
catch (BadLocationException e) {
e.printStackTrace();
}
}
}
static void addSpecifyTypeProposal(Tree.CompilationUnit cu, Node node,
Collection<ICompletionProposal> proposals, CeylonEditor editor) {
for (SpecifyTypeProposal proposal: createProposals(cu, node, editor)) {
proposals.add(proposal);
}
}
public static SpecifyTypeProposal createProposal(Tree.CompilationUnit cu,
Node node, CeylonEditor editor) {
Tree.Type type = (Tree.Type) node;
return new SpecifyTypeProposal("Declare explicit type",
type, cu, type.getTypeModel(), editor);
}
public static List<SpecifyTypeProposal> createProposals(Tree.CompilationUnit cu,
Node node, CeylonEditor editor) {
final Tree.Type type = (Tree.Type) node;
InferredType result = inferType(cu, type);
List<SpecifyTypeProposal> list =
new ArrayList<SpecifyTypeProposal>(2);
Type declaredType = type.getTypeModel();
if (!isTypeUnknown(declaredType)) {
if (!isTypeUnknown(result.generalizedType) &&
(isTypeUnknown(result.inferredType) ||
!result.generalizedType.isSubtypeOf(result.inferredType)) &&
!result.generalizedType.isSubtypeOf(declaredType)) {
list.add(new SpecifyTypeProposal("Widen type to",
type, cu, result.generalizedType, editor));
}
if (!isTypeUnknown(result.inferredType)) {
if (!result.inferredType.isSubtypeOf(declaredType)) {
list.add(new SpecifyTypeProposal("Change type to", type, cu,
result.inferredType, editor));
}
else if (!declaredType.isSubtypeOf(result.inferredType)) {
list.add(new SpecifyTypeProposal("Narrow type to", type, cu,
result.inferredType, editor));
}
}
if (type instanceof Tree.LocalModifier) {
list.add(new SpecifyTypeProposal("Declare explicit type",
type, cu, declaredType, editor));
}
}
else {
if (!isTypeUnknown(result.inferredType)) {
list.add(new SpecifyTypeProposal("Declare type", type, cu,
result.inferredType, editor));
}
if (!isTypeUnknown(result.generalizedType) &&
(isTypeUnknown(result.inferredType) ||
!result.generalizedType.isSubtypeOf(result.inferredType))) {
list.add(new SpecifyTypeProposal("Declare type", type, cu,
result.generalizedType, editor));
}
}
return list;
}
static InferredType inferType(Tree.CompilationUnit cu,
final Tree.Type type) {
InferTypeVisitor itv = new InferTypeVisitor(type.getUnit()) {
@Override
public void visit(Tree.TypedDeclaration that) {
if (that.getType()==type) {
dec = that.getDeclarationModel();
// union(that.getType().getTypeModel());
}
super.visit(that);
}
};
itv.visit(cu);
return itv.result;
}
@Override
public StyledString getStyledDisplayString() {
return Highlights.styleProposal(getDisplayString(), false);
}
@Override
public Point getSelection(IDocument document) {
return selection;
}
@Override
public String getAdditionalProposalInfo() {
return null;
}
@Override
public String getDisplayString() {
String type = infType.asString(rootNode.getUnit());
return desc + " '" + type + "'";
}
@Override
public Image getImage() {
return REVEAL;
}
@Override
public IContextInformation getContextInformation() {
return null;
}
static void addTypingProposals(Collection<ICompletionProposal> proposals,
IFile file, Tree.CompilationUnit cu, Node node,
Tree.Declaration decNode, CeylonEditor editor) {
if (decNode instanceof Tree.TypedDeclaration &&
!(decNode instanceof Tree.ObjectDefinition) &&
!(decNode instanceof Tree.Variable)) {
Tree.Type type = ((Tree.TypedDeclaration) decNode).getType();
if (type instanceof Tree.LocalModifier ||
type instanceof Tree.StaticType) {
addSpecifyTypeProposal(cu, type, proposals, editor);
}
}
else if (node instanceof Tree.LocalModifier ||
node instanceof Tree.StaticType) {
addSpecifyTypeProposal(cu, node, proposals, editor);
}
if (node instanceof Tree.MemberOrTypeExpression) {
addSpecifyTypeArgumentsProposal(cu, node, proposals, file);
}
}
}