/*
 * このソースコードは blanco Frameworkによって自動生成されています。
 */
package blanco.sample.csv.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.csv.record.BlancoCsvSampleCsvRecord;
import blanco.sample.csv.util.BlancoCsvRuntimeUtil;

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

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

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

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

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

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

        // 項目番号[1]項目名[field_1/フィールド1]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 1項目目。項目番号[1] 項目名[field_1/フィールド1]の処理中において不正な終端を検知しました。");
        }
        // 任意項目。
        if (tokenString.length() == 0) {
            // 必須項目ではない文字列項目に長さ0の値が読み込まれた場合には、読み込み後の値としても長さ0の文字列とします。
            record.setField1(tokenString);
        } else {
            if (tokenString.getBytes().length < 1) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 1項目目。項目番号[1] 項目名[field_1/フィールド1]の処理中においてMIN長さ(1)よりも短い値[" + tokenString + "]を検知しました。");
            }
            if (tokenString.getBytes().length > 10) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 1項目目。項目番号[1] 項目名[field_1/フィールド1]の処理中においてMAX長さ(10)よりも長い値[" + tokenString + "]を検知しました。");
            }
            record.setField1(tokenString);
        }

        // 項目番号[2]項目名[field_2/フィールド2]
        // クオートを考慮した読み込みを行います。
        tokenString = BlancoCsvRuntimeUtil.readTokenWithQuote(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 2項目目。項目番号[2] 項目名[field_2/フィールド2]の処理中において不正な終端を検知しました。");
        }
        // 任意項目。
        if (tokenString.length() == 0) {
            // 必須項目ではない文字列項目に長さ0の値が読み込まれた場合には、読み込み後の値としても長さ0の文字列とします。
            record.setField2(tokenString);
        } else {
            if (tokenString.getBytes().length < 4) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 2項目目。項目番号[2] 項目名[field_2/フィールド2]の処理中においてMIN長さ(4)よりも短い値[" + tokenString + "]を検知しました。");
            }
            if (tokenString.getBytes().length > 4) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 2項目目。項目番号[2] 項目名[field_2/フィールド2]の処理中においてMAX長さ(4)よりも長い値[" + tokenString + "]を検知しました。");
            }
            record.setField2(tokenString);
        }

        // 項目番号[3]項目名[field_3/フィールド3]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 3項目目。項目番号[3] 項目名[field_3/フィールド3]の処理中において不正な終端を検知しました。");
        }
        // 任意項目。
        if (tokenString.length() == 0) {
            // 必須項目ではない項目に長さ0の値が読み込まれた場合には、値としてnullを代入します。
            record.setField3(null);
        } else {
            if (tokenString.getBytes().length < 1) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 3項目目。項目番号[3] 項目名[field_3/フィールド3]の処理中においてMIN長さ(1)よりも短い値[" + tokenString + "]を検知しました。");
            }
            if (tokenString.getBytes().length > 3) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 3項目目。項目番号[3] 項目名[field_3/フィールド3]の処理中においてMAX長さ(3)よりも長い値[" + tokenString + "]を検知しました。");
            }
            try {
                record.setField3(new Integer(tokenString));
            } catch (NumberFormatException ex) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 3項目目。項目番号[3] 項目名[field_3/フィールド3]の処理中において数値(int)としては解析できない文字[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
            }
        }

        // 項目番号[4]項目名[field_4/フィールド4]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 4項目目。項目番号[4] 項目名[field_4/フィールド4]の処理中において不正な終端を検知しました。");
        }
        // 任意項目。
        if (tokenString.length() == 0) {
            // 必須項目ではない項目に長さ0の値が読み込まれた場合には、値としてnullを代入します。
            record.setField4(null);
        } else {
            if (tokenString.getBytes().length < 1) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 4項目目。項目番号[4] 項目名[field_4/フィールド4]の処理中においてMIN長さ(1)よりも短い値[" + tokenString + "]を検知しました。");
            }
            if (tokenString.getBytes().length > 3) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 4項目目。項目番号[4] 項目名[field_4/フィールド4]の処理中においてMAX長さ(3)よりも長い値[" + tokenString + "]を検知しました。");
            }
            try {
                record.setField4(new Long(tokenString));
            } catch (NumberFormatException ex) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 4項目目。項目番号[4] 項目名[field_4/フィールド4]の処理中において数値(long)としては解析できない文字[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
            }
        }

        // 項目番号[5]項目名[field_5/フィールド5]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 5項目目。項目番号[5] 項目名[field_5/フィールド5]の処理中において不正な終端を検知しました。");
        }
        // 任意項目。
        if (tokenString.length() == 0) {
            // 必須項目ではない項目に長さ0の値が読み込まれた場合には、値としてnullを代入します。
            record.setField5(null);
        } else {
            try {
                record.setField5(fSimpleDateFormatField5.parse(tokenString));
            } catch (ParseException ex) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 5項目目。項目番号[5] 項目名[field_5/フィールド5]の処理中において与えられた形式[" + fSimpleDateFormatField5.toPattern() + "]では解析できない文字列[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
            }
        }

        // 項目番号[6]項目名[field_6/フィールド6]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 6項目目。項目番号[6] 項目名[field_6/フィールド6]の処理中において不正な終端を検知しました。");
        }
        // 任意項目。
        if (tokenString.length() == 0) {
            // 必須項目ではない項目に長さ0の値が読み込まれた場合には、値としてnullを代入します。
            record.setField6(null);
        } else {
            if (tokenString.getBytes().length < 1) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 6項目目。項目番号[6] 項目名[field_6/フィールド6]の処理中においてMIN長さ(1)よりも短い値[" + tokenString + "]を検知しました。");
            }
            if (tokenString.getBytes().length > 3) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 6項目目。項目番号[6] 項目名[field_6/フィールド6]の処理中においてMAX長さ(3)よりも長い値[" + tokenString + "]を検知しました。");
            }
            try {
                record.setField6(new BigDecimal(tokenString));
            } catch (NumberFormatException ex) {
                throw new BlancoCsvIOException("入力" + fLineCounter + "行目 6項目目。項目番号[6] 項目名[field_6/フィールド6]の処理中において数値(decimal)としては解析できない文字[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
            }
        }

        // 項目名[field_11/フィールド11]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 7項目目。項目名[field_11/フィールド11]の処理中において不正な終端を検知しました。");
        }
        // 必須項目。
        if (tokenString.length() == 0) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 7項目目。項目名[field_11/フィールド11]の処理中において必須項目に値が入っていないことを検知しました。");
        }
        record.setField11(tokenString);

        // 項目名[field_12/フィールド12]
        // クオートを考慮した読み込みを行います。
        tokenString = BlancoCsvRuntimeUtil.readTokenWithQuote(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 8項目目。項目名[field_12/フィールド12]の処理中において不正な終端を検知しました。");
        }
        // 必須項目。
        if (tokenString.length() == 0) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 8項目目。項目名[field_12/フィールド12]の処理中において必須項目に値が入っていないことを検知しました。");
        }
        record.setField12(tokenString);

        // 項目名[field_13/フィールド13]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 9項目目。項目名[field_13/フィールド13]の処理中において不正な終端を検知しました。");
        }
        // 必須項目。
        if (tokenString.length() == 0) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 9項目目。項目名[field_13/フィールド13]の処理中において必須項目に値が入っていないことを検知しました。");
        }
        try {
            record.setField13(Integer.parseInt(tokenString));
        } catch (NumberFormatException ex) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 9項目目。項目名[field_13/フィールド13]の処理中において数値(int)としては解析できない文字[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
        }

        // 項目名[field_14/フィールド14]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 10項目目。項目名[field_14/フィールド14]の処理中において不正な終端を検知しました。");
        }
        // 必須項目。
        if (tokenString.length() == 0) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 10項目目。項目名[field_14/フィールド14]の処理中において必須項目に値が入っていないことを検知しました。");
        }
        try {
            record.setField14(Long.parseLong(tokenString));
        } catch (NumberFormatException ex) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 10項目目。項目名[field_14/フィールド14]の処理中において数値(long)としては解析できない文字[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
        }

        // 項目名[field_15/フィールド15]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', false);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 11項目目。項目名[field_15/フィールド15]の処理中において不正な終端を検知しました。");
        }
        // 必須項目。
        if (tokenString.length() == 0) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 11項目目。項目名[field_15/フィールド15]の処理中において必須項目に値が入っていないことを検知しました。");
        }
        try {
            record.setField15(fSimpleDateFormatField15.parse(tokenString));
        } catch (ParseException ex) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 11項目目。項目名[field_15/フィールド15]の処理中において与えられた形式[" + fSimpleDateFormatField15.toPattern() + "]では解析できない文字列[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
        }

        // 項目名[field_16/フィールド16]
        tokenString = BlancoCsvRuntimeUtil.readToken(reader, ',', true);
        if (tokenString == null) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 12項目目。項目名[field_16/フィールド16]の処理中において不正な終端を検知しました。");
        }
        // 必須項目。
        if (tokenString.length() == 0) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 12項目目。項目名[field_16/フィールド16]の処理中において必須項目に値が入っていないことを検知しました。");
        }
        try {
            record.setField16(new BigDecimal(tokenString));
        } catch (NumberFormatException ex) {
            throw new BlancoCsvIOException("入力" + fLineCounter + "行目 12項目目。項目名[field_16/フィールド16]の処理中において数値(decimal)としては解析できない文字[" + tokenString + "]を検知しました。:" + ex.toString(), ex);
        }
        return record;
    }

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

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