/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.completion.handlers;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.lang.ASTNode;
import gw.lang.parser.IExpression;
import gw.lang.parser.IParseIssue;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.expressions.*;
import gw.lang.parser.resources.Res;
import gw.lang.reflect.*;
import gw.plugin.ij.completion.model.BeanInfoModel;
import gw.plugin.ij.completion.model.BeanTree;
import gw.plugin.ij.completion.proposals.InitializerCompletionProposal;
import gw.plugin.ij.lang.parser.GosuCompositeElement;
import gw.plugin.ij.lang.psi.impl.GosuBaseElementImpl;
import gw.util.IFeatureFilter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class InitializerCompletionHandler extends AbstractPathCompletionHandler {
private IType _rootType;
public InitializerCompletionHandler(@NotNull CompletionParameters params, @NotNull CompletionResultSet result) {
super(params.getPosition().getProject(), params, result.getPrefixMatcher(), result);
}
public void handleCompletePath() {
IParsedElement parsedElement = null;
ASTNode node = getContext().getPosition().getParent().getParent().getNode();
if (node instanceof GosuCompositeElement) {
if (node.getPsi() instanceof GosuBaseElementImpl) {
parsedElement = ((GosuBaseElementImpl) node.getPsi()).getParsedElement();
}
} else {
return;
}
if (parsedElement != null) {
IObjectInitializerExpression oie = findObjectInitializerExpression(parsedElement);
if (oie != null) {
IType type = oie.getType();
String strMemberPath = "";
strMemberPath = strMemberPath != null ? strMemberPath.trim() : null;
final List<String> usedProperties = new ArrayList<>();
for (IInitializerAssignment prop : oie.getInitializers()) {
usedProperties.add(prop.getPropertyName());
}
//TODO cgross - pass in module?
BeanInfoModel model = new BeanInfoModel(type, strMemberPath, type, type.getTypeLoader().getModule(),
new IFeatureFilter() {
@Override
public boolean acceptFeature(IType beanType, @NotNull IFeatureInfo fi) {
return fi instanceof IPropertyInfo && ((IPropertyInfo) fi).isPublic() && ((IPropertyInfo) fi).isWritable();
}
});
makeProposals(model);
} else {
if (parsedElement instanceof IArgumentListClause) {
parsedElement = parsedElement.getParent();
}
if (parsedElement instanceof IMethodCallExpression) {
IFunctionType functionType = ((IMethodCallExpression) parsedElement).getFunctionType();
if (functionType != null) {
String[] parameterNames = functionType.getParameterNames();
IType[] parameterTypes = functionType.getParameterTypes();
IExpression[] defaultValues = functionType.getDefaultValueExpressions();
for (int i = 0; i < parameterNames.length; i++) {
String parameterName = parameterNames[i];
IType parameterType = parameterTypes[i];
boolean required = defaultValues.length < i || defaultValues[i] == null;
addCompletion(new InitializerCompletionProposal(parameterName, parameterType, required));
}
}
}
if (parsedElement instanceof INewExpression) {
INewExpression mc = (INewExpression) parsedElement;
IConstructorInfo ci = mc.getConstructor();
IParameterInfo[] parameterNames = ci.getParameters();
if (ci instanceof IOptionalParamCapable) {
IExpression[] defaultValues = ((IOptionalParamCapable) ci).getDefaultValueExpressions();
for (int i = 0; i < parameterNames.length; i++) {
IParameterInfo parameterName = parameterNames[i];
boolean required = defaultValues.length < i || defaultValues[i] == null;
addCompletion(new InitializerCompletionProposal(parameterName.getName(), parameterName.getFeatureType(), required));
}
}
}
if (parsedElement instanceof IBeanMethodCallExpression) {
IBeanMethodCallExpression mc = (IBeanMethodCallExpression) parsedElement;
IMethodInfo mi = mc.getMethodDescriptor();
IParameterInfo[] parameterNames = mi.getParameters();
if (mi instanceof IOptionalParamCapable) {
IExpression[] defaultValues = ((IOptionalParamCapable) mi).getDefaultValueExpressions();
for (int i = 0; i < parameterNames.length; i++) {
IParameterInfo parameterName = parameterNames[i];
boolean required = defaultValues.length < i || defaultValues[i] == null;
addCompletion(new InitializerCompletionProposal(parameterName.getName(), parameterName.getFeatureType(), required));
}
}
}
}
}
}
@NotNull
@Override
protected InitializerCompletionProposal makeProposal(@NotNull BeanTree child) {
return new InitializerCompletionProposal(child.getBeanNode().getName(), child.getBeanNode().getType(), true);
}
@Nullable
@Override
public String getStatusMessage() {
return _rootType == null ? null : _rootType.getName();
}
private boolean isDoubleColonAtCaret() {
// final GosuContentAssistantHelper helper = getViewer().getContentAssistParserHelper();
// if (":".equals(TextViewerUtil.getWordBeforeCaret(getViewer()))) {
// return helper.getDeepestLocationAtCaret() != null && helper.getDeepestLocationAtCaret().getParsedElement() instanceof IInitializerAssignment
// && helper.getExpressionAtCaret() == null;
// }
return false;
}
@Nullable
private IObjectInitializerExpression findObjectInitializerExpression(@NotNull IParsedElement parsedElement) {
if (parsedElement instanceof IObjectInitializerExpression) {
return (IObjectInitializerExpression) parsedElement;
} else if (parsedElement.getParent() != null) {
return findObjectInitializerExpression(parsedElement.getParent());
} else {
return null;
}
}
private static boolean isInitializerStart(@Nullable IParsedElement parsedElement) {
if (parsedElement instanceof IInitializerAssignment) {
IInitializerAssignment iia = (IInitializerAssignment) parsedElement;
if (parsedElement instanceof IIdentifierExpression) {
return true;
} else {
List<IParseIssue> exceptions = iia.getParseExceptions();
for (IParseIssue exception : exceptions) {
if (exception.getMessageKey().equals(Res.MSG_EQUALS_FOR_INITIALIZER_EXPR) || exception.getMessageKey().equals(Res.MSG_NO_PROPERTY_DESCRIPTOR_FOUND)) {
return true;
}
}
return false;
}
} else {
return parsedElement != null && isInitializerStart(parsedElement.getParent());
}
}
}