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

import java.util.Arrays;
import java.util.Date;

import jp.co.cybec.cb3.exception.DataFormatException;
import jp.co.cybec.cb3.util.DateUtil;
import jp.co.cybec.cb3.util.NumberUtil;
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;

 /**
  * ファイルのレコード項目をフォーマットするクラス(Writer用)。
  * @author Jianming Guo
  */
public class RecordFieldWriterFormat implements RecordFieldWriterFormatable {
	/** ログ */
	private static final Log LOG = LogFactory.getLog(RecordFieldWriterFormat.class);

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

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

	/** 項目名 */
	private String field = null;

	/**
	 * コンストラクタ
	 *
	 * @param filepath 設定ファイルパス
	 * @param field 項目名
	 */
	public RecordFieldWriterFormat(String filepath, String field){
		this.filepath = filepath;
		this.field = field;
	}

	/**
	 * 引数の文字列をフォーマットします。
	 *
	 * @param pattern フォーマット
	 * @param type タイプ
	 * @param data フォーマット対象の文字列
	 * @return フォーマット後の文字列
	 * @throws DataFormatException データ型の変換に失敗したときに発生します。
	 */
	public String format(String pattern, String type, String data) throws DataFormatException {
		String retValue = null;

		// 引数の文字列がNULL or 空白の場合
		if (data == null || data.trim().length() == 0) {
			return data;
		}

		// パターンが未指定の場合
		if (pattern == null || pattern.length() == 0) {
			return data;
		}

		// タイプが未指定 or タイプが正しくない場合
		if (type == null || (!type.equalsIgnoreCase(RecordFieldConstants.TYPE_NUMBER)
				&& !type.equalsIgnoreCase(RecordFieldConstants.TYPE_DATE))) {
			String messageId = LogMessageConstant.CB3_ACCESSOR_FILEACCESS_008;
			DataFormatException ex = new DataFormatException(MESSAGE.getErrorMessage(
					ErrorCodeConstant.ACCESSOR_FILEACCESS_005, messageId, this.filepath,
					this.field, type));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		}

		try {
			if (type.equalsIgnoreCase(RecordFieldConstants.TYPE_NUMBER)) {
			// タイプ：数字の場合
				retValue = NumberUtil.formatNumber(pattern, data);

			} else {
			// タイプ：日付の場合
				// 文字列(デフォールトフォーマット)→Dateに変換
				Date date = DateUtil.parseDate(data);
				// Date→文字列に変換
				retValue = DateUtil.formatDate(date, pattern);
			}
		} catch (Exception e) {
			String messageId = LogMessageConstant.CB3_ACCESSOR_FILEACCESS_007;
			DataFormatException ex = new DataFormatException(MESSAGE
					.getErrorMessage(ErrorCodeConstant.ACCESSOR_FILEACCESS_006, messageId,
							this.field, data, pattern));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		}

		return retValue;

	}

	/**
	 * 引数の文字列をパディングします。
	 *
	 * @param length  バイト数
	 * @param algin   アラインメント指定子(右寄せ・左寄せ)
	 * @param padding パディング文字
	 * @param data パディング対象の文字列
	 * @return パディング後の文字列
	 * @throws DataFormatException 引数に指定された値のフォーマットに間違いがある場合に発生します。
	 */
	public String padding(String length, String algin, String padding, String data) throws DataFormatException {
		int iLength;

		if(data == null){
			data = new String();
		}

		// どちらか未設定の場合
		if ((length == null || length.trim().length() == 0) ||
				(algin == null || algin.trim().length() == 0) ||
				(padding == null || padding.length() == 0)) {
			return data;
		}

		// アラインメント指定子(右寄せ・左寄せ)のチェック
		if (!algin.equalsIgnoreCase(RecordFieldConstants.ALGIN_LEFT)
				&& !algin.equalsIgnoreCase(RecordFieldConstants.ALGIN_RIGHT)) {
			DataFormatException ex = new DataFormatException(MESSAGE.getErrorMessage(
					ErrorCodeConstant.ACCESSOR_FILEACCESS_007,
					LogMessageConstant.CB3_ACCESSOR_FILEACCESS_011, this.filepath, this.field,
					algin));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		}

		// パディング文字のバイト数チェック
		if (padding.getBytes().length > 1) {
			DataFormatException ex = new DataFormatException(MESSAGE.getErrorMessage(
					ErrorCodeConstant.ACCESSOR_FILEACCESS_008,
					LogMessageConstant.CB3_ACCESSOR_FILEACCESS_012, this.filepath, this.field,
					padding));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		}

		try {
			iLength = Integer.parseInt(length);
		} catch (NumberFormatException e) {
			DataFormatException ex = new DataFormatException(MESSAGE.getErrorMessage(
					ErrorCodeConstant.ACCESSOR_FILEACCESS_009,
					LogMessageConstant.CB3_ACCESSOR_FILEACCESS_012, this.filepath, this.field,
					length));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		}

		// データのバイト数をチェック
		if (data.getBytes().length > iLength) {
			DataFormatException ex = new DataFormatException(MESSAGE.getErrorMessage(
					ErrorCodeConstant.ACCESSOR_FILEACCESS_010,
					LogMessageConstant.CB3_ACCESSOR_FILEACCESS_014, data, this.filepath,
					this.field, length));
			LOG.info(ex.getMessage(), ex);
			throw ex;
		}

		// 引数の文字列 → char配列
		char[] dataCharArr = data.toCharArray();
		// 引数の文字列に全角と半角の混在可能性があるため、コピー用のchar配列を作成
		int retCharLength = iLength - (data.getBytes().length - dataCharArr.length);
		char[] retCharArr = new char[retCharLength];
		Arrays.fill(retCharArr, padding.charAt(0));

		if (algin.equalsIgnoreCase(RecordFieldConstants.ALGIN_LEFT)) {
		// 左寄せの場合
			System.arraycopy(dataCharArr, 0, retCharArr, 0, dataCharArr.length);
		} else {
		// 右寄せの場合
			System.arraycopy(dataCharArr, 0, retCharArr, retCharArr.length - dataCharArr.length, dataCharArr.length);
		}

		return String.valueOf(retCharArr);
	}

}
