/*
 * This code is generated by blanco Framework.
 * ファイル定義書(固定長)から作成されたリーダクラス<br>
 */
package blanco.sample.fixedlength.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import blanco.sample.fixedlength.record.SampleFixedLengthFixedLengthRecord;
import blanco.sample.fixedlength.util.BlancoFixedLengthRuntimeUtil;

/**
 * ファイル定義[SAMPLE_FIXED_LENGTH/固定長ファイルのサンプル。このクラスは単にサンプルです。実際の動作には利用されません。]のリーダクラス<br>
 * このクラスはファイル定義書(固定長)から自動生成されたリーダクラスです。<br>
 * 　1.文字列長チェックには、[Windows-31J]エンコーディングを利用します。<br>
 * 　2.クラスの利用した後は必ず close()を呼び出してください。<br>
 */
public class SampleFixedLengthFixedLengthReader {
    /**
     * リーダオブジェクト<br>
     * 内部的に実際に入力を行うのリーダを記憶します。
     */
    private BufferedReader fReader;

    /**
     * 処理中の行カウンタ<br>
     * 現在処理を行っている行の位置を記憶します。
     */
    private long fLineCounter = 0;

    /**
     * 項目[field_5]の読み込みの際に利用するフォーマッター<br>
     * ※インスタンス化しておくことによりメモリゴミ発生を抑制します。
     */
    private SimpleDateFormat fSimpleDateFormatField5;

    /**
     * 固定長ファイルリーダクラスのコンストラクタ<br>
     * 与えられたリーダと連結します。
     *
     * @param arg 連結するリーダ
     */
    public SampleFixedLengthFixedLengthReader(final BufferedReader arg) {
        fReader = arg;
        fSimpleDateFormatField5 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        // 日付/時刻解析を厳密におこないます。
        fSimpleDateFormatField5.setLenient(false);
    }

    /**
     * 次の一行を読み込みます<br>
     *
     * @return 行オブジェクトを返します。もはや行が無い場合には nullを返します。
     * @throws BlancoFixedLengthIOException 入力データが不正な場合など。
     * @throws IOException 連結先リーダで異常が発生した場合。
     */
    public SampleFixedLengthFixedLengthRecord readRecord() throws BlancoFixedLengthIOException, IOException {
        final String line = fReader.readLine();
        if (line == null) {
            // ファイルの終端に到達しました。
            return null;
        }
        fLineCounter++;
        final SampleFixedLengthFixedLengthRecord record = new SampleFixedLengthFixedLengthRecord();
        final StringReader reader = new StringReader(line);
        String tokenString = null;

        // 項目番号[1]項目名[field_1/フィールド1]
        tokenString = BlancoFixedLengthRuntimeUtil.readToken(reader, 10, "Windows-31J");
        if (tokenString.getBytes("Windows-31J").length < 10) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 1項目目。項目番号[1] 項目名[field_1/フィールド1]の処理中において長さ(10)よりも短い値[" + tokenString + "]を検知しました。");
        }
        if (tokenString.getBytes("Windows-31J").length > 10) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 1項目目。項目番号[1] 項目名[field_1/フィールド1]の処理中において長さ(10)よりも長い値[" + tokenString + "]を検知しました。");
        }
        record.setField1(tokenString);

        // 項目番号[2]項目名[field_2/フィールド2]
        tokenString = BlancoFixedLengthRuntimeUtil.readToken(reader, 9, "Windows-31J");
        if (tokenString.getBytes("Windows-31J").length < 9) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 2項目目。項目番号[2] 項目名[field_2/フィールド2]の処理中において長さ(9)よりも短い値[" + tokenString + "]を検知しました。");
        }
        if (tokenString.getBytes("Windows-31J").length > 9) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 2項目目。項目番号[2] 項目名[field_2/フィールド2]の処理中において長さ(9)よりも長い値[" + tokenString + "]を検知しました。");
        }
        try {
            record.setField2(Integer.parseInt(tokenString.trim()));
        } catch (NumberFormatException ex) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 2項目目。項目番号[2] 項目名[field_2/フィールド2]の処理中において数値(int)としては解析できない文字[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
        }

        // 項目番号[3]項目名[field_3/フィールド3]
        tokenString = BlancoFixedLengthRuntimeUtil.readToken(reader, 10, "Windows-31J");
        if (tokenString.getBytes("Windows-31J").length < 10) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 3項目目。項目番号[3] 項目名[field_3/フィールド3]の処理中において長さ(10)よりも短い値[" + tokenString + "]を検知しました。");
        }
        if (tokenString.getBytes("Windows-31J").length > 10) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 3項目目。項目番号[3] 項目名[field_3/フィールド3]の処理中において長さ(10)よりも長い値[" + tokenString + "]を検知しました。");
        }
        try {
            record.setField3(Long.parseLong(tokenString.trim()));
        } catch (NumberFormatException ex) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 3項目目。項目番号[3] 項目名[field_3/フィールド3]の処理中において数値(long)としては解析できない文字[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
        }

        // 項目番号[4]項目名[field_4/フィールド4]
        tokenString = BlancoFixedLengthRuntimeUtil.readToken(reader, 7, "Windows-31J");
        if (tokenString.getBytes("Windows-31J").length < 7) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 4項目目。項目番号[4] 項目名[field_4/フィールド4]の処理中において長さ(7)よりも短い値[" + tokenString + "]を検知しました。");
        }
        if (tokenString.getBytes("Windows-31J").length > 7) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 4項目目。項目番号[4] 項目名[field_4/フィールド4]の処理中において長さ(7)よりも長い値[" + tokenString + "]を検知しました。");
        }
        try {
            record.setField4(new BigDecimal(tokenString.trim()));
        } catch (NumberFormatException ex) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 4項目目。項目番号[4] 項目名[field_4/フィールド4]の処理中において数値(decimal)としては解析できない文字[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
        }

        // 項目番号[5]項目名[field_5/フィールド5]
        tokenString = BlancoFixedLengthRuntimeUtil.readToken(reader, 19, "Windows-31J");
        if (tokenString.getBytes("Windows-31J").length < 19) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 5項目目。項目番号[5] 項目名[field_5/フィールド5]の処理中において長さ(19)よりも短い値[" + tokenString + "]を検知しました。");
        }
        if (tokenString.getBytes("Windows-31J").length > 19) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 5項目目。項目番号[5] 項目名[field_5/フィールド5]の処理中において長さ(19)よりも長い値[" + tokenString + "]を検知しました。");
        }
        try {
            record.setField5(fSimpleDateFormatField5.parse(tokenString));
        } catch (ParseException ex) {
            throw new BlancoFixedLengthIOException("入力" + fLineCounter + "行目 5項目目。項目番号[5] 項目名[field_5/フィールド5]の処理中において与えられた形式[" + fSimpleDateFormatField5.toPattern() + "]では解析できない文字列[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
        }

        if (reader.read() >= 0) {
            throw new BlancoFixedLengthIOException("全ての列の固定長データを超えるデータが行に存在することを検知しました。");
        }
        return record;
    }

    /**
     * 現在処理中の行カウンタを返します。
     *
     * @return 現在処理中の行カウンタ。
     */
    public long getLineCounter() {
        return fLineCounter;
    }

    /**
     * このリーダを閉じます。<br>
     * 関連づけられていたリーダに対してもclose()を呼び出します。
     *
     * @throws IOException 関連づけられていたリーダのclose()に失敗した場合。
     */
    public void close() throws IOException {
        fReader.close();
    }
}
