package org.basex.api.dom;
import static org.basex.util.Token.*;
import org.basex.data.Data;
import org.basex.io.IO;
import org.basex.query.item.ANode;
import org.basex.query.item.NodeType;
import org.basex.query.iter.NodeCache;
import org.basex.query.iter.AxisIter;
import org.basex.util.Util;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.UserDataHandler;
/**
* DOM - Node implementation.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public abstract class BXNode implements Node {
/** Node type mapping (see {@link Data} interface). */
private static final short[] TYPES = {
Node.DOCUMENT_NODE, Node.ELEMENT_NODE,
Node.TEXT_NODE, Node.ATTRIBUTE_NODE,
Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
Node.CDATA_SECTION_NODE, Node.DOCUMENT_FRAGMENT_NODE
};
/** Node name mapping (see {@link Data} interface). */
private static final String[] NAMES = {
"#document", null, "#text", null, "#comment", null, "#cdata-section",
"#document-fragment"
};
/** Data reference. */
final ANode node;
/**
* Constructor.
* @param n node reference
*/
BXNode(final ANode n) {
node = n;
}
@Override
public String getNodeName() {
return NAMES[kind()];
}
@Override
public final short getNodeType() {
return TYPES[kind()];
}
/**
* Returns a numeric value for the node kind.
* @return node kind
*/
int kind() {
return node.kind();
}
@Override
public String getNodeValue() {
return null;
}
@Override
public String getLocalName() {
return null;
}
@Override
public final BXNode cloneNode(final boolean deep) {
return node.copy().toJava();
}
@Override
public final short compareDocumentPosition(final Node other) {
final int d = node.diff(((BXNode) other).node);
return (short) (d < 0 ? -1 : d > 0 ? 1 : 0);
}
@Override
public BXNNode getAttributes() {
return null;
}
@Override
public final String getBaseURI() {
return IO.get(string(node.baseURI())).url();
}
@Override
public BXNList getChildNodes() {
return new BXNList(finish(node.children()));
}
@Override
public BXNode getFirstChild() {
return toJava(node.children().next());
}
@Override
public final BXNode getLastChild() {
ANode n = null;
final AxisIter ai = node.children();
for(ANode t; (t = ai.next()) != null;) n = t;
return toJava(n);
}
@Override
public String getNamespaceURI() {
return null;
}
@Override
public BXNode getNextSibling() {
return toJava(node.followingSibling().next());
}
@Override
public BXNode getPreviousSibling() {
return toJava(node.precedingSibling().next());
}
@Override
public final BXNode getParentNode() {
return toJava(node.parent());
}
/**
* Returns a Java node for the specified argument or {@code null}.
* @param n node instance
* @return resulting node
*/
private static BXNode toJava(final ANode n) {
return n != null ? n.toJava() : null;
}
@Override
public final boolean hasChildNodes() {
return getFirstChild() != null;
}
@Override
public final boolean isSameNode(final Node other) {
return this == other;
}
@Override
public BXDoc getOwnerDocument() {
ANode n = node;
for(ANode p; (p = n.parent()) != null;) n = p;
return n.type == NodeType.DOC ? (BXDoc) n.toJava() : null;
}
@Override
public final boolean hasAttributes() {
return getAttributes().getLength() != 0;
}
@Override
public final Object getFeature(final String feature, final String version) {
return null;
}
@Override
public final String getPrefix() {
return null;
}
@Override
public final String getTextContent() {
return string(node.string());
}
@Override
public final BXNode appendChild(final Node newChild) {
readOnly();
return null;
}
@Override
public final Object getUserData(final String key) {
return null;
}
@Override
public final boolean isSupported(final String feature, final String version) {
return false;
}
@Override
public final BXNode insertBefore(final Node newChild, final Node refChild) {
readOnly();
return null;
}
@Override
public final boolean isDefaultNamespace(final String namespaceURI) {
Util.notimplemented();
return false;
}
@Override
public final boolean isEqualNode(final Node cmp) {
Util.notimplemented();
return false;
}
@Override
public final String lookupNamespaceURI(final String prefix) {
Util.notimplemented();
return null;
}
@Override
public final String lookupPrefix(final String namespaceURI) {
Util.notimplemented();
return null;
}
@Override
public final void normalize() {
readOnly();
}
@Override
public final BXNode removeChild(final Node oldChild) {
readOnly();
return null;
}
@Override
public final BXNode replaceChild(final Node newChild, final Node oldChild) {
readOnly();
return null;
}
@Override
public final void setNodeValue(final String nodeValue) {
readOnly();
}
@Override
public final void setPrefix(final String prefix) {
readOnly();
}
@Override
public final void setTextContent(final String textContent) {
readOnly();
}
@Override
public final Object setUserData(final String key, final Object dat,
final UserDataHandler handler) {
readOnly();
return null;
}
@Override
public final String toString() {
return '[' + getNodeName() + ": " + getNodeValue() + ']';
}
/**
* Returns all nodes with the given tag name.
* @param tag tag name
* @return nodes
*/
final BXNList getElements(final String tag) {
final NodeCache nb = new NodeCache();
final AxisIter ai = node.descendant();
final byte[] nm = tag.equals("*") ? null : token(tag);
for(ANode n; (n = ai.next()) != null;) {
if(n.type == NodeType.ELM && (nm == null || eq(nm, n.name())))
nb.add(n.copy());
}
return new BXNList(nb);
}
/**
* Returns a node cache with the specified nodes.
* @param ai axis iterator
* @return node cache
*/
static NodeCache finish(final AxisIter ai) {
final NodeCache nc = new NodeCache();
for(ANode n; (n = ai.next()) != null;) nc.add(n.finish());
return nc;
}
/**
* Returns the XQuery node.
* @return xquery node
*/
public final ANode getNod() {
return node;
}
/**
* Throws a DOM modification exception.
*/
static final void readOnly() {
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
"DOM implementation is read-only.");
}
}