/*
* Copyright 2013-2015 Grzegorz Ligas <ligasgr@gmail.com> and other contributors
* (see the CONTRIBUTORS file).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.intellij.xquery.reference.namespace;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementResolveResult;
import com.intellij.psi.ResolveResult;
import com.intellij.psi.ResolveState;
import com.intellij.psi.util.PsiTreeUtil;
import org.intellij.xquery.psi.XQueryAttrLocalName;
import org.intellij.xquery.psi.XQueryDirAttribute;
import org.intellij.xquery.psi.XQueryDirAttributeList;
import org.intellij.xquery.psi.XQueryDirAttributeName;
import org.intellij.xquery.psi.XQueryPsiElement;
import org.intellij.xquery.psi.XQueryXmlEmptyTag;
import org.intellij.xquery.psi.XQueryXmlFullTag;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.intellij.xquery.reference.namespace.XQuery30PredeclaredNamespaces.XMLNS;
public class XQueryXmlNamespaceReference<T extends XQueryPsiElement> extends XQueryPrefixReference<T> {
public XQueryXmlNamespaceReference(T element, TextRange textRange) {
super(element, textRange);
}
@Override
protected Collection<ResolveResult> getPrimaryReferences() {
XQueryAttrLocalName matchingNamespaceDeclaration = getMatchingInlineNamespaceDeclaration();
if (matchingNamespaceDeclaration == null) {
matchingNamespaceDeclaration = getReferenceFromXmlUpInTheHierarchy();
}
if (matchingNamespaceDeclaration != null) {
return convertToResolveResults(matchingNamespaceDeclaration);
} else {
return Collections.emptyList();
}
}
private XQueryAttrLocalName getMatchingInlineNamespaceDeclaration() {
List<XQueryDirAttributeName> attributeNameList = getAttributeNames();
XQueryAttrLocalName matchingAttribute = null;
for (XQueryDirAttributeName attributeName : attributeNameList) {
if (isInlineNamespaceDeclaration(attributeName, myElement.getText())) {
matchingAttribute = attributeName.getAttrLocalName();
break;
}
}
return matchingAttribute;
}
private List<XQueryDirAttributeName> getAttributeNames() {
XQueryDirAttributeList attributeList = getAttributeList();
List<XQueryDirAttributeName> names = new ArrayList<XQueryDirAttributeName>();
for (XQueryDirAttribute dirAttribute : attributeList.getDirAttributeList()) {
names.add(dirAttribute.getDirAttributeName());
}
return names;
}
private XQueryDirAttributeList getAttributeList() {
PsiElement grandParent = myElement.getParent().getParent();
XQueryDirAttributeList attributeList;
if (grandParent instanceof XQueryXmlFullTag) {
attributeList = ((XQueryXmlFullTag) grandParent).getDirAttributeList();
} else if (grandParent instanceof XQueryXmlEmptyTag) {
attributeList = ((XQueryXmlEmptyTag) grandParent).getDirAttributeList();
} else {
attributeList = (XQueryDirAttributeList) grandParent.getParent();
}
return attributeList;
}
private boolean isInlineNamespaceDeclaration(XQueryDirAttributeName attributeName, String namespaceName) {
return attributeName.getAttrNamespace() != null
&& XMLNS.getPrefix().equals(attributeName.getAttrNamespace().getText())
&& namespaceName.equals(attributeName.getAttrLocalName().getText());
}
private Collection<ResolveResult> convertToResolveResults(XQueryAttrLocalName localName) {
Collection<ResolveResult> result = new ArrayList<ResolveResult>();
result.add(new PsiElementResolveResult(localName));
return result;
}
private XQueryAttrLocalName getReferenceFromXmlUpInTheHierarchy() {
XmlTagNamespaceReferenceScopeProcessor processor = new XmlTagNamespaceReferenceScopeProcessor<T>(myElement);
PsiTreeUtil.treeWalkUp(processor, myElement, null, ResolveState.initial());
if (processor.getResult() != null) {
return processor.getResult();
} else {
return null;
}
}
@Override
protected boolean includeOnlyPrimaryReferencesIfPresent() {
return true;
}
}