/* static */
void
txXPathNodeUtils::appendNodeValue(const txXPathNode& aNode, nsAString& aResult)
{
    if (aNode.isAttribute()) {
        const nsAttrName* name = aNode.Content()->GetAttrNameAt(aNode.mIndex);

        if (aResult.IsEmpty()) {
            aNode.Content()->GetAttr(name->NamespaceID(), name->LocalName(),
                                     aResult);
        }
        else {
            nsAutoString result;
            aNode.Content()->GetAttr(name->NamespaceID(), name->LocalName(),
                                     result);
            aResult.Append(result);
        }

        return;
    }

    if (aNode.isDocument() ||
        aNode.mNode->IsElement() ||
        aNode.mNode->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) {
        nsContentUtils::AppendNodeTextContent(aNode.mNode, true, aResult);

        return;
    }

    aNode.Content()->AppendTextTo(aResult);
}
/* static */
void
txXPathNodeUtils::getNodeName(const txXPathNode& aNode, nsAString& aName)
{
    if (aNode.isDocument()) {
        aName.Truncate();

        return;
    }

    if (aNode.isContent()) {
        // Elements and PIs have a name
        if (aNode.mNode->IsElement() ||
            aNode.mNode->NodeType() ==
            nsIDOMNode::PROCESSING_INSTRUCTION_NODE) {
            aName = aNode.Content()->NodeName();
            return;
        }

        aName.Truncate();

        return;
    }

    aNode.Content()->GetAttrNameAt(aNode.mIndex)->GetQualifiedName(aName);
}
/* static */
already_AddRefed<nsAtom>
txXPathNodeUtils::getLocalName(const txXPathNode& aNode)
{
    if (aNode.isDocument()) {
        return nullptr;
    }

    if (aNode.isContent()) {
        if (aNode.mNode->IsElement()) {
            RefPtr<nsAtom> localName =
                aNode.Content()->NodeInfo()->NameAtom();
            return localName.forget();
        }

        if (aNode.mNode->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
            return NS_Atomize(aNode.mNode->NodeName());
        }

        return nullptr;
    }

    // This is an attribute node, so we necessarily come from an element.
    RefPtr<nsAtom> localName =
      aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->LocalName();

    return localName.forget();
}
/* static */
already_AddRefed<nsIAtom>
txXPathNodeUtils::getLocalName(const txXPathNode& aNode)
{
    if (aNode.isDocument()) {
        return nsnull;
    }

    if (aNode.isContent()) {
        if (aNode.mNode->IsElement()) {
            nsIAtom* localName = aNode.Content()->Tag();
            NS_ADDREF(localName);

            return localName;
        }

        if (aNode.mNode->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
            nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode.mNode);
            nsAutoString target;
            node->GetNodeName(target);

            return NS_NewAtom(target);
        }

        return nsnull;
    }

    nsIAtom* localName = aNode.Content()->
        GetAttrNameAt(aNode.mIndex)->LocalName();
    NS_ADDREF(localName);

    return localName;
}
/* static */
bool
txXPathNodeUtils::getAttr(const txXPathNode& aNode, nsAtom* aLocalName,
                          int32_t aNSID, nsAString& aValue)
{
    if (aNode.isDocument() || aNode.isAttribute() ||
        !aNode.Content()->IsElement()) {
        return false;
    }

    return aNode.Content()->AsElement()->GetAttr(aNSID, aLocalName, aValue);
}
/* static */
PRInt32
txXPathNodeUtils::getNamespaceID(const txXPathNode& aNode)
{
    if (aNode.isDocument()) {
        return kNameSpaceID_None;
    }

    if (aNode.isContent()) {
        return aNode.Content()->GetNameSpaceID();
    }

    return aNode.Content()->GetAttrNameAt(aNode.mIndex)->NamespaceID();
}
/* static */
bool
txXPathNodeUtils::isWhitespace(const txXPathNode& aNode)
{
    NS_ASSERTION(aNode.isContent() && isText(aNode), "Wrong type!");

    return aNode.Content()->TextIsOnlyWhitespace();
}
/* static */
void
txXPathNodeUtils::getLocalName(const txXPathNode& aNode, nsAString& aLocalName)
{
    if (aNode.isDocument()) {
        aLocalName.Truncate();

        return;
    }

    if (aNode.isContent()) {
        if (aNode.mNode->IsNodeOfType(nsINode::eELEMENT)) {
            nsINodeInfo* nodeInfo = aNode.Content()->NodeInfo();
            nodeInfo->GetLocalName(aLocalName);

            // Check for html
            if (nodeInfo->NamespaceEquals(kNameSpaceID_None) &&
                aNode.mNode->IsNodeOfType(nsINode::eHTML)) {
                ToUpperCase(aLocalName);
            }

            return;
        }

        if (aNode.mNode->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
            // PIs don't have a nodeinfo but do have a name
            nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode.mNode);
            node->GetNodeName(aLocalName);

            return;
        }

        aLocalName.Truncate();

        return;
    }

    aNode.Content()->GetAttrNameAt(aNode.mIndex)->LocalName()->
      ToString(aLocalName);

    // Check for html
    if (aNode.Content()->NodeInfo()->NamespaceEquals(kNameSpaceID_None) &&
        aNode.Content()->IsNodeOfType(nsINode::eHTML)) {
        ToUpperCase(aLocalName);
    }
}
/* static */
bool
txXPathNodeUtils::getAttr(const txXPathNode& aNode, nsIAtom* aLocalName,
                          PRInt32 aNSID, nsAString& aValue)
{
    if (aNode.isDocument() || aNode.isAttribute()) {
        return PR_FALSE;
    }

    return aNode.Content()->GetAttr(aNSID, aLocalName, aValue);
}
/* static */
void
txXPathNodeUtils::getNodeName(const txXPathNode& aNode, nsAString& aName)
{
    if (aNode.isDocument()) {
        aName.Truncate();

        return;
    }

    if (aNode.isContent()) {
        if (aNode.mNode->IsElement()) {
            nsINodeInfo* nodeInfo = aNode.Content()->NodeInfo();
            nodeInfo->GetQualifiedName(aName);

            // Check for html
            if (aNode.Content()->IsHTML() &&
                aNode.Content()->IsInHTMLDocument()) {
                ToUpperCase(aName);
            }
            return;
        }

        if (aNode.mNode->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
            // PIs don't have a nodeinfo but do have a name
            nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode.mNode);
            node->GetNodeName(aName);

            return;
        }

        aName.Truncate();

        return;
    }

    aNode.Content()->GetAttrNameAt(aNode.mIndex)->GetQualifiedName(aName);

    // Check for html
    if (aNode.Content()->IsHTML()) {
        ToUpperCase(aName);
    }
}
/* static */
void
txXPathNodeUtils::getLocalName(const txXPathNode& aNode, nsAString& aLocalName)
{
    if (aNode.isDocument()) {
        aLocalName.Truncate();

        return;
    }

    if (aNode.isContent()) {
        if (aNode.mNode->IsElement()) {
            mozilla::dom::NodeInfo* nodeInfo = aNode.Content()->NodeInfo();
            nodeInfo->GetName(aLocalName);
            return;
        }

        if (aNode.mNode->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
            // PIs don't have a nodeinfo but do have a name
            // XXXbz Not actually true, but this function looks like it wants
            // different things from elements and PIs for "local name"...
            aLocalName = aNode.mNode->NodeName();
            return;
        }

        aLocalName.Truncate();

        return;
    }

    aNode.Content()->AsElement()->GetAttrNameAt(aNode.mIndex)->LocalName()->
      ToString(aLocalName);

    // Check for html
    if (aNode.Content()->NodeInfo()->NamespaceEquals(kNameSpaceID_None) &&
        aNode.Content()->IsHTMLElement()) {
        nsContentUtils::ASCIIToUpper(aLocalName);
    }
}
/* static */
nsresult
txXPathNativeNode::getNode(const txXPathNode& aNode, nsIDOMNode** aResult)
{
    if (!aNode.isAttribute()) {
        return CallQueryInterface(aNode.mNode, aResult);
    }

    const nsAttrName* name = aNode.Content()->GetAttrNameAt(aNode.mIndex);

    nsAutoString namespaceURI;
    nsContentUtils::NameSpaceManager()->GetNameSpaceURI(name->NamespaceID(), namespaceURI);

    nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode.mNode);
    nsCOMPtr<nsIDOMAttr> attr;
    element->GetAttributeNodeNS(namespaceURI,
                                nsDependentAtomString(name->LocalName()),
                                getter_AddRefs(attr));

    return CallQueryInterface(attr, aResult);
}