package org.objectstyle.wolips.templateeditor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPathEditorInput;
import org.objectstyle.wolips.bindings.api.ApiUtils;
import org.objectstyle.wolips.bindings.utils.BindingReflectionUtils;
import org.objectstyle.wolips.bindings.wod.IWodElement;
import org.objectstyle.wolips.bindings.wod.IWodModel;
import org.objectstyle.wolips.bindings.wod.TagShortcut;
import org.objectstyle.wolips.variables.BuildProperties;
import org.objectstyle.wolips.wodclipse.core.completion.WodCompletionProposal;
import org.objectstyle.wolips.wodclipse.core.completion.WodCompletionUtils;
import org.objectstyle.wolips.wodclipse.core.completion.WodDeprecatedCompletionProposal;
import org.objectstyle.wolips.wodclipse.core.completion.WodParserCache;
import org.objectstyle.wolips.wodclipse.core.util.WodHtmlUtils;
import tk.eclipse.plugin.htmleditor.assist.AssistInfo;
import tk.eclipse.plugin.htmleditor.assist.AttributeInfo;
import tk.eclipse.plugin.htmleditor.assist.HTMLAssistProcessor;
import tk.eclipse.plugin.htmleditor.assist.TagDefinition;
import tk.eclipse.plugin.htmleditor.assist.TagInfo;
import tk.eclipse.plugin.htmleditor.editors.HTMLSourceEditor;
public class TemplateAssistProcessor extends HTMLAssistProcessor {
private static final int SCOPE = 100;
private static final int CLASS = 101;
private List<TagInfo> _tagList;
private WodParserCache _cache;
//private ClassNameAssistProcessor classNameProcessor = new ClassNameAssistProcessor();
private IFile _file;
private IEditorPart _editorPart;
private BuildProperties _buildProperties;
public TemplateAssistProcessor(IEditorPart editorPart, WodParserCache wodParserCache, BuildProperties buildProperties) {
_buildProperties = buildProperties;
_editorPart = editorPart;
_cache = wodParserCache;
_tagList = new ArrayList<TagInfo>(TagDefinition.getTagInfoAsList());
TagInfo treasureboat = new TagInfo("treasureboat", true);
treasureboat.addAttributeInfo(new AttributeInfo("name", true, AttributeInfo.NONE, true));
_tagList.add(treasureboat);
TagInfo tb = new TagInfo("tb", true);
tb.addAttributeInfo(new AttributeInfo("name", true, AttributeInfo.NONE, true));
_tagList.add(tb);
TagInfo webobject = new TagInfo("webobject", true);
webobject.addAttributeInfo(new AttributeInfo("name", true, AttributeInfo.NONE, true));
_tagList.add(webobject);
TagInfo wo = new TagInfo("wo", true);
wo.addAttributeInfo(new AttributeInfo("name", true, AttributeInfo.NONE, true));
_tagList.add(wo);
// // JSP directives
// _tagList.add(new TextInfo("<% %>", 3));
// _tagList.add(new TextInfo("<%= %>", 4));
// _tagList.add(new TextInfo("<%@ page %>", 9));
// _tagList.add(new TextInfo("<%@ include %>", "<%@ include file=\"\" %>", 18));
// _tagList.add(new TextInfo("<%@ taglib %>", "<%@ taglib prefix=\"\" %>", 19));
}
@Override
protected boolean supportTagRelation() {
return false;
}
protected IFile getFile() {
IFile wodFile = null;
IEditorInput input = _editorPart.getEditorInput();
if (input instanceof IPathEditorInput) {
IPathEditorInput pathInput = (IPathEditorInput) input;
IPath path = pathInput.getPath();
wodFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path);
}
return wodFile;
}
protected IJavaProject getJavaProject() {
IJavaProject javaProject = null;
IFile wodFile = getFile();
if (wodFile != null) {
IProject project = wodFile.getProject();
javaProject = JavaCore.create(project);
}
return javaProject;
}
@Override
protected List<TagInfo> getDynamicTagInfo(String tagName) {
List<TagInfo> tagInfos = null;
if (tagName.startsWith("tb:") || tagName.startsWith("wo:")) {
String elementPrefix = (tagName.startsWith("tb:")) ? "tb:" : "wo:";
String partialElementType = tagName.substring(elementPrefix.length());
IJavaProject javaProject = getJavaProject();
try {
Set<WodCompletionProposal> proposals = new HashSet<WodCompletionProposal>();
WodCompletionUtils.fillInElementTypeCompletionProposals(javaProject, partialElementType, 0, partialElementType.length(), proposals, false, null);
for (TagShortcut tagShortcut : _cache.getTagShortcuts()) {
String shortcut = tagShortcut.getShortcut();
if (shortcut.startsWith(partialElementType.toLowerCase())) {
proposals.add(new WodCompletionProposal(partialElementType, 0, partialElementType.length(), shortcut));
}
}
if (!proposals.isEmpty()) {
tagInfos = new LinkedList<TagInfo>();
for (WodCompletionProposal proposal : proposals) {
InlineWodTagInfo tagInfo = new InlineWodTagInfo(elementPrefix, proposal.getProposal(), WodParserCache.getTypeCache());
tagInfo.setJavaProject(javaProject);
tagInfos.add(tagInfo);
}
}
}
catch (JavaModelException e) {
e.printStackTrace();
}
}
return tagInfos;
}
@Override
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {
// Java code completion for partitions which are not parted as HTMLPartitionScanner#HTML_SCRIPT.
//String rawText = viewer.getDocument().get();
//System.out.println("TemplateAssistProcessor.computeCompletionProposals: " + rawText);
// rawText = HTMLUtil.comment2space(rawText, false);
// String text = rawText.substring(0, documentOffset);
// int begin = text.lastIndexOf("<%");
// if (begin >= 0) {
// int end = rawText.indexOf("%>", begin);
// if (end >= 0 && documentOffset < end) {
// return scriptletProcessor.computeCompletionProposals(viewer, documentOffset);
// }
// }
return super.computeCompletionProposals(viewer, documentOffset);
}
@Override
protected AssistInfo[] getAttributeValues(String tagName, String value, TagInfo tagInfo, AttributeInfo attrInfo) {
AssistInfo[] attributeValues;
TagInfo useTagInfo = tagInfo;
// support for TBOgnl_ParseStandardTags = true
if ( (! (useTagInfo instanceof InlineWodTagInfo)) && value != null && value.startsWith(_buildProperties.getInlineBindingPrefix()) ) {
InlineWodTagInfo tmpTagInfo = new InlineWodTagInfo("tb:", tagInfo.getTagName(), WodParserCache.getTypeCache());
tmpTagInfo.setRequiresAttributes(tagInfo.requiresAttributes());
tmpTagInfo.setJavaProject(getJavaProject());
useTagInfo = tmpTagInfo;
}
if (useTagInfo instanceof InlineWodTagInfo) {
List<AssistInfo> attributeValuesList = new LinkedList<AssistInfo>();
try {
InlineWodTagInfo wodTagInfo = (InlineWodTagInfo) useTagInfo;
String bindingValue = value;
String prefix = "$";
String suffix = "";
String inlineBindingPrefix = _buildProperties.getInlineBindingPrefix();
String inlineBindingSuffix = _buildProperties.getInlineBindingSuffix();
if (value.startsWith(inlineBindingPrefix)) {
prefix = inlineBindingPrefix;
bindingValue = value.substring(inlineBindingPrefix.length());
if (inlineBindingSuffix.length() > 0 && value.endsWith(inlineBindingSuffix)) {
bindingValue = bindingValue.substring(0, bindingValue.length() - inlineBindingSuffix.length());
suffix = inlineBindingSuffix;
}
}
else if (value.startsWith("~")) {
Matcher m = Pattern.compile("[a-z0-9.]*$").matcher(value);
if (m.find()) {
int index = m.start();
prefix = value.substring(0, index);
bindingValue = value.substring(index);
}
else {
prefix = "~";
bindingValue = "";
}
}
IFile wodFile = getFile();
String componentTypeName = wodFile.getLocation().removeFileExtension().lastSegment();
IType componentType = BindingReflectionUtils.findElementType(wodTagInfo.getJavaProject(), componentTypeName, true, WodParserCache.getTypeCache());
Set<WodCompletionProposal> proposals = new HashSet<WodCompletionProposal>();
int dotIndex = bindingValue.lastIndexOf('.');
if (dotIndex == -1) {
dotIndex = 0;
}
else {
dotIndex += (prefix.length() + 1);
}
boolean checkBindingValue = WodCompletionUtils.fillInBindingValueCompletionProposals(wodTagInfo.getJavaProject(), componentType, bindingValue, 0, bindingValue.length(), proposals, WodParserCache.getTypeCache());
if (checkBindingValue) {
try {
String elementTypeName = wodTagInfo.getExpandedElementTypeName();
IType elementType = BindingReflectionUtils.findElementType(wodTagInfo.getJavaProject(), elementTypeName, false, WodParserCache.getTypeCache());
String[] validValues = ApiUtils.getValidValues(value, wodTagInfo.getJavaProject(), _cache.getComponentType(), elementType, attrInfo.getAttributeName(), WodParserCache.getTypeCache());
if (validValues != null) {
String lowercaseBindingValue = bindingValue.toLowerCase();
for (String validValue : validValues) {
String lowercaseValidValue = validValue.toLowerCase();
if (lowercaseValidValue.toLowerCase().startsWith(lowercaseBindingValue) || (lowercaseValidValue.startsWith("\"") && lowercaseValidValue.substring(1).toLowerCase().startsWith(lowercaseBindingValue))) {
proposals.add(new WodCompletionProposal(bindingValue, 0, bindingValue.length(), validValue));
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
for (WodCompletionProposal proposal : proposals) {
String proposalString = proposal.getProposal();
if (dotIndex == 0) {
if (proposalString.startsWith("\"")) {
proposalString = proposalString.substring(1, proposalString.length() - 1);
}
else {
proposalString = prefix + proposalString + suffix;
}
}
AssistInfo assist = new AssistInfo(proposalString);
assist.setOffset(dotIndex);
if (proposal instanceof WodDeprecatedCompletionProposal) {
assist.setDeprecated(true);
}
attributeValuesList.add(assist);
}
}
catch (JavaModelException e) {
e.printStackTrace();
}
attributeValues = attributeValuesList.toArray(new AssistInfo[attributeValuesList.size()]);
}
else if ("name".equals(attrInfo.getAttributeName()) && WodHtmlUtils.isWOTag(tagName)) {
List<AssistInfo> attributeValuesList = new LinkedList<AssistInfo>();
try {
IWodModel wodModel = _cache.getWodEntry().getModel();
if (wodModel != null) {
for (IWodElement wodElement : wodModel.getElements()) {
String wodElementName = wodElement.getElementName();
if (wodElementName.toLowerCase().startsWith(value.toLowerCase())) {
AssistInfo assist = new AssistInfo(wodElementName);
attributeValuesList.add(assist);
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
attributeValues = attributeValuesList.toArray(new AssistInfo[attributeValuesList.size()]);
}
else {
// if (tagName.indexOf(":") != -1) {
// String[] dim = tagName.split(":");
// String uri = getUri(dim[0]);
// ICustomTagAttributeAssist[] assists = HTMLPlugin.getDefault().getCustomTagAttributeAssists();
// for (int i = 0; i < assists.length; i++) {
// AssistInfo[] values = assists[i].getAttributeValues(dim[1], uri, value, info);
// if (values != null) {
// return values;
// }
// }
// }
// if (info.getAttributeType() == SCOPE) {
// return new AssistInfo[] { new AssistInfo("application"), new AssistInfo("page"), new AssistInfo("request"), new AssistInfo("session") };
// }
// if (info.getAttributeType() == CLASS && this._file != null) {
// return classNameProcessor.getClassAttributeValues(this._file, value);
// }
attributeValues = super.getAttributeValues(tagName, value, useTagInfo, attrInfo);
}
return attributeValues;
}
@Override
protected TagInfo getTagInfo(String name) {
if (name.startsWith("tb:") || name.startsWith("wo:")) {
String elementPrefix = (name.startsWith("tb:")) ? "tb:" : "wo:";
String elementTypeName = name.substring(elementPrefix.length());
InlineWodTagInfo tagInfo = new InlineWodTagInfo(elementPrefix,elementTypeName, WodParserCache.getTypeCache());
tagInfo.setJavaProject(getJavaProject());
return tagInfo;
}
List tagList = getTagList();
for (int i = 0; i < tagList.size(); i++) {
TagInfo info = (TagInfo) tagList.get(i);
if (info.getTagName() != null) {
if (name.equals(info.getTagName().toLowerCase())) {
return info;
}
}
}
return null;
}
@Override
protected List<TagInfo> getTagList() {
List<TagInfo> list = new ArrayList<TagInfo>();
list.addAll(_tagList);
return list;
}
/**
* Updates informations about code completion.
*
* @param input the <code>HTMLSourceEditor</code> instance
* @param source JSP source code
*/
@Override
public void update(HTMLSourceEditor editor, String source) {
// this.scriptletProcessor.update((JSPSourceEditor) editor);
if (editor.getEditorInput() instanceof IFileEditorInput) {
IFileEditorInput input = (IFileEditorInput) editor.getEditorInput();
// cunstomTagList.clear();
// namespace.clear();
// JSPInfo jspInfo = JSPInfo.getJSPInfo(input.getFile(), source);
// TLDInfo[] tlds = jspInfo.getTLDInfo();
// for (int i = 0; i < tlds.length; i++) {
// namespace.put(tlds[i].getPrefix(), tlds[i].getTaglibUri());
// cunstomTagList.addAll(tlds[i].getTagInfo());
// }
_file = input.getFile();
}
super.update(editor, source);
}
}