package com.sap.furcas.ide.editor.contentassist;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import org.antlr.runtime.Token;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.ETypedElement;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.swt.graphics.Image;
import com.sap.furcas.metamodel.FURCAS.TCS.ClassTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.FunctionCall;
import com.sap.furcas.metamodel.FURCAS.TCS.Property;
import com.sap.furcas.metamodel.FURCAS.TCS.SequenceElement;
import com.sap.furcas.metamodel.FURCAS.TCS.Template;
import com.sap.furcas.runtime.tcs.PropertyArgumentUtil;
import com.sap.furcas.runtime.tcs.TcsUtil;
public class CtsContentAssistUtil {
private static Image keywordImage = null;
private static Image propertyImage = null;
private static Image propValueImage = null;
private static Image templateImage = null;
private static ITextViewer imageHostViewer = null;
private static ICompletionProposal createProposal(String displayString, String replacementString, Image img,
ITextViewer viewer, int line, int charPositionInLine, Token token) {
int cursorPosition = getOffset(viewer, line, charPositionInLine);
int replacementOffset = cursorPosition;
int replacementLength = 0;
if (token != null) {
if (isInToken(line, charPositionInLine, token)) {
replacementOffset = getOffset(viewer, getLine(token), getCharPositionInLine(token));
replacementLength = Math.min(displayString.length(),
Math.min(getLength(token), getCommonPrefix(token.getText(), replacementString).length()));
} else {
// TODO workaround because ANTRL will not create error token
// for unlexed characters
// TODO this assumes languages with standard whitespaces
// filter by currently un-tokenized non-whitespace prefix
int stopOffset = -1;
// stop at end of last valid token
if (getCharPositionInLine(token) != -1) {
try {
stopOffset = viewer.getDocument().getLineInformation(getLine(token)).getOffset()
+ getCharPositionInLine(token);
} catch (BadLocationException e) {
// do nothing
}
}
String prefix = "";
try {
prefix = computeNonWhitespacePrefix(viewer.getDocument().get(), viewer.getDocument().getLineInformation(line)
.getOffset()
+ charPositionInLine, stopOffset);
} catch (BadLocationException e) {
// do nothing
}
if (!prefix.isEmpty()) {
replacementOffset = cursorPosition - prefix.length();
replacementLength = Math.min(displayString.length(),
Math.min(prefix.length(), getCommonPrefix(prefix, replacementString).length()));
}
// end workaround
}
}
return new CompletionProposal(replacementString, replacementOffset, replacementLength, replacementString.length(), img,
displayString, null, null);
}
/**
* computes the non-whitespace-prefix starting at the offset and going back
* until reaching stopOffset
*
* @param documentContents
* @param offset
* @param stopOffset
* @return
*/
public static String computeNonWhitespacePrefix(String documentContents, int offset, int stopOffset) {
String result = "";
int curOffset = offset - 1;
while (curOffset >= 0 && !(curOffset == stopOffset) && !isWhitespace(documentContents.charAt(curOffset))) {
result = documentContents.charAt(curOffset) + result;
curOffset--;
}
return result;
}
private static boolean isWhitespace(char c) {
return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
}
public static String getCommonPrefix(String a, String b) {
int prefixLength = 0;
while (prefixLength < a.length() && prefixLength < b.length()) {
if (a.regionMatches(0, b, 0, prefixLength + 1)) {
prefixLength++;
} else {
break;
}
}
return a.substring(0, prefixLength);
}
private static Image getKeywordImage(ITextViewer currentViewer) {
if (imageHostViewer != currentViewer || keywordImage == null) {
imageHostViewer = currentViewer;
keywordImage = new Image(imageHostViewer.getTextWidget().getDisplay(),
CtsContentAssistUtil.class.getResourceAsStream("img/keyword.gif"));
}
return keywordImage;
}
private static Image getPropertyImage(ITextViewer currentViewer) {
if (imageHostViewer != currentViewer || propertyImage == null) {
imageHostViewer = currentViewer;
propertyImage = new Image(imageHostViewer.getTextWidget().getDisplay(),
CtsContentAssistUtil.class.getResourceAsStream("img/property.gif"));
}
return propertyImage;
}
private static Image getPropValueImage(ITextViewer currentViewer) {
if (imageHostViewer != currentViewer || propValueImage == null) {
imageHostViewer = currentViewer;
propValueImage = new Image(imageHostViewer.getTextWidget().getDisplay(),
CtsContentAssistUtil.class.getResourceAsStream("img/propValue.gif"));
}
return propValueImage;
}
private static Image getTemplateImage(ITextViewer currentViewer) {
if (imageHostViewer != currentViewer || templateImage == null) {
imageHostViewer = currentViewer;
templateImage = new Image(imageHostViewer.getTextWidget().getDisplay(),
CtsContentAssistUtil.class.getResourceAsStream("img/template.gif"));
}
return templateImage;
}
public static ICompletionProposal createKeywordProposal(String displayString, String replacementString, ITextViewer viewer,
int line, int charPositionInLine, Token token) {
Image img = null;
if (viewer != null && viewer.getTextWidget() != null) {
img = getKeywordImage(viewer);
}
return createProposal(displayString, replacementString, img, viewer, line, charPositionInLine, token);
}
public static ICompletionProposal createPropValueProposal(String displayString, String replacementString, ITextViewer viewer,
int line, int charPositionInLine, Token token) {
Image img = null;
if (viewer != null && viewer.getTextWidget() != null) {
img = getPropValueImage(viewer);
}
return createProposal(displayString, replacementString, img, viewer, line, charPositionInLine, token);
}
public static ICompletionProposal createTemplateProposal(String displayString, String replacementString, ITextViewer viewer,
int line, int charPositionInLine, Token token) {
Image img = null;
if (viewer != null && viewer.getTextWidget() != null) {
img = getTemplateImage(viewer);
}
return createProposal(displayString, replacementString, img, viewer, line, charPositionInLine, token);
}
public static ICompletionProposal createPropertyProposal(String displayString, String replacementString, ITextViewer viewer,
int line, int charPositionInLine, Token token) {
Image img = null;
if (viewer != null && viewer.getTextWidget() != null) {
img = getPropertyImage(viewer);
}
return createProposal(displayString, replacementString, img, viewer, line, charPositionInLine, token);
}
public static int getOffset(ITextViewer viewer, int line, int charPositionInLine) {
if (viewer != null) {
try {
return viewer.getDocument().getLineOffset(line) + charPositionInLine;
} catch (BadLocationException e) {
e.printStackTrace();
}
}
return 0;
}
public static boolean isContained(SequenceElement e, Set<SequenceElement> templateFirstAtomicSet) {
if (e != null) {
return templateFirstAtomicSet.contains(e);
}
return false;
}
public static boolean isInToken(int line, int charPositionInLine, Token t) {
if (line != getLine(t)) {
return false;
}
if (charPositionInLine < getCharPositionInLine(t)) {
return false;
}
if (charPositionInLine > getCharPositionInLine(t) + getLength(t)) {
return false;
}
return true;
}
public static int getAbsoluteOffset(ITextViewer viewer, int line, int charPositionInLine) throws BadLocationException {
return viewer.getDocument().getLineInformation(line).getOffset() + charPositionInLine;
}
public static String getDocumentContents(ITextViewer viewer) {
return viewer.getDocument().get();
}
public static int getCharPositionInLine(Token token) {
// ANTRL line positions start at 0
return token.getCharPositionInLine();
}
public static int getLine(Token token) {
// ANTRL lines start at 1
return token.getLine() - 1;
}
public static int getLength(Token token) {
int length = 0;
if (token.getText() != null) {
length = token.getText().length();
}
return length;
}
public static boolean isContextAtWhitespace(ITextViewer viewer, CtsContentAssistContext context) throws BadLocationException {
if (context != null) {
if (context.getToken() != null) {
String contents = getDocumentContents(viewer);
int offset = getAbsoluteOffset(viewer, getLine(context.getToken()), getCharPositionInLine(context.getToken()));
char c = contents.charAt(offset);
if (isWhitespace(c)) {
return true;
}
}
}
return false;
}
public static void fixTokenText(ITextViewer viewer, Token t) throws BadLocationException {
// assumes the tokens line and charPositionInLine point to its start
// location
String contents = getDocumentContents(viewer);
int curOffset = CtsContentAssistUtil.getAbsoluteOffset(viewer, getLine(t), getCharPositionInLine(t));
String newText = "";
boolean firstWhitespace = true;
while (curOffset < contents.length()) {
char c = contents.charAt(curOffset);
if (!isWhitespace(c)) {
firstWhitespace = false;
newText += c;
} else {
if (!firstWhitespace) {
break;
}
// move token to the right or down
if (c == ' ' || c == '\t') {
t.setCharPositionInLine(t.getCharPositionInLine() + 1);
}
if (c == '\n') {
t.setLine(t.getLine() + 1);
}
}
curOffset++;
}
t.setText(newText);
}
/**
*
* @param viewer
* @param offset
* 0..n-1
* @return
* @throws BadLocationException
*/
public static int getLine(ITextViewer viewer, int offset) throws BadLocationException {
return viewer.getDocument().getLineOfOffset(offset);
}
public static boolean isAtEndOfToken(int line, int charPositionInLine, Token t) {
if (line != getLine(t)) {
return false;
}
if (charPositionInLine == getCharPositionInLine(t) + getLength(t)) {
return true;
}
return false;
}
public static boolean isAtomic(Property p, Map<List<String>, Map<String, ClassTemplate>> classTemplateMap) {
ETypedElement s = TcsUtil.getStructuralFeature(p);
if (s != null) {
if (s instanceof EReference) {
if (!PropertyArgumentUtil.containsRefersToArg(p) && !PropertyArgumentUtil.containsAsArg(p) && !PropertyArgumentUtil.containsLookupScopePArg(p)) {
return false;
}
}
if (s instanceof EAttribute && classTemplateMap != null) {
// check if we have a non-primitive type attribute by querying
// classTemplateMap
List<String> typeName = TcsUtil.getQualifiedName(TcsUtil.getType(p));
if (classTemplateMap.containsKey(typeName)) {
return false;
}
}
}
return true;
}
public static Stack<Property> duplicatePropertyStack(Stack<Property> source) {
if (source == null) {
return null;
}
Stack<Property> copiedPropertyStack = new Stack<Property>();
for (Property p : source) {
copiedPropertyStack.push(p);
}
return copiedPropertyStack;
}
public static Stack<FunctionCall> duplicateFunctionCallStack(Stack<FunctionCall> source) {
if (source == null) {
return null;
}
Stack<FunctionCall> copiedFunctionCallStack = new Stack<FunctionCall>();
for (FunctionCall p : source) {
copiedFunctionCallStack.push(p);
}
return copiedFunctionCallStack;
}
public static Stack<Template> duplicateTemplateStack(Stack<Template> source) {
if (source == null) {
return null;
}
Stack<Template> copiedTemplateStack = new Stack<Template>();
for (Template p : source) {
copiedTemplateStack.push(p);
}
return copiedTemplateStack;
}
}