/*
 * $Id: TemplateUtil.java,v 1.5 2005/11/03 14:33:48 sugimotokenichi Exp $
 * Copyright (C) 2005 SUGIMOTO Ken-ichi
 * 作成日： 2005/07/28
 */
package feat.v1.impl.template;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import feat.v1.FeatRuntimeException;
import feat.v1.template.CompositeNode;
import feat.v1.template.HTMLNode;
import feat.v1.template.HTMLNodeList;
import feat.v1.template.NodeListIterator;
import feat.v1.template.NodeNotFoundException;


/**
 * テンプレート実装のためのユーティリティ。
 * @author SUGIMOTO
 */
public class TemplateUtil {

    /**
     * start以降の兄弟ノードをコピーする。ノードはすべて深いコピーが作られる。
     * @param start コピーする先頭のノード
     * @param parent コピー先のノード
     * @return コピーされたノード。startがnullのときはnullを返す。
     */
    public static HTMLNode copyNodeList(HTMLNodeImpl start, HTMLNode parent) {
        HTMLNode ret = null;
        HTMLNodeImpl prev = null;
        for(HTMLNodeImpl cur=start; cur != null; cur=cur.next) {
            HTMLNodeImpl cp = (HTMLNodeImpl)cur.copy(true);
            if ( ret == null ) {
                ret = cp;
            }
            if ( prev != null ) {
                prev.setNext(cp);
            }
            cp.setPrev(prev);
            cp.setParent(parent);

            prev = cp;
        }
        return ret;
    }

    public static StringBuffer nodeListToHTML(HTMLNode start, StringBuffer buf) {
        for(HTMLNode node=start; node != null; node=((HTMLNodeImpl)node).next) {
            node.toHTML(buf);
        }
        return buf;
    }

    /**
     * nodeとそれ以降の兄弟ノードをツリーから切り離す。
     * @param node nullのときは何もしない
     * @return 削除したノード。リスト構造は保たれるが親ノードへの参照はなくなっている
     */
    public static HTMLNode detachAll(HTMLNode node) {
        if ( node == null )
            return null;

        // 前のノードとの参照を切る
        try {
            HTMLNodeImpl prev = (HTMLNodeImpl)(node.getPrev());
            prev.setNext(null);
        }
        catch (NodeNotFoundException ex) {
        }

        // 親ノードからの参照を切る
        try {
            HTMLNodeImpl parent = (HTMLNodeImpl)(node.getParent());
            if ( parent.getFirstChild() == node ) {
                parent.setFirstChild(null);
            }
        }
        catch (NodeNotFoundException ex1) {
        }

        // 親ノードへの参照を切る
        TemplateUtil.setParentAll((HTMLNodeImpl)node, null, null);

        return node;
    }

    /**
     * nodeとそれ以降の兄弟ノードをdestの子ノードに追加する。
     * nodeまたはdestがnullの場合は何もしない。
     * @param node
     * @param dest
     */
    public static void moveAll(HTMLNode node, HTMLNode dest) {
        if ( node == null || dest == null )
            return;
        detachAll(node);
        if ( dest instanceof CompositeNode ) {
            ((HTMLCompositeNodeImpl)dest).addChild(node);
        }
    }

    /**
     * startからendまでのノードの親ノードをnewParentに設定する。
     * @param start リストの最初のノード。nullのときは何もしない。
     * @param end リストの最後のノード。nullを指定するとstart以降のすべてのノードが対象になる
     * @param newParent
     */
    public static void setParentAll(HTMLNodeImpl start, HTMLNode end, HTMLNode newParent) {
        NodeListIterator it = new NodeListIterator(start);
        while( it.hasNext() ) {
            HTMLNodeImpl n = (HTMLNodeImpl)it.next();
            n.setParent(newParent);
            if ( n == end ) {
                break;
            }
        }
    }

    /**
     * nodeをDOMのNodeに変換する。
     * @param node 変換するノードまたはnull
     * @return nodeが変換できないかnullならnullを返す
     */
    public static Node toDomNode(HTMLNode node) {
        if ( node == null )
            return null;
        else if ( node instanceof HTMLNodeImpl )
            return ((HTMLNodeImpl)node).getDomNode();
        else
            throw new FeatRuntimeException("HTMLNodeがDOMインタフェースを持っていない");
    }

    public static NodeList toDomNodeList(HTMLNodeList list) {
        if ( list instanceof NodeList ) {
            return (NodeList)list;
        }
        else {
            return null;
        }

    }
}
