package blanco.html.normalizer.util;

import java.util.ArrayList;
import java.util.List;

import blanco.html.normalizer.parser.valueobject.BlancoHtmlEvent;
import blanco.html.normalizer.parser.valueobject.BlancoHtmlEventCharacters;
import blanco.html.normalizer.parser.valueobject.BlancoHtmlEventComments;
import blanco.html.normalizer.parser.valueobject.BlancoHtmlEventEndDocument;
import blanco.html.normalizer.parser.valueobject.BlancoHtmlEventEndElement;
import blanco.html.normalizer.parser.valueobject.BlancoHtmlEventStartDocument;
import blanco.html.normalizer.parser.valueobject.BlancoHtmlEventStartElement;
import blanco.html.normalizer.spec.BlancoHtmlElementSpecUtil;
import blanco.html.normalizer.spec.stringgroup.BlancoHtmlElementSpecTypeStringGroup;
import blanco.html.normalizer.spec.valueobject.BlancoHtmlElementSpec;

public class BlancoHtmlNormalizerUtil {
    /**
     * 要素リストを調整。
     * 
     * タグのペアをチェック。補完。 deapth調整の実施。
     * 
     * @param eventList
     */
    public static final List<BlancoHtmlEvent> adjust(
            final List<BlancoHtmlEvent> argOriginalEventList) {
        final List<BlancoHtmlEvent> eventList = new ArrayList<BlancoHtmlEvent>();
        for (BlancoHtmlEvent event : argOriginalEventList) {
            eventList.add(event);
        }

        int deapth = -1;

        for (BlancoHtmlEvent look : eventList) {
            if (look instanceof BlancoHtmlEventStartDocument) {
                final BlancoHtmlEventStartDocument event = (BlancoHtmlEventStartDocument) look;
                event.setDeapth(deapth);
            } else if (look instanceof BlancoHtmlEventEndDocument) {
                final BlancoHtmlEventEndDocument event = (BlancoHtmlEventEndDocument) look;
                event.setDeapth(deapth);
            } else if (look instanceof BlancoHtmlEventStartElement) {
                // 事前処理。
                // TODO ネストできない開始タグが開きっぱなしになっていないかどうかチェック。
                // 開きっぱなしだったら、まず先に閉じます。

                // 真っ先に増やします。
                deapth++;

                final BlancoHtmlEventStartElement event = (BlancoHtmlEventStartElement) look;
                event.setDeapth(deapth);

                if (event.getName().startsWith("!")
                        || event.getName().startsWith("?")) {
                    // !DOCTYPE などに相当と判断。
                    deapth--;
                } else {
                    final List<BlancoHtmlElementSpec> specs = BlancoHtmlElementSpecUtil
                            .getSpecListInstance();
                    for (BlancoHtmlElementSpec spec : specs) {
                        if (event.getName().toUpperCase().equals(
                                spec.getName().toUpperCase())) {
                            if (spec.getEmpty() == BlancoHtmlElementSpecTypeStringGroup.EMPTY) {
                                // 空タグについては、有無をいわさず減らします。
                                // ポイント: これと対にになる処理として、禁止タグは削除フラグを立てます。
                                deapth--;
                            }
                        }
                    }
                }
            } else if (look instanceof BlancoHtmlEventEndElement) {

                // TODO このタグより先に閉じなくてはならない終了タグが無いかどうか事前チェック。
                // 対になっていないタグがあれば閉じなくてはならない。

                // TODO 対応付く開始タグがあるかどうかサーチ。無ければ、そもそもこのタグ、存在してはならないのかも。

                final BlancoHtmlEventEndElement event = (BlancoHtmlEventEndElement) look;
                event.setDeapth(deapth);

                final List<BlancoHtmlElementSpec> specs = BlancoHtmlElementSpecUtil
                        .getSpecListInstance();
                for (BlancoHtmlElementSpec spec : specs) {
                    if (event.getName().toUpperCase().equals(
                            spec.getName().toUpperCase())) {
                        if (spec.getEndTag() == BlancoHtmlElementSpecTypeStringGroup.FORBIDDEN) {
                            // これは存在してはならない終了タグです。
                            // 除去フラグをセットします。
                            event.setIsRemoved(true);
                        }
                    }
                }

                if (event.getIsRemoved()) {
                    // 除去されて、すでに存在しないタグなので、深さ計算には関係ありません。
                } else {
                    // 一番最後に減らします。
                    deapth--;
                }
            } else if (look instanceof BlancoHtmlEventCharacters) {
                final BlancoHtmlEventCharacters event = (BlancoHtmlEventCharacters) look;
                event.setDeapth(deapth);
            } else if (look instanceof BlancoHtmlEventComments) {
                final BlancoHtmlEventComments event = (BlancoHtmlEventComments) look;
                event.setDeapth(deapth);
            }
        }

        return eventList;
    }
}
