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

import java.io.BufferedWriter;
import java.io.IOException;
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 SampleFixedLengthFixedLengthWriter {
    /**
     * ライタオブジェクト<br>
     * 内部的に実際に出力を行うのライタを記憶します。
     */
    private BufferedWriter fWriter;

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

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

    /**
     * 固定長ファイルライタクラスのコンストラクタ<br>
     * 与えられたライタと連結します。
     *
     * @param arg 連結するライタ
     */
    public SampleFixedLengthFixedLengthWriter(final BufferedWriter arg) {
        fWriter = arg;
        fSimpleDateFormatField5 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    }

    /**
     * 与えられた一行を書き出します<br>
     * データはデリミタで区切られながらライタに出力され、最後に改行コードが付与されます。
     *
     * @param record レコードオブジェクト
     * @throws BlancoFixedLengthIOException 与えられたレコード中の項目値が不正な場合など。
     * @throws IOException 連結されたライター出力の際に例外が発生した場合。
     */
    public void writeRecord(final SampleFixedLengthFixedLengthRecord record) throws BlancoFixedLengthIOException, IOException {
        String writeToken = null;

        // 項目番号[1] 項目名[field_1/フィールド1]
        // 任意項目で文字列の項目に nullまたは長さ0の文字列が与えられた場合には、いずれも値が入っていないものとみなします。
        // この場合には長さチェックは行いません。
        writeToken = record.getField1() == null ? "" : record.getField1();
        // 指定の長さまでパディングします。
        writeToken = BlancoFixedLengthRuntimeUtil.padRight(writeToken, 10, ' ', "Windows-31J");
        if (writeToken.getBytes("Windows-31J").length < 10) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 1項目目。項目番号[1] 項目名[field_1/フィールド1]の処理中において長さ(10)よりも短い値[" + writeToken + "]を検知しました。");
        }
        if (writeToken.getBytes("Windows-31J").length > 10) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 1項目目。項目番号[1] 項目名[field_1/フィールド1]の処理中において長さ(10)よりも長い値[" + writeToken + "]を検知しました。");
        }
        fWriter.write(writeToken);

        // 項目番号[2] 項目名[field_2/フィールド2]
        writeToken = String.valueOf(record.getField2());
        // 指定の長さまでパディングします。
        writeToken = BlancoFixedLengthRuntimeUtil.padLeft(writeToken, 9, ' ', "Windows-31J");
        if (writeToken.getBytes("Windows-31J").length < 9) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 2項目目。項目番号[2] 項目名[field_2/フィールド2]の処理中において長さ(9)よりも短い値[" + writeToken + "]を検知しました。");
        }
        if (writeToken.getBytes("Windows-31J").length > 9) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 2項目目。項目番号[2] 項目名[field_2/フィールド2]の処理中において長さ(9)よりも長い値[" + writeToken + "]を検知しました。");
        }
        fWriter.write(writeToken);

        // 項目番号[3] 項目名[field_3/フィールド3]
        writeToken = String.valueOf(record.getField3());
        // 指定の長さまでパディングします。
        writeToken = BlancoFixedLengthRuntimeUtil.padLeft(writeToken, 10, ' ', "Windows-31J");
        if (writeToken.getBytes("Windows-31J").length < 10) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 3項目目。項目番号[3] 項目名[field_3/フィールド3]の処理中において長さ(10)よりも短い値[" + writeToken + "]を検知しました。");
        }
        if (writeToken.getBytes("Windows-31J").length > 10) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 3項目目。項目番号[3] 項目名[field_3/フィールド3]の処理中において長さ(10)よりも長い値[" + writeToken + "]を検知しました。");
        }
        fWriter.write(writeToken);

        // 項目番号[4] 項目名[field_4/フィールド4]
        writeToken = record.getField4() == null ? "" : record.getField4().toString();
        // 指定の長さまでパディングします。
        writeToken = BlancoFixedLengthRuntimeUtil.padLeft(writeToken, 7, ' ', "Windows-31J");
        if (writeToken.getBytes("Windows-31J").length < 7) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 4項目目。項目番号[4] 項目名[field_4/フィールド4]の処理中において長さ(7)よりも短い値[" + writeToken + "]を検知しました。");
        }
        if (writeToken.getBytes("Windows-31J").length > 7) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 4項目目。項目番号[4] 項目名[field_4/フィールド4]の処理中において長さ(7)よりも長い値[" + writeToken + "]を検知しました。");
        }
        fWriter.write(writeToken);

        // 項目番号[5] 項目名[field_5/フィールド5]
        if (record.getField5() == null) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 5項目目。項目番号[5] 項目名[field_5/フィールド5]の処理中において項目にnullが与えられていることを検知しました。");
        }
        writeToken = fSimpleDateFormatField5.format(record.getField5());
        // 指定の長さまでパディングします。
        writeToken = BlancoFixedLengthRuntimeUtil.padRight(writeToken, 19, ' ', "Windows-31J");
        if (writeToken.getBytes("Windows-31J").length < 19) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 5項目目。項目番号[5] 項目名[field_5/フィールド5]の処理中において長さ(19)よりも短い値[" + writeToken + "]を検知しました。");
        }
        if (writeToken.getBytes("Windows-31J").length > 19) {
            throw new BlancoFixedLengthIOException("出力" + (fLineCounter + 1) + "行目 5項目目。項目番号[5] 項目名[field_5/フィールド5]の処理中において長さ(19)よりも長い値[" + writeToken + "]を検知しました。");
        }
        fWriter.write(writeToken);

        // 最後に改行コードが付与されます。
        fWriter.newLine();
        fLineCounter++;
    }

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

    /**
     * このライタをフラッシュします。<br>
     * 関連づけられていたライタに対してもflush()を呼び出します。
     *
     * @throws IOException 関連づけられていたライタのflush()に失敗した場合。
     */
    public void flush() throws IOException {
        fWriter.flush();
    }

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