/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.completion.handlers;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import gw.lang.parser.IExpression;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.expressions.IParenthesizedExpression;
import gw.lang.parser.expressions.ITypeLiteralExpression;
import gw.lang.reflect.IConstructorInfo;
import gw.lang.reflect.IErrorType;
import gw.lang.reflect.IMetaType;
import gw.lang.reflect.IMethodInfo;
import gw.lang.reflect.INamespaceType;
import gw.lang.reflect.IParameterInfo;
import gw.lang.reflect.IPropertyInfo;
import gw.lang.reflect.IRelativeTypeInfo;
import gw.lang.reflect.IType;
import gw.lang.reflect.ITypeInfo;
import gw.lang.reflect.TypeSystem;
import gw.plugin.ij.completion.proposals.RawCompletionProposal;
import gw.plugin.ij.lang.parser.GosuCompositeElement;
import gw.plugin.ij.lang.parser.GosuRawPsiElement;
import gw.plugin.ij.lang.psi.api.expressions.IGosuReferenceExpression;
import gw.plugin.ij.lang.psi.impl.GosuBaseElementImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import static com.google.common.collect.Iterables.transform;
public class FeatureRefCompletionHandler extends AbstractPathCompletionHandler {
private IType _rootType;
public FeatureRefCompletionHandler(@NotNull CompletionParameters params, @NotNull CompletionResultSet result) {
super(params.getOriginalFile().getProject(), params, result.getPrefixMatcher(), result);
}
public void handleCompletePath() {
// head back to the other side of the dot
PsiElement prevSibling = getContext().getPosition().getPrevSibling();
if (prevSibling == null) {
return;
}
PsiElement csr = prevSibling.getPrevSibling();
if (csr != null) {
if (csr instanceof LeafPsiElement) {
csr = csr.getParent();
}
while (csr instanceof GosuRawPsiElement &&
((GosuRawPsiElement) csr).getParsedElement() instanceof IParenthesizedExpression) {
csr = csr.getFirstChild();
while (csr != null && csr instanceof LeafPsiElement) {
csr = csr.getNextSibling();
}
}
//## todo: handle this case better, we could be ignorign valid root expressions
if (!(csr instanceof GosuBaseElementImpl)) {
return;
}
GosuBaseElementImpl gosuRefExpr = (GosuBaseElementImpl) csr;
if (!(gosuRefExpr instanceof IGosuReferenceExpression)) {
return;
}
IExpression expr = (IExpression) gosuRefExpr.getParsedElement();
IParsedElement parentExpr = expr.getParent();
while (parentExpr instanceof IParenthesizedExpression) {
parentExpr = parentExpr.getParent();
}
if (expr instanceof ITypeLiteralExpression) {
_rootType = ((ITypeLiteralExpression) expr).getType().getType();
} else {
_rootType = expr.getType();
}
} else {
ASTNode fl = prevSibling.getParent().getNode();
if (fl instanceof GosuCompositeElement) {
GosuCompositeElement parent = (GosuCompositeElement) fl;
_rootType = ((GosuBaseElementImpl) parent.getPsi()).getParsedElement().getGosuClass();
} else {
return;
}
}
if (_rootType instanceof IErrorType || _rootType instanceof INamespaceType || (_rootType instanceof IMetaType && ((IMetaType) _rootType).getType() instanceof IErrorType)) {
return;
}
ITypeInfo ti = _rootType.getTypeInfo();
List<? extends IMethodInfo> methods;
List<? extends IPropertyInfo> properties;
List<? extends IConstructorInfo> ctors;
if (ti instanceof IRelativeTypeInfo) {
methods = ((IRelativeTypeInfo) ti).getMethods(_rootType);
properties = ((IRelativeTypeInfo) ti).getProperties(_rootType);
ctors = ((IRelativeTypeInfo) ti).getConstructors(_rootType);
} else {
methods = ti.getMethods();
properties = ti.getProperties();
ctors = ti.getConstructors();
}
for (IMethodInfo method : methods) {
if (!method.getDisplayName().startsWith("@")) {
addCompletion(new RawCompletionProposal(makeMethodRef(method)));
}
}
for (IPropertyInfo property : properties) {
addCompletion(new RawCompletionProposal(property.getName()));
}
for (IConstructorInfo ctor : ctors) {
addCompletion(new RawCompletionProposal(makeConstructorRef(ctor)));
}
}
private String makeConstructorRef(@NotNull IConstructorInfo ctor) {
return String.format("construct(%s)", getParams(ctor.getParameters()));
}
private String makeMethodRef(@NotNull IMethodInfo method) {
return String.format("%s(%s)", method.getDisplayName(), getParams(method.getParameters()));
}
private String getParams(IParameterInfo[] parameters) {
return Joiner.on(", ").join(transform(Arrays.asList(parameters), new Function<IParameterInfo, String>() {
@Override
public String apply(@NotNull IParameterInfo parameterInfo) {
final IType type = parameterInfo.getFeatureType();
if (type.equals(TypeSystem.getDefaultTypeUsesMap().resolveType(type.getRelativeName()))) {
return type.getRelativeName();
} else {
return type.getName();
}
}
}));
}
@Nullable
@Override
public String getStatusMessage() {
return _rootType == null ? null : _rootType.getName();
}
}