/*******************************************************************************
* Copyright (c) 2005, 2012 eBay Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
*******************************************************************************/
package org.eclipse.vjet.eclipse.codeassist.keywords;
import java.util.List;
import org.eclipse.vjet.dsf.jst.IJstNode;
import org.eclipse.vjet.dsf.jst.IJstType;
import org.eclipse.vjet.dsf.jst.IJstTypeReference;
import org.eclipse.vjet.dsf.jstojava.translator.robust.completion.JstCompletion;
import org.eclipse.vjet.eclipse.codeassist.CodeassistUtils;
import org.eclipse.vjet.eclipse.codeassist.compliance.SupportedByAnnotationAcceptor;
import org.eclipse.vjet.eclipse.codeassist.keywords.MethodCompletionHandler.TypeMembersRequestor;
import org.eclipse.vjet.eclipse.core.IJSMethod;
import org.eclipse.vjet.eclipse.internal.core.util.Util;
import org.eclipse.vjet.vjo.meta.VjoKeywords;
import org.eclipse.vjet.vjo.tool.typespace.TypeSpaceMgr;
import org.eclipse.core.resources.IProject;
import org.eclipse.dltk.mod.compiler.env.ISourceModule;
import org.eclipse.dltk.mod.core.CompletionProposal;
import org.eclipse.dltk.mod.core.DLTKCore;
import org.eclipse.dltk.mod.core.IField;
import org.eclipse.dltk.mod.core.IMethod;
import org.eclipse.dltk.mod.core.IModelElement;
import org.eclipse.dltk.mod.core.IType;
import org.eclipse.dltk.mod.core.ModelException;
import org.eclipse.dltk.mod.internal.core.JSSourceField;
import org.eclipse.dltk.mod.internal.core.JSSourceFieldElementInfo;
import org.eclipse.dltk.mod.internal.core.JSSourceMethod;
import org.eclipse.dltk.mod.internal.core.JSSourceType;
import org.eclipse.dltk.mod.internal.core.NativeVjoSourceModule;
import org.eclipse.dltk.mod.internal.core.VjoLocalVariable;
public class FieldExpressionHandler {
private static final String GLOBAL = TypeSpaceMgr.GLOBAL;
static FieldExpressionHandler getNonForcedHandler() {
return new FieldExpressionHandler(false);
}
private boolean forceInherits;
private FieldExpressionHandler(boolean forceInherits) {
this.forceInherits = forceInherits;
}
FieldExpressionHandler() {
this(true);
}
private boolean isAccepted(IJstNode jst,
SupportedByAnnotationAcceptor acceptor) {
boolean isAccepted = true;
if (jst != null) {
isAccepted = acceptor.accept(jst.getAnnotations());
}
return isAccepted;
}
public void complete(ISourceModule module, int position,
JstCompletion completion, List<CompletionProposal> list,
Object jstNode) {
String token = completion.getToken();
String typeName = completion.getOwnerType().getName();
IType currentType = CodeassistUtils.getCurrentType(module, typeName);
IType type = getType(module, jstNode, typeName);
if (type != null) {
IProject typeProject = type.getParent().getScriptProject()
.getProject();
SupportedByAnnotationAcceptor acceptor = SupportedByAnnotationAcceptor
.getAcceptor(typeProject);
IJstType nativeJstType = null;
if (type.getSourceModule() instanceof NativeVjoSourceModule) {
List<IJstType> jstTypes = TypeSpaceMgr.getInstance().findType(
type.getElementName());
if(jstTypes != null && jstTypes.size() > 0){
nativeJstType = jstTypes.get(0);
}
}
TypeMembersRequestor requestor;
requestor = new MethodCompletionHandler.TypeMembersRequestor(token,
false, currentType, completion);
if (forceInherits) {
getMembers(requestor, type);
} else {
getOwnMembers(requestor, type);
}
if (isNeededGlobal(type)) {
IType global;
global = CodeassistUtils.createNativeType(module, GLOBAL);
getMembers(requestor, global);
}
List<IMethod> methods = requestor.getMethods();
for (IMethod method : methods) {
if (nativeJstType != null
&& !isAccepted(nativeJstType.getMethod(method
.getElementName()), acceptor)) {
continue;
}
char[] name = method.getElementName().toCharArray();
boolean isConstructor = false;
try {
isConstructor = method.isConstructor();
} catch (ModelException e) {
DLTKCore.error(e.toString(), e);
}
if (isConstructor && type.equals((method.getParent()))) {
continue;
} else if (isConstructor) {
name = VjoKeywords.BASE.toCharArray();
}
CompletionProposal data;
data = CompletionProposal.create(CompletionProposal.METHOD_REF,
position);
data.setCompletion(name);
data.setName(name);
data.setModelElement(method);
setParameters(method, data);
int flags = 0;
try {
flags = method.getFlags();
} catch (ModelException e) {
DLTKCore.error(e.toString(), e);
}
data.setFlags(flags);
data.setReplaceRange(position - token.length(), position);
String returnType = null;
try {
if (method instanceof IJSMethod) {
returnType = ((IJSMethod) method).getReturnType();
data.extraInfo = returnType + " - "
+ method.getParent().getElementName();
}
} catch (ModelException e) {
DLTKCore.error(e.toString(), e);
}
list.add(data);
}
List<IField> fields = requestor.getFields();
for (IField field : fields) {
if (nativeJstType != null
&& !isAccepted(nativeJstType.getProperty(field
.getElementName()), acceptor)) {
continue;
}
int flags = 0;
try {
flags = field.getFlags();
} catch (ModelException e) {
DLTKCore.error(e.toString(), e);
}
CompletionProposal data;
data = CompletionProposal.create(CompletionProposal.FIELD_REF,
position);
data.setCompletion(field.getElementName().toCharArray());
data.setName(field.getElementName().toCharArray());
data.setModelElement(field);
data.setFlags(flags);
data.setReplaceRange(position - token.length(), position);
// add a type
try {
JSSourceFieldElementInfo info = (JSSourceFieldElementInfo) ((JSSourceField) field)
.getElementInfo();
typeName = info.getType();
} catch (ModelException e) {
DLTKCore.error(e.toString(), e);
}
data.extraInfo = typeName + " - "
+ field.getParent().getElementName();
list.add(data);
}
}
// CompletionContext.isInstanceContext = false;
}
private boolean isNeededGlobal(IType type) {
String name = type.getElementName();
return TypeSpaceMgr.OBJECT.equals(name)
|| !TypeSpaceMgr.isNativeGlobalObject(name);
}
public static IType getType(ISourceModule module, Object jstNode,
String typeName) {
IType type;
IModelElement element = getElement(module, jstNode);
// if (element instanceof NativeVjoSourceModule) {
// NativeVjoSourceModule sourceModule = (NativeVjoSourceModule) element;
// type = sourceModule.getType();
// } else
if (element instanceof JSSourceType) {
type = (IType) element;
} else {
try {
if (element instanceof JSSourceMethod) {
typeName = ((JSSourceMethod) element).getReturnType();
} else if (element instanceof JSSourceField) {
JSSourceFieldElementInfo info = (JSSourceFieldElementInfo) ((JSSourceField) element)
.getElementInfo();
typeName = info.getType();
} else if (element instanceof VjoLocalVariable) {
typeName = ((VjoLocalVariable) element).getTypeSignature();
}
} catch (Exception e) {
DLTKCore.error(e.toString(), e);
}
IModelElement sm = element;
if (sm == null) {
return null;
}
sm = sm.getAncestor(IModelElement.SOURCE_MODULE);
type = CodeassistUtils.findType((ISourceModule) sm, typeName);
if (type == null) {
type = CodeassistUtils.getType((ISourceModule) sm, typeName);
}
if (type == null) {
// lets try to find native type
type = CodeassistUtils.findNativeSourceType((ISourceModule) sm,
typeName);
}
}
return type;
}
private static IModelElement getElement(ISourceModule module, Object jstNode) {
IModelElement element = null;
if (element == null) {
IModelElement[] modelElements = CodeassistUtils
.resolveQualifiedNameReference(jstNode, module);
if (modelElements != null && modelElements.length > 0) {
element = modelElements[0];
}
}
return element;
}
public Class getCompletionClass() {
// TODO Auto-generated method stub
return null;
}
protected void getOwnMembers(TypeMembersRequestor requestor, IType type) {
if (type == null || requestor == null) {
return;
}
try {
IMethod[] methods = type.getMethods();
IField[] fields = type.getFields();
for (IMethod method : methods) {
requestor.acceptMember(method);
}
for (IField field : fields) {
requestor.acceptMember(field);
}
} catch (ModelException me) {
DLTKCore.error(me.toString(), me);
}
}
protected void getMembers(TypeMembersRequestor requestor, IType type) {
if (type == null || requestor == null) {
return;
}
try {
getOwnMembers(requestor, type);
String[] superClassNames = type.getSuperClasses();
if (superClassNames != null && superClassNames.length > 0) {
IType superType = CodeassistUtils.findResourceType(
(ISourceModule) type.getParent(), superClassNames[0]);
if (superType != null) {
getMembers(requestor, superType);
}
}
IJstType jstType = Util.toJstType(type);
if (jstType != null) {
List<? extends IJstTypeReference> mixinTypes = Util.toJstType(
type).getMixinsRef();
for (IJstTypeReference mixinType : mixinTypes) {
getMembers(requestor, Util.toIType(mixinType
.getReferencedType()));
}
}
} catch (ModelException e) {
DLTKCore.error(e.toString(), e);
}
}
protected void setParameters(IMethod method, CompletionProposal data) {
try {
String[] paramNames = method.getParameters();
char[][] params = createParameters(paramNames);
data.setParameterNames(params);
} catch (ModelException e) {
DLTKCore.error(e.toString(), e);
}
}
protected char[][] createParameters(String[] paramNames) {
char[][] parameters = new char[paramNames.length][];
for (int i = 0; i < paramNames.length; i++) {
parameters[i] = paramNames[i].toCharArray();
}
return parameters;
}
}