/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.xml.impl;

import java.util.Map;
import java.util.Objects;
import net.ranides.assira.generic.CompareUtils;
import net.ranides.assira.xml.XMLElement;
import org.w3c.dom.Node;
import se.fishtank.css.selectors.dom.DOMNode;

/**
 * Kopia klasy "W3CNode" z biblioteki css-selectors. 
 * "W3Element" dziedziczy z tej klasy aby uniknąć podwójnego wrapowania "Node" w selektorach CSS.
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public abstract class CElement implements DOMNode<W3Element, Node>, XMLElement {

    protected final Node node;

    public CElement(Node node) {
        this.node = node;
    }

    @Override
    public Node getUnderlying() {
        return node;
    }

    @Override
    public DOMNode.Type getType() {
        switch (node.getNodeType()) {
        case Node.DOCUMENT_NODE:
            return DOMNode.Type.DOCUMENT;
        case Node.ELEMENT_NODE:
            return DOMNode.Type.ELEMENT;
        case Node.TEXT_NODE:
            return DOMNode.Type.TEXT;
        default:
            return DOMNode.Type.OTHER;
        }
    }

    @Override
    public String getData() {
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            return node.getNodeName();
        }
        return node.getNodeValue();
    }

    @Override
    public Map<String, String> getAttributes() {
        return attrs().map();
    }

    @Override
    public W3Element getFirstChild() {
        return wrap(node.getFirstChild());
    }

    @Override
    public W3Element getPreviousSibling() {
        return wrap(node.getPreviousSibling());
    }

    @Override
    public W3Element getNextSibling() {
        return wrap(node.getNextSibling());
    }

    @Override
    public W3Element getParentNode() {
        return wrap(node.getParentNode());
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (other instanceof XMLElement) {
            XMLElement that = (XMLElement) other;
            return CompareUtils.equals(node, that.node());
        }
        return false;
    }

    @Override
    public int hashCode() {
        return Objects.hash(node);
    }

    private W3Element wrap(Node n) {
        return n == null ? null : new W3Element(n);
    }

}
