/*
 * FlatFileRecordWriterImpl.java
 * Copyright (C) 2008 Cyber Beans Corporation. All rights reserved.
 */
package jp.co.cybec.cb3.accessor.fileaccess.flat;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Map;

import jp.co.cybec.cb3.accessor.AccessorsLifeCycle;
import jp.co.cybec.cb3.accessor.fileaccess.RecordFieldConstants;
import jp.co.cybec.cb3.exception.AccessorAlreadyOpenedException;
import jp.co.cybec.cb3.exception.AccessorNotOpenException;
import jp.co.cybec.cb3.exception.DataFileIOException;
import jp.co.cybec.cb3.exception.DataFileNotFoundException;
import jp.co.cybec.cb3.exception.DataFormatException;
import jp.co.cybec.cb3.util.logging.ErrorCodeConstant;
import jp.co.cybec.cb3.util.logging.LogMessageConstant;
import jp.co.cybec.cb3.util.logging.LogMessageFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * ファイルのレコード書き込みクラス。
 * @author Jianming Guo
 */
public class FlatFileRecordWriterImpl implements FlatFileRecordWriter, AccessorsLifeCycle {
	/** ログ */
	private static final Log LOG = LogFactory.getLog(FlatFileRecordWriterImpl.class);

	/** メッセージ */
	private static final LogMessageFactory MESSAGE = new LogMessageFactory(
			LogMessageConstant.CB3_MESSAGE_FILENAME);

	/** ファイルパス */
	private String filepath = null;

	/** バッファーライター */
	private BufferedWriter writer = null;

	/** エンコード */
	private String encode = null;

	/** ファイルオープンモード */
	private boolean append = false;

	/** ファイルのオープン状態を保持するフラグ */
	private boolean isOpen = false;

	/**
	 * ファイルをオープンします。
	 *
	 * @throws AccessorAlreadyOpenedException ファイルがすでにオープンされている場合に発生します。
	 * @throws DataFileNotFoundException ファイルが存在しない場合に発生します。
	 * @throws DataFileIOException IOエラーの場合に発生します。
	 */
	public void open() throws AccessorAlreadyOpenedException, DataFileNotFoundException, DataFileIOException {
		// すでにopenされている場合、例外をスローします。
		if (isOpen) {
			AccessorAlreadyOpenedException ex = new AccessorAlreadyOpenedException(MESSAGE
					.getErrorMessage(ErrorCodeConstant.ACCESSOR_FILEACCESS_FLAT_012,
							LogMessageConstant.CB3_ACCESSOR_FILEACCESS_002, filepath));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		}

		// ファイルパスが設定されていない場合は例外をスローします。
		if (filepath == null || filepath.length() == 0) {
			DataFileNotFoundException ex = new DataFileNotFoundException(MESSAGE.getErrorMessage(
					ErrorCodeConstant.ACCESSOR_FILEACCESS_FLAT_017,
					LogMessageConstant.CB3_ACCESSOR_FILEACCESS_018));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		}

		try {
			// バッファーライターを作成
			writer = new BufferedWriter(new OutputStreamWriter(
					new FileOutputStream(new File(filepath), append), encode));
			isOpen = true;
		} catch (FileNotFoundException e) {
			DataFileNotFoundException ex = new DataFileNotFoundException(MESSAGE.getErrorMessage(
					ErrorCodeConstant.ACCESSOR_FILEACCESS_FLAT_013,
					LogMessageConstant.CB3_ACCESSOR_FILEACCESS_003, e));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		} catch (IOException e) {
			DataFileIOException ex = new DataFileIOException(MESSAGE.getErrorMessage(
					ErrorCodeConstant.ACCESSOR_FILEACCESS_FLAT_014,
					LogMessageConstant.CB3_ACCESSOR_FILEACCESS_004, e));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		}
	}

	/**
	 * ファイルをオープンします。
	 *
	 * @param filepath データファイルのパス
	 * @throws AccessorAlreadyOpenedException ファイルがすでにオープンされている場合に発生します。
	 * @throws DataFileNotFoundException ファイルが存在しない場合に発生します。
	 * @throws DataFileIOException IOエラーの場合に発生します。
	 */
	public void open(String filepath) throws AccessorAlreadyOpenedException,
			DataFileNotFoundException, DataFileIOException {
		this.filepath = filepath;
		open();
	}

	/**
	 * ファイルに１行のレコードを書き込みます。
	 *
	 * @param record 1行のレコード
	 * @throws AccessorNotOpenException ファイルがオープンされていない場合に発生します。
	 * @throws DataFileIOException レコードの書き込み時のIOエラーにより発生します。
	 * @throws DataFormatException レコード項目のフォーマットに失敗した場合に発生します。
	 */
	public void write(FlatFileRecord record) throws AccessorNotOpenException, DataFileIOException, DataFormatException {
		// 子クラスで実装
	}

	/**
	 * FlatFileRecordデータを作成します。
	 *
	 * @param record データマップ
	 * @return 作成したFlatFileRecordデータ
	 */
	public FlatFileRecord createFlatFileRecord(Map<String, String> record) {
		// 子クラスで実装

		return null;
	}

	/**
	 * ファイルをクローズします。
	 *
	 * @throws DataFileIOException ファイルのクローズに失敗した場合に発生します。
	 */
	public void close() throws DataFileIOException {
		if (isOpen) {
			try {
				writer.close();
				writer = null;
				isOpen = false;
			} catch (IOException e) {
				DataFileIOException ex = new DataFileIOException(MESSAGE.getErrorMessage(
						ErrorCodeConstant.ACCESSOR_FILEACCESS_FLAT_015,
						LogMessageConstant.CB3_ACCESSOR_FILEACCESS_004, e));
				LOG.info(ex.getMessage(), ex);
				throw ex;
			}
		}
	}

	/**
	 * 設定ファイルを読み込む。
	 *
	 * @param key 設定ファイル名
	 */
	public void initialize(String key) {
		// 子クラスで実装
	}

	/**
	 * 後処理する。
	 */
	public void release() {
		close();
	}

	/**
	 * ファイルパスを返します。
	 *
	 * @return ファイルパス
	 */
	protected String getFilepath() {
		return filepath;
	}

	/**
	 * ファイルパスを設定します。
	 *
	 * @param filepath ファイルパス
	 */
	protected void setFilepath(String filepath) {
		this.filepath = filepath;
	}

	/**
	 * バッファーライターを返します。
	 *
	 * @return バッファーライター
	 */
	protected BufferedWriter getBufferedWriter() {
		return writer;
	}

	/**
	 * ファイルのオープン状態を返します。
	 *
	 * @return ファイルのオープン状態
	 */
	protected boolean isOpen() {
		return this.isOpen;
	}

	/**
	 * ファイルオープンモードを返します。
	 *
	 * @return ファイルオープンモード
	 */
	protected boolean getAppend() {
		return append;
	}

	/**
	 * ファイルオープンモードを設定します。
	 *
	 * @param append ファイルオープンモード
	 */
	protected void setAppend(String append) {
		if (append.equalsIgnoreCase(RecordFieldConstants.FILE_OPEN_APPEND_TRUE)) {
			this.append = true;
		} else {
			this.append = false;
		}
	}

	/**
	 * エンコードを返します。
	 *
	 * @return エンコード
	 */
	protected String getEncode() {
		return encode;
	}

	/**
	 * エンコードを設定します。
	 *
	 * @param encode エンコード
	 */
	protected void setEncode(String encode) {
		this.encode = encode;
	}
}
