bug224938 - refactored xpath content assistance
diff --git a/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/XSLCore.java b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/XSLCore.java
index dcfe0b5..9a08fee 100644
--- a/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/XSLCore.java
+++ b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/XSLCore.java
@@ -18,6 +18,7 @@
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
 import org.eclipse.wst.xsl.core.internal.model.Stylesheet;
 import org.eclipse.wst.xsl.core.internal.model.StylesheetBuilder;
 import org.eclipse.wst.xsl.core.internal.model.StylesheetModel;
@@ -146,4 +147,8 @@
 	{
 		return FileUtil.isXSLFile(file);
 	}
+	
+	public static boolean isXSLNamespace(IDOMNode node) {
+		return node.getNamespaceURI().equals(XSL_NAMESPACE_URI);
+	}
 }
diff --git a/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/util/StructuredDocumentUtil.java b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/util/StructuredDocumentUtil.java
new file mode 100644
index 0000000..1827d31
--- /dev/null
+++ b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/util/StructuredDocumentUtil.java
@@ -0,0 +1,34 @@
+package org.eclipse.wst.xsl.core.internal.util;
+
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
+
+/**
+ * General Purpose utility classes to convert from StructuredDocument to DOM.
+ * 
+ * @author dcarver
+ *
+ */
+public class StructuredDocumentUtil {
+	
+	/**
+	 * Given a StructuredDocumentRegion and a TextRegion, return a
+	 * IDOMNode for that particular position in the StructuredDocument
+	 * 
+	 * @param documentRegion
+	 * @param textRegion
+	 * @return IDOMNode
+	 */
+	public static IDOMNode getNode(IStructuredDocumentRegion documentRegion, ITextRegion textRegion) {
+		IStructuredModel sModel = StructuredModelManager.getModelManager().getExistingModelForRead(documentRegion.getParentDocument());
+		IDOMDocument documentNode = ((IDOMModel) sModel).getDocument();
+
+		return (IDOMNode)documentNode.getModel().getIndexedRegion(documentRegion.getStartOffset(textRegion));
+	}
+
+}
diff --git a/bundles/org.eclipse.wst.xsl.ui/src/org/eclipse/wst/xsl/ui/internal/contentassist/XSLContentAssistProcessor.java b/bundles/org.eclipse.wst.xsl.ui/src/org/eclipse/wst/xsl/ui/internal/contentassist/XSLContentAssistProcessor.java
index 32813cd..91e835c 100644
--- a/bundles/org.eclipse.wst.xsl.ui/src/org/eclipse/wst/xsl/ui/internal/contentassist/XSLContentAssistProcessor.java
+++ b/bundles/org.eclipse.wst.xsl.ui/src/org/eclipse/wst/xsl/ui/internal/contentassist/XSLContentAssistProcessor.java
@@ -25,7 +25,6 @@
 import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
 import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
 import org.eclipse.wst.sse.ui.internal.contentassist.CustomCompletionProposal;
-import org.eclipse.wst.xml.core.internal.contentmodel.util.DOMNamespaceHelper;
 import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
 import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;
 import org.eclipse.wst.xml.ui.internal.contentassist.ContentAssistRequest;
@@ -34,6 +33,7 @@
 import org.eclipse.wst.xml.xpath.ui.internal.contentassist.XPathTemplateCompletionProcessor;
 import org.eclipse.wst.xml.xpath.ui.internal.templates.TemplateContextTypeIdsXPath;
 import org.eclipse.wst.xsl.core.XSLCore;
+import org.eclipse.wst.xsl.core.internal.util.StructuredDocumentUtil;
 import org.eclipse.wst.xsl.ui.internal.XSLUIPlugin;
 import org.eclipse.wst.xsl.ui.internal.util.XSLPluginImageHelper;
 import org.eclipse.wst.xsl.ui.internal.util.XSLPluginImages;
@@ -91,6 +91,8 @@
 		super();
 	}
 	
+	
+	
 	/**
 	 * TODO: Add Javadoc
 	 * 
@@ -120,7 +122,6 @@
 	@Override
 	protected void addAttributeValueProposals(ContentAssistRequest contentAssistRequest) {
 		super.addAttributeValueProposals(contentAssistRequest);
-		String namespace = DOMNamespaceHelper.getNamespaceURI(contentAssistRequest.getNode());
 
 		String attributeName = getAttributeName(contentAssistRequest);
 		Element rootElement = contentAssistRequest.getNode().getOwnerDocument().getDocumentElement();
@@ -128,9 +129,9 @@
 		if (attributeName != null) {
 			int offset = contentAssistRequest.getStartOffset() + 1;
 
-			addAttributeValueOfProposals(contentAssistRequest, namespace, rootElement, offset);
+			addAttributeValueOfProposals(contentAssistRequest, contentAssistRequest.getNode().getNamespaceURI(), rootElement, offset);
 
-			if (isXSLNamespace(namespace)) {
+			if (XSLCore.isXSLNamespace((IDOMNode)contentAssistRequest.getNode())) {
 				addSelectAndTestProposals(contentAssistRequest, attributeName, rootElement, offset);
 				addMatchProposals(contentAssistRequest, attributeName,	offset);
 			}
@@ -156,10 +157,6 @@
 		}
 	}
 
-	private boolean isXSLNamespace(String namespace) {
-		return namespace != null && namespace.equals(XSLCore.XSL_NAMESPACE_URI);
-	}
-
 	private void addAttributeValueOfProposals(
 			ContentAssistRequest contentAssistRequest, String namespace, Element rootElement, int offset) {
 		if (contentAssistRequest.getMatchString().contains("{")) {
@@ -310,4 +307,107 @@
 		return null;
 	}
 
+	/**
+	 * Get the Match String.  This is typically the string-before the current
+	 * offset position.   For a standard XML Region this is calculated from the
+	 * beginning of the region (i.e. element, attribute, attribute value, etc.
+	 * For XSL, an additional check has to be made to determine if we are parsing
+	 * within an XPath region and where we are in the XPath region, as different
+	 * content assistance can be made available depending on where we are at.  This
+	 * primarily affects TEST, and SELECT attributes.
+	 * @param parent
+	 * @param aRegion
+	 * @param offset
+	 * @return
+	 */
+	@Override
+	protected String getMatchString(IStructuredDocumentRegion parent, ITextRegion aRegion, int offset) {
+		String emptyString = "";
+
+		if (isMatchStringEmpty(parent, aRegion, offset)) {
+			return emptyString; //$NON-NLS-1$
+		}
+		
+		if (hasXMLMatchString(parent, aRegion, offset)) {
+			return extractXMLMatchString(parent, aRegion, offset);
+		}
+		// This is here for saftey reasons.
+		return emptyString;
+	}
+
+	protected boolean notXPathRegion(IStructuredDocumentRegion nodeRegion, ITextRegion aRegion) {
+		IDOMNode currentNode = StructuredDocumentUtil.getNode(nodeRegion, aRegion);
+		
+		if (XSLCore.isXSLNamespace(currentNode)) {
+			
+		}
+
+		return true;
+	}
+	
+	/**
+	 * An XML Match string is extracted starting from the beginning of the
+	 * region to the current offset.
+	 * @param parent
+	 * @param aRegion
+	 * @param offset
+	 * @return
+	 */
+	protected String extractXMLMatchString(IStructuredDocumentRegion parent,
+			ITextRegion aRegion, int offset) {
+		return parent.getText(aRegion).substring(0, offset - parent.getStartOffset(aRegion));
+	}
+
+	protected boolean hasXMLMatchString(IStructuredDocumentRegion parent,
+			ITextRegion aRegion, int offset) {
+		return regionHasData(parent, aRegion) && isOffsetAfterStart(parent, aRegion, offset);
+	}
+
+	protected boolean isOffsetAfterStart(IStructuredDocumentRegion parent,
+			ITextRegion aRegion, int offset) {
+		return parent.getStartOffset(aRegion) < offset;
+	}
+
+	protected boolean regionHasData(IStructuredDocumentRegion parent,
+			ITextRegion aRegion) {
+		return parent.getText(aRegion).length() > 0;
+	}
+
+	protected boolean isXMLContentRegion(String regionType) {
+		return regionType == DOMRegionContext.XML_CONTENT;
+	}
+
+	protected boolean isOffsetAfterEndOffset(IStructuredDocumentRegion parent,
+			ITextRegion aRegion, int offset) {
+		return offset > getRegionEndOffset(parent, aRegion);
+	}
+
+	protected int getRegionEndOffset(IStructuredDocumentRegion parent,
+			ITextRegion aRegion) {
+		return parent.getStartOffset(aRegion) + aRegion.getTextLength();
+	}
+
+	protected boolean isXMLTagOpen(String regionType) {
+		return regionType == DOMRegionContext.XML_TAG_OPEN;
+	}
+
+	protected boolean isAttributeEqualsRegion(String regionType) {
+		return regionType == DOMRegionContext.XML_TAG_ATTRIBUTE_EQUALS;
+	}
+
+	protected boolean isMatchStringEmpty(IStructuredDocumentRegion parent, ITextRegion aRegion, int offset) {
+		return isRegionNull(aRegion) ||
+		       isCloseRegion(aRegion) ||
+		       isAttributeEqualsRegion(aRegion.getType()) ||
+		       isXMLTagOpen(aRegion.getType()) ||
+		       isOffsetAfterEndOffset(parent, aRegion, offset) ||
+		       isXMLContentRegion(aRegion.getType());
+	}
+	
+	protected boolean isRegionNull(ITextRegion aRegion) {
+		return aRegion == null;
+	}
+	
+	
+	
 }