/*
 * $Id: HTMLNodeImpl.java,v 1.1 2006/04/11 16:14:32 sugimotokenichi Exp $
 * Copyright (C) 2005 SUGIMOTO Ken-ichi
 * 作成日: 2005/10/29
 */
package feat2.template.impl;

import org.w3c.dom.Node;

import feat2.template.HTMLDocument;
import feat2.template.HTMLNode;
import feat2.template.NodeNotFoundException;

/**
 * HTMLNodeの実装。
 * @author SUGIMOTO Ken-ichi
 */
abstract public class HTMLNodeImpl implements HTMLNode {

    //private static Log log = LogFactory.getLog(HTMLNodeImpl.class);

    public HTMLNodeImpl parent;
    public HTMLNodeImpl prev;
    public HTMLNodeImpl next;
    private Node domNode;

    abstract public void setFirstChild(HTMLNode child);

    public void setNext(HTMLNode next) {
        this.next = (HTMLNodeImpl)next;
    }

    public void setParent(HTMLNode parent) {
        this.parent = (HTMLNodeImpl)parent;
    }

    public void setPrev(HTMLNode prev) {
        this.prev = (HTMLNodeImpl)prev;
    }

    public void setDomNode(Node n) {
        domNode = n;
    }

    public Node getDomNode() {
        return domNode;
    }

    // HTMLNodeの実装 ------------------------------------------------------------

    public HTMLNode getParent() throws NodeNotFoundException {
        if ( parent == null )
            throw new NodeNotFoundException();
        return parent;
    }

    public HTMLDocument getDocument() throws NodeNotFoundException {
        for(HTMLNode node = this; true; node = node.getParent()) {
            if ( node.getNodeType() == HTMLNode.NODETYPE_DOCUMENT )
                return (HTMLDocument)node;
        }
    }

    abstract public HTMLNode getFirstChild() throws NodeNotFoundException;

    public HTMLNode getNext() throws NodeNotFoundException {
        if ( next == null )
            throw new NodeNotFoundException();
        return next;
    }

    public HTMLNode getPrev() throws NodeNotFoundException {
        if ( prev == null )
            throw new NodeNotFoundException();
        return prev;
    }

    public HTMLNode getFirst() {
        HTMLNode current = this;
        try {
            while(true) {
                current = current.getPrev();
            }
        }
        catch (NodeNotFoundException ex) {
        }
        return current;
    }

    public HTMLNode getLast() {
        HTMLNodeImpl current = this;
        while(current.next != null) {
            current = (HTMLNodeImpl)current.next;
        }
        return current;
    }

    public void insertAfter(HTMLNode node) {
        if ( node == null )
            return;

        // 次のノードとnodeを連結
        HTMLNodeImpl lastNode = (HTMLNodeImpl)node.getLast();
        lastNode.setNext(next);
        if ( next != null )
            ((HTMLNodeImpl)next).setPrev(lastNode);

        // このノードにnodeを連結
        next = (HTMLNodeImpl)node;
        ((HTMLNodeImpl)node).setPrev(this);

        // nodeの親ノードを設定
        TemplateUtil.setParentAll((HTMLNodeImpl)node, lastNode, parent);
    }

    public void insertBefore(HTMLNode node) {
        if ( node == null )
            return;

        // 前のノードとnodeを連結
        if ( prev != null )
            ((HTMLNodeImpl)prev).setNext(node);
        ((HTMLNodeImpl)node).setPrev(prev);

        // nodeの最後のノードに、このノードを連結
        HTMLNodeImpl lastNode = (HTMLNodeImpl)node.getLast();
        lastNode.setNext(this);
        prev = lastNode;

        // 必要ならば親ノードの最初の子ノードを変更する
        try {
            if ( parent != null && parent instanceof HTMLCompositeNodeImpl && parent.getFirstChild() == this ) {
                ((HTMLCompositeNodeImpl)parent).setFirstChild(node);
            }
        }
        catch (NodeNotFoundException ex) {
        }

        // nodeの親ノードを設定
        TemplateUtil.setParentAll((HTMLNodeImpl)node, lastNode, parent);
    }

    public void detach() {
        // 親子の参照を切る
        if ( parent != null ) {
            HTMLNodeImpl parentNode = (HTMLNodeImpl)parent;

            // このノードが最初の子ノードだったら
            // 次の兄弟ノードが最初の子ノードに繰り上がる
            try {
                HTMLNodeImpl childNode = (HTMLNodeImpl)parentNode.getFirstChild();
                if ( childNode == this )
                    parentNode.setFirstChild(next);
            }
            catch (NodeNotFoundException ex) {
            }
            parent = null;
        }

        // 兄弟の参照を切る
        if ( prev != null ) {
            ((HTMLNodeImpl)prev).setNext(next);
        }
        if ( next != null ) {
            ((HTMLNodeImpl)next).setPrev(prev);
        }
        prev = null;
        next = null;
    }


}
