package org.eclipse.dltk.xotcl.internal.core;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.dltk.ast.ASTNode;
import org.eclipse.dltk.ast.declarations.FieldDeclaration;
import org.eclipse.dltk.ast.declarations.ModuleDeclaration;
import org.eclipse.dltk.ast.declarations.TypeDeclaration;
import org.eclipse.dltk.ast.expressions.Expression;
import org.eclipse.dltk.ast.references.SimpleReference;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IParent;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.mixin.IMixinElement;
import org.eclipse.dltk.core.mixin.IMixinRequestor;
import org.eclipse.dltk.tcl.ast.TclStatement;
import org.eclipse.dltk.tcl.core.TclParseUtil;
import org.eclipse.dltk.tcl.core.ast.ExtendedTclMethodDeclaration;
import org.eclipse.dltk.tcl.core.extensions.ISelectionExtension;
import org.eclipse.dltk.tcl.internal.core.codeassist.TclResolver;
import org.eclipse.dltk.tcl.internal.core.codeassist.TclSelectionEngine;
import org.eclipse.dltk.tcl.internal.core.codeassist.selection.SelectionOnKeywordOrFunction;
import org.eclipse.dltk.tcl.internal.core.search.mixin.TclMixinModel;
import org.eclipse.dltk.xotcl.core.ast.xotcl.XOTclExInstanceVariable;
import org.eclipse.dltk.xotcl.core.ast.xotcl.XOTclInstanceVariable;
import org.eclipse.dltk.xotcl.core.ast.xotcl.XOTclMethodCallStatement;
import org.eclipse.dltk.xotcl.core.ast.xotcl.XOTclMethodDeclaration;
import org.eclipse.dltk.xotcl.core.ast.xotcl.XOTclProcCallStatement;
import org.eclipse.dltk.xotcl.internal.core.parser.XOTclCommandDetector.XOTclGlobalClassParameter;
import org.eclipse.dltk.xotcl.internal.core.search.mixin.model.XOTclInstProc;
public class XOTclSelectionExtension implements ISelectionExtension {
public void selectionOnKeywordOrFunction(SelectionOnKeywordOrFunction key,
TclSelectionEngine engine) {
ASTNode originalNode = key.getOriginalNode();
if (originalNode instanceof TclStatement) {
processXOTclCommandCalls((TclStatement) originalNode, engine);
}
}
private void processXOTclInstanceVariable(XOTclInstanceVariable node,
TclSelectionEngine engine) {
SimpleReference classInstanceName = node.getClassInstanceName();
if (classInstanceName.sourceStart() <= engine.getActualSelectionStart()
&& engine.getActualSelectionStart() <= classInstanceName
.sourceEnd()) {
TypeDeclaration declaringType = node.getDeclaringType();
IModelElement type = engine.findElementFromNode(declaringType);
if (type != null) {
engine.addSelectionElement(type);
}
}
}
private void processXOTclCommandCalls(TclStatement node,
TclSelectionEngine engine) {
// System.out.println("CoOL:" + node);
if (node.getCount() == 0) {
return;
}
ASTNode parent = TclParseUtil.getPrevParent(engine.getAssistParser()
.getModule(), node);
String prefix = TclParseUtil.getElementFQN(parent,
IMixinRequestor.MIXIN_NAME_SEPARATOR, engine.getAssistParser()
.getModule());
Expression commandExpr = node.getAt(0);
String command = TclParseUtil.getNameFromNode(commandExpr);
IScriptProject project = engine.getScriptProject();
if (command != null && command.startsWith("::")) {
String name = command.substring(2);
// Check class proc call
String[] split = name.split("::");
IModelElement[] typeMixin = XOTclResolver.findTypeMixin(engine
.tclNameToKey(name), split[split.length - 1], project);
checkMixinTypeForMethod(node, commandExpr, typeMixin, prefix,
engine);
} else if (command != null) {
String[] split = command.split("::");
if (parent instanceof ModuleDeclaration) {
IModelElement[] typeMixin = XOTclResolver.findTypeMixin(engine
.tclNameToKey(command), split[split.length - 1],
project);
checkMixinTypeForMethod(node, commandExpr, typeMixin, prefix,
engine);
} else {
IModelElement[] typeMixin = XOTclResolver.findTypeMixin(prefix
+ IMixinRequestor.MIXIN_NAME_SEPARATOR
+ engine.tclNameToKey(command),
split[split.length - 1], project);
checkMixinTypeForMethod(node, commandExpr, typeMixin, prefix,
engine);
}
}
}
private boolean checkMixinTypeForMethod(TclStatement node,
Expression commandExpr, IModelElement[] typeMixin, String prefix,
TclSelectionEngine engine) {
for (int i = 0; i < typeMixin.length; i++) {
// Select type if point on type
if (commandExpr.sourceStart() <= engine.getActualSelectionStart()
&& engine.getActualSelectionStart() <= commandExpr
.sourceEnd()) {
engine.addSelectionElement(typeMixin[i]);
return true;
}
Expression callExpr = node.getAt(1);
if (node.getCount() > 1 && typeMixin[i] instanceof IParent) {
if (callExpr.sourceStart() <= engine.getActualSelectionStart()
&& engine.getActualSelectionStart() <= callExpr
.sourceEnd()) {
String call = TclParseUtil.getNameFromNode(callExpr);
IParent eParent = (IParent) typeMixin[i];
if (call != null) {
// search for method call in selected type
IModelElement[] children = null;
try {
children = eParent.getChildren();
} catch (ModelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (children != null) {
for (int j = 0; j < children.length; j++) {
if (children[j].getElementType() == IModelElement.METHOD
&& children[j].getElementName().equals(
call)) {
engine.addSelectionElement(children[j]);
return true;
}
}
}
// We need to check super type of this type.
if (eParent instanceof IType) {
IType type = (IType) eParent;
try {
String[] superClasses = type.getSuperClasses();
// String command = TclParseUtil
// .getNameFromNode(commandExpr);
if (superClasses != null) {
for (int j = 0; j < superClasses.length; j++) {
IModelElement[] ptypeMixin = XOTclResolver
.findTypeMixin(
(prefix.length() > 0 ? prefix
+ IMixinRequestor.MIXIN_NAME_SEPARATOR
: "")
+ engine
.tclNameToKey(superClasses[j]),
superClasses[j],
engine
.getScriptProject());
String[] split = superClasses[j]
.split("::");
checkMixinTypeForMethod(node,
commandExpr, ptypeMixin,
split[split.length - 1], engine);
}
}
} catch (ModelException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
}
}
}
}
}
return false;
}
private void processSelectXOTclMethod(XOTclProcCallStatement node,
int position, TclSelectionEngine engine) {
SimpleReference typeName = node.getInstNameRef();
List levels = TclParseUtil.findLevelsTo(engine.getAssistParser().getModule(),
node);
ASTNode nParent = (ASTNode) levels.get(levels.size() - 2);
TypeDeclaration type = TclParseUtil.findXOTclTypeDeclarationFrom(engine
.getAssistParser().getModule(), nParent, typeName.getName());
if (type instanceof TypeDeclaration) {
IModelElement parent = engine.findElementFromNode(type);
if (parent != null && parent instanceof IParent) {
if (node.getCallName().sourceStart() <= position
&& position <= node.getCallName().sourceEnd()) {
IModelElement methodElement = TclResolver
.findChildrenByName(node.getCallName().getName(),
(IParent) parent);
engine.addSelectionElement(methodElement);
return;
} else if (typeName.sourceStart() <= position
&& position <= typeName.sourceEnd()) {
engine.addSelectionElement(parent);
}
}
}
}
private void processSelectXOTclMethodDeclaration(
ExtendedTclMethodDeclaration node, int position,
TclSelectionEngine engine) {
ASTNode type = node.getDeclaringType();
if (type instanceof TypeDeclaration) {
SimpleReference ref = node.getTypeNameRef();
IModelElement parent = engine.findElementFromNode(type);
if (parent != null && parent instanceof IParent) {
if (node.getNameStart() <= position
&& position <= node.getNameEnd()) {
IModelElement methodElement = TclResolver
.findChildrenByName(node.getName(),
(IParent) parent);
engine.addSelectionElement(methodElement);
return;
} else if (ref.sourceStart() <= position
&& position <= ref.sourceEnd()) {
engine.addSelectionElement(parent);
}
}
}
}
private void processSelectXOTclMethod(XOTclMethodCallStatement call,
int position, TclSelectionEngine engine) {
FieldDeclaration instanceVar = call.getInstanceVariable();
SimpleReference callName = call.getCallName();
SimpleReference instName = call.getInstNameRef();
if (instanceVar != null && instanceVar instanceof XOTclInstanceVariable) {
// Check for method
if (callName.sourceStart() <= position
&& position <= callName.sourceEnd()) {
XOTclInstanceVariable instanceVariable = (XOTclInstanceVariable) instanceVar;
TypeDeclaration declaringType = instanceVariable
.getDeclaringType();
if (declaringType != null) {
IModelElement parent = engine
.findElementFromNode(declaringType);
if (parent != null) {
if (engine.checkMethodFrom(declaringType, callName,
parent)) {
return;
}
// Check mixin for selected class.
String typeMixin = TclParseUtil.getElementFQN(
declaringType,
IMixinRequestor.MIXIN_NAME_SEPARATOR, engine
.getAssistParser().getModule())
+ IMixinRequestor.MIXIN_NAME_SEPARATOR;
engine.findMethodMixin(typeMixin
+ engine.tclNameToKey(callName.getName()),
callName.getName());
// Check super.
ASTNode nde = TclParseUtil.getPrevParent(engine
.getAssistParser().getModule(), declaringType);
List supersToHandle = new ArrayList();
engine
.fillSuperClassesTo(declaringType,
supersToHandle);
TypeDeclaration prev = declaringType;
while (supersToHandle.size() > 0) {
String superClassName = (String) supersToHandle
.get(0);
supersToHandle.remove(0);
TypeDeclaration sType = TclParseUtil
.findXOTclTypeDeclarationFrom(engine
.getAssistParser().getModule(), nde,
superClassName);
if (sType != null) {
prev = sType;
engine
.fillSuperClassesTo(sType,
supersToHandle);
IModelElement sParent = engine
.findElementFromNode(sType);
if (engine.checkMethodFrom(sType, callName,
sParent)) {
return;
}
String sTypeMixin = TclParseUtil.getElementFQN(
sType,
IMixinRequestor.MIXIN_NAME_SEPARATOR,
engine.getAssistParser().getModule())
+ IMixinRequestor.MIXIN_NAME_SEPARATOR;
findXOTclMethodMixin(sTypeMixin
+ engine.tclNameToKey(callName
.getName()),
callName.getName(), engine);
// System.out.println("COOL");
} else {
String sTypeMixin = "";
if (prev != null) {
ASTNode prevParent = TclParseUtil
.getPrevParent(engine.getAssistParser()
.getModule(), prev);
if (prevParent instanceof ModuleDeclaration) {
sTypeMixin = engine
.tclNameToKey(superClassName)
+ IMixinRequestor.MIXIN_NAME_SEPARATOR;
} else {
sTypeMixin = TclParseUtil
.getElementFQN(
prevParent,
IMixinRequestor.MIXIN_NAME_SEPARATOR,
engine.getAssistParser()
.getModule())
+ IMixinRequestor.MIXIN_NAME_SEPARATOR
+ engine
.tclNameToKey(superClassName)
+ IMixinRequestor.MIXIN_NAME_SEPARATOR;
}
}
findXOTclMethodMixin(sTypeMixin
+ engine.tclNameToKey(callName
.getName()),
callName.getName(), engine);
// Lets also look to toplevel
findXOTclMethodMixin(engine
.tclNameToKey(superClassName)
+ IMixinRequestor.MIXIN_NAME_SEPARATOR
+ engine.tclNameToKey(callName
.getName()),
callName.getName(), engine);
}
}
}
}
}
} else if (instanceVar != null
&& instanceVar instanceof XOTclExInstanceVariable) {
// Check for method
XOTclExInstanceVariable instanceVariable = (XOTclExInstanceVariable) instanceVar;
IType type = (IType) instanceVariable.getDeclaringClassParameter()
.resolveElement();
if (type != null
&& (instName.sourceStart() <= position && position <= instName
.sourceEnd())) {
engine.addSelectionElement(type);
} else if (type != null && callName.sourceStart() <= position
&& position <= callName.sourceEnd()) {
String typeMixin = TclParseUtil.getFQNFromModelElement(type,
"::");
if (typeMixin.startsWith("::")) {
typeMixin = typeMixin.substring(2);
}
findXOTclMethodMixin(engine.tclNameToKey(typeMixin)
+ IMixinRequestor.MIXIN_NAME_SEPARATOR
+ engine.tclNameToKey(callName.getName()), callName
.getName(), engine);
// Check super.
List supersToHandle = new ArrayList();
String[] superClasses = null;
try {
superClasses = type.getSuperClasses();
} catch (ModelException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
if (superClasses != null) {
for (int i = 0; i < superClasses.length; i++) {
supersToHandle.add(superClasses[i]);
}
}
String prevClass = type.getFullyQualifiedName();
if (prevClass.startsWith("::")) {
prevClass = prevClass.substring(2);
}
while (supersToHandle.size() > 0) {
String superClassName = (String) supersToHandle.get(0);
supersToHandle.remove(0);
if (superClassName.startsWith("::")) {
findXOTclMethodMixin(superClassName.substring(2)
+ engine.tclNameToKey(callName.getName()),
callName.getName(), engine);
} else {
// remove one level from prev class
}
}
}
}
if (engine.getSelectionElementsSize() == 0) {
if (instName.sourceStart() <= position
&& position <= instName.sourceEnd()) {
engine.addElementFromASTNode(instanceVar);
}
}
}
private void findXOTclMethodMixin(String pattern, String name,
TclSelectionEngine engine) {
IScriptProject project = engine.getScriptProject();
IMixinElement[] find = TclMixinModel.getInstance().getMixin(project)
.find(pattern + "*");
int pos = pattern.indexOf(IMixinRequestor.MIXIN_NAME_SEPARATOR);
if (find.length == 0 && pos != -1) {
String newPattern = pattern.substring(0, pos);
find = TclMixinModel.getInstance().getMixin(project).find(
newPattern + "*");
}
for (int i = 0; i < find.length; i++) {
Object[] allObjects = find[i].getAllObjects();
for (int j = 0; j < allObjects.length; j++) {
if (allObjects[j] != null
&& allObjects[j] instanceof XOTclInstProc) {
XOTclInstProc field = (XOTclInstProc) allObjects[j];
if (name.equals(field.getName())) {
engine.addSelectionElement(field.getModelElement());
return;
}
}
}
}
}
public void selectionOnAST(ASTNode node, TclSelectionEngine engine) {
if (node instanceof XOTclMethodDeclaration) {
processSelectXOTclMethodDeclaration(
(ExtendedTclMethodDeclaration) node, engine
.getActualSelectionStart(), engine);
if (engine.getSelectionElementsSize() > 0) {
return;
}
}
}
public void selectionOnNode(ASTNode node, int position,
TclSelectionEngine engine) {
if (node instanceof XOTclMethodCallStatement) {
processSelectXOTclMethod((XOTclMethodCallStatement) node, position,
engine);
} else if (node instanceof XOTclProcCallStatement) {
processSelectXOTclMethod((XOTclProcCallStatement) node, position,
engine);
} else if (node instanceof XOTclMethodDeclaration) {
processSelectXOTclMethodDeclaration(
(ExtendedTclMethodDeclaration) node, engine
.getActualSelectionStart(), engine);
} else if (node instanceof TclStatement) {
// We need to check for XOTcl command calls.
processXOTclCommandCalls((TclStatement) node, engine);
} else if (node instanceof XOTclInstanceVariable) {
processXOTclInstanceVariable((XOTclInstanceVariable) node, engine);
} else if (node instanceof XOTclExInstanceVariable) {
XOTclExInstanceVariable ex = (XOTclExInstanceVariable) node;
XOTclGlobalClassParameter declaringClassParameter = ex
.getDeclaringClassParameter();
IModelElement resolveElement = declaringClassParameter
.resolveElement();
if (resolveElement != null) {
engine.addSelectionElement(resolveElement);
}
}
}
public IModelElement findElementParent(ASTNode node, String name,
IParent parent, TclSelectionEngine engine) {
return null;
}
public void findVariables(String name, ASTNode parent, int beforePosition,
TclSelectionEngine tclSelectionEngine) {
}
}