// $Id: ElementNode.java 96 2005-02-28 21:07:29Z blindsey $

package com.jclark.xsl.dom;

import com.jclark.xsl.om.*;

class ElementNode extends ContainerNode
{
    private Name name;
    private AttributeNode[] attributeNodes = null;

    ElementNode(org.w3c.dom.Node domNode, ContainerNode parent, int childIndex)
    {
        super(domNode, parent, childIndex);
        org.w3c.dom.NamedNodeMap domAttributes = domNode.getAttributes();
        int len = domAttributes.getLength();
        if (len == 0)
            return;
        attributeNodes = new AttributeNode[len];
        int firstPrefixIndex = -1;
        for (int i = 0; i < len; i++) {
            org.w3c.dom.Node domAttribute = domAttributes.item(i);
            String qName = domAttribute.getNodeName();
            switch (qName.indexOf(':')) {
            case -1:
                if (qName.equals("xmlns")) {
                    String uri = domAttribute.getNodeValue();
                    if (uri.length() == 0)
                        prefixMap = prefixMap.unbindDefault();
                    else
                        prefixMap = prefixMap.bindDefault(uri);
                }
                else
                    attributeNodes[i] = new AttributeNode(root.nameTable.createName(domAttribute.getNodeName()),
                                                          domAttribute,
                                                          this,
                                                          // attributes occur before children
                                                          i - len - 1);
                break;
            case 3:
                if (qName.equals("xml:space")) {
                    String value = domAttribute.getNodeValue();
                    if ("preserve".equals(value))
                        preserveSpace = true;
                    else if ("default".equals(value))
                        preserveSpace = false;
                }
                if (firstPrefixIndex < 0)
                    firstPrefixIndex = i;
                break;
            case 5:
                if (qName.startsWith("xmlns")) {
                    prefixMap = prefixMap.bind(qName.substring(6),
                                               domAttribute.getNodeValue());
                    break;
                }
                // fall through
            default:
                if (firstPrefixIndex < 0)
                    firstPrefixIndex = i;
                break;
            }
        }
        if (firstPrefixIndex >= 0) {
            // global attributes are hopefully relatively rare
            for (int i = firstPrefixIndex; i < len; i++) {
                if (attributeNodes[i] == null) {
                    org.w3c.dom.Node domAttribute = domAttributes.item(i);
                    String qName = domAttribute.getNodeName();
                    if (qName.startsWith("xmlns")
                        && (qName.length() == 5 || qName.charAt(5) == ':'))
                        ;
                    else {
                        try {
                            attributeNodes[i]
                                = new AttributeNode(prefixMap.expandAttributeName(domAttribute.getNodeName(),
                                                                                  null),
                                                    domAttribute,
                                                    this,
                                                    // attributes occur before children
                                                    i - len - 1);
                        }
                        catch (XSLException e) { }
                    }
                }
            }
        }
    }


    public byte getType() {
        return ELEMENT;
    }

    public Name getName() {
        if (name == null) {
            String qName = domNode.getNodeName();
            try {
                name = prefixMap.expandElementTypeName(qName, null);
            }
            catch (XSLException e) {
                name = root.nameTable.createName(qName);
            }
        }
        return name;
    }

    public String getAttributeValue(Name name) {
        if (attributeNodes == null)
            return null;
        for (int i = 0; i < attributeNodes.length; i++)
            if (attributeNodes[i] != null && name.equals(attributeNodes[i].name))
                return attributeNodes[i].getData();
        return null;
    }

    public Node getAttribute(Name name) {
        if (attributeNodes == null)
            return null;
        for (int i = 0; i < attributeNodes.length; i++)
            if (attributeNodes[i] != null && name.equals(attributeNodes[i].name))
                return attributeNodes[i];
        return null;
    }

    class AttributesIterator implements SafeNodeIterator {
        int i = 0;
        public Node next() {
            while (i < attributeNodes.length) {
                Node attributeNode = attributeNodes[i++];
                if (attributeNode != null)
                    return attributeNode;
            }
            return null;
        }
    }

    public SafeNodeIterator getAttributes() {
        if (attributeNodes == null)
            return NullNodeIterator.getInstance();
        return new AttributesIterator();
    }

    public boolean getPreserveSpace() {
        return preserveSpace || !root.loadContext.getStripSource(getName());
    }
}
