/*
 * blanco Framework
 * Copyright (C) 2004-2007 IGA Tosiki
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */
package blanco.text.converter;

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;

/**
 * 「ソーステキスト」をパースします。
 */
public abstract class BlancoTextConverterSrcTxtCmd {
    public final void execute(final Reader reader, final Writer writer)
            throws IOException {
        int startCounter = 0;
        for (;;) {
            final int iRead = reader.read();
            if (iRead < 0) {
                break;
            }

            if (iRead == '[') {
                startCounter++;
                if (startCounter >= 2) {
                    // コマンド開始。
                    startCounter = 0;
                    parseCommand(reader, writer);
                } else {
                    // 何もしない。
                }
            } else {
                if (startCounter > 0) {
                    // ためていたら、これを放出。
                    for (; startCounter > 0; startCounter--) {
                        writer.write('[');
                    }
                }

                writer.write(iRead);
            }
        }
    }

    /**
     * [[でコマンドが開始されたと判断するとここに入ってきます。
     * 
     * @param reader
     * @param writer
     * @throws IOException
     */
    private void parseCommand(final Reader reader, final Writer writer)
            throws IOException {
        final StringBuffer strbuf = new StringBuffer();
        int endCounter = 0;
        for (;;) {
            final int iRead = reader.read();
            if (iRead < 0) {
                break;
            }

            if (iRead == ']') {
                endCounter++;
                if (endCounter >= 2) {
                    // コマンド終了。
                    break;
                } else {
                    // 何もしない。
                }
            } else {
                if (endCounter > 0) {
                    // ためていたら、これを放出。
                    for (; endCounter > 0; endCounter--) {
                        strbuf.append(']');
                    }
                }
                strbuf.append((char) iRead);
            }
        }

        if (processCommand(strbuf, writer)) {
            // 処理したので後続処理は不要。
        } else {
            // 覚えていた文字列を書き戻します。
            writer.write("[[");
            writer.write(strbuf.toString());
            writer.write("]]");
        }
    }

    /**
     * 具体的な処理。
     * 
     * @param strbuf
     * @param writer
     * @return このコマンドを処理したらtrue。処理しなかったらfalse。
     * @throws IOException
     */
    abstract boolean processCommand(final StringBuffer strbuf,
            final Writer writer) throws IOException;
}
