package jp.sourceforge.shovel.io;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class InputStreamReaderExt extends InputStreamReader
{
    String prepend = "<#escape x as x?html>";
    String append = "</#escape>";
    int cursor_ = 0;
    int end_;
    
    public InputStreamReaderExt(InputStream in) {
        super(in);
        cursor_ = 0;
        end_ = 0;
    }
    
    public InputStreamReaderExt(InputStream in, String charsetName)
    throws UnsupportedEncodingException {
        super(in, charsetName);
        cursor_ = 0;
        end_ = 0;
    }
    
    public InputStreamReaderExt(InputStream in, Charset cs) {
        super(in, cs);
        cursor_ = 0;
        end_ = 0;
    }
    
    public InputStreamReaderExt(InputStream in, CharsetDecoder dec) {
        super(in, dec);
        cursor_ = 0;
        end_ = 0;
    }
    
    /**
     * 単一の文字を読み込みます。
     * 
     * @return  読み込まれた文字。ストリームの終わりに達した場合は -1
     * @throws  IOException 入出力エラーが発生した場合
     */
    public int read() throws IOException {
        if (cursor_ < prepend.length()) {
             return prepend.codePointAt(cursor_++);
        }
        int code = super.read();
        if (code >= 0) {
            return code;
        }
        int offset = cursor_ - prepend.length();
        if (offset <= 0) {
            return -1;
        }
        cursor_++;
        return append.codePointAt(offset);
    }

    public int read(char cbuf[], int offset, int length) throws IOException {
        length -= offset;
        StringBuilder builder = new StringBuilder();
        //<#escape x as x?html>
        int end = prepend.length();
        int read = 0;
        if (end > cursor_) {
            if (end > length) {
                end = length;
            }
            builder.append(prepend.substring(0, end));
            read += end;
            if (read == length) {
                builder.getChars(offset, read, cbuf, 0);
                return read;
            }
            cursor_ += end;
        } else {
            end = 0;
        }
        //テンプレートファイルの中身
        end = super.read(cbuf, 0, length - read);
        if (end != -1) {
            builder.append(cbuf, 0, end);
            read += end;
            cursor_ += end;
            if (read == length) {
                builder.getChars(offset, read, cbuf, 0);
                return read;
            }
            end_ = cursor_;
        }
        //</#escape>
        end = append.length();
        int start = cursor_ - end_;
        if (start >= end) {
            return -1;
        }
        builder.append(append.substring(start, end));
        read += end - start;
        if (read > length) {
            end -= read - length;
            read = length;
        }
        builder.getChars(offset, read, cbuf, 0);
        cursor_ += end;
        return read;
/*
        StringBuilder builder = new StringBuilder();
        int len = prepend.length();
        int read = 0;
        //prependのタグは読んだ？
        if (len > cursor_) {
            len -= offset;
            if (len > length) {
                len = length;
            }
            builder.append(prepend.substring(offset, len));
            read += len;
            if (read == length) {
                builder.getChars(0, read, cbuf, 0);
                return read;
            }
            cursor_ += len;
        } else {
            len = 0;
        }
        len = super.read(cbuf, 0, length - read);
        if (len != -1) {
            builder.append(cbuf, 0, len);
            read += len;
            cursor_ += len;
            if (read == length) {
                builder.getChars(0, read, cbuf, 0);
                return read;
            }
            end_ = cursor_;
        }
        len = append.length();
        offset = end_ - cursor_;
        if (offset < 0) {
            return -1;
        }
        len -= offset;
        builder.append(append.substring(offset, len));
        read += len;
        builder.getChars(0, read, cbuf, 0);
        cursor_ += len; 
        return read;
*/
    }
}
