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

import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import jp.co.cybec.cb3.util.DateUtil;
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;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;

/**
 * レコードを表すインタフェースの実装クラス。
 * @author Lijuan Sun
 */
public class JdbcRecord implements DBRecord {

	/** ログ */
	private static final Log LOG = LogFactory.getLog(JdbcRecord.class);

	/** 該当レコードを指すResultSet */
	private ResultSet resultSet = null;

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

	/** SQL */
	private String sql = null;

	/** SQLのパラメータ */
	private DBQueryParameterMap parameter = null;

	/** 行番号 */
	private int row = 0;

	/** レコードのMap */
	HashMap<String, Object> recordMap = null;

	/** String型の値を保持するレコードのMap */
	HashMap<String, String> recordStringMap = null;

	/**
	 *
	 * コンストラクタ
	 *
	 * @param rs 該当レコードを指すResultSet
	 * @param sql ResultSet取得に使用したSQL
	 * @param parameter sqlのパラメータ
	 * @param row 行番号
	 */
	public JdbcRecord(ResultSet rs, String sql, DBQueryParameterMap parameter, int row){

		this.resultSet = rs;
		this.sql = sql;
		this.parameter = parameter;
		this.row = row;
	};

	 /**
	 * 引数「columnName」に該当する値をInteger型で返却します。
	 *
	 * @param columnName 項目名
	 * @return Integer
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public Integer getInteger(String columnName) throws DataAccessException {
		try {
			return new Integer(resultSet.getInt(columnName));
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_021,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_006,
							"Integer",
							sql,
							stringOfParameter,
							stringOfRowIndex,
							columnName),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
	}

	 /**
	 * 引数「columnName」に該当する値をObject型で返却します。
	 *
	 * @param columnName 項目名
	 * @return Object
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public Object getObject(String columnName) throws DataAccessException {
		try {
			return resultSet.getObject(columnName);
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_022,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_006,
							"Object",
							sql,
							stringOfParameter,
							stringOfRowIndex,
							columnName),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
	}

	 /**
	 * 引数「columnName」に該当する値をString型で返却します。
	 *
	 * @param columnName 項目名
	 * @return String
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public String getString(String columnName) throws DataAccessException {
		try {
			return resultSet.getString(columnName);
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_023,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_006,
							"String",
							sql,
							stringOfParameter,
							stringOfRowIndex,
							columnName),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
	}

	 /**
	 * 引数「columnName」に該当する値をBigDecimal型で返却します。
	 *
	 * @param columnName 項目名
	 * @return BigDecimal
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public BigDecimal getBigDecimal(String columnName) throws DataAccessException {
		try {
			return resultSet.getBigDecimal(columnName);
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_024,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_006,
							"BigDecimal",
							sql,
							stringOfParameter,
							stringOfRowIndex,
							columnName),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
	}

	 /**
	 * 引数「columnName」に該当する値をDate型で返却します。
	 *
	 * @param columnName 項目名
	 * @return Date
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public Date getDate(String columnName) throws DataAccessException {
		try {
			return new Date(resultSet.getDate(columnName).getTime());
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_025,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_006,
							"Date",
							sql,
							stringOfParameter,
							stringOfRowIndex,
							columnName),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
	}

	 /**
	 * 引数「columnName」に該当する値をFloat型で返却します。
	 *
	 * @param columnName 項目名
	 * @return Float
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public Float getFloat(String columnName) throws DataAccessException {
		try {
			return new Float(resultSet.getFloat(columnName));
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_026,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_006,
							"Float",
							sql,
							stringOfParameter,
							stringOfRowIndex,
							columnName),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
	}

	 /**
	 * 引数「columnName」に該当する値をLong型で返却します。
	 *
	 * @param columnName 項目名
	 * @return Long
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public Long getLong(String columnName) throws DataAccessException {
		try {
			return new Long(resultSet.getLong(columnName));
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_027,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_006,
							"Long",
							sql,
							stringOfParameter,
							stringOfRowIndex,
							columnName),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
	}

	 /**
	 * 引数「columnName」に該当する値をShort型で返却します。
	 *
	 * @param columnName 項目名
	 * @return Short
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public Short getShort(String columnName) throws DataAccessException {
		try {
			return new Short(resultSet.getShort(columnName));
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_028,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_006,
							"Short",
							sql,
							stringOfParameter,
							stringOfRowIndex,
							columnName),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
	}

	 /**
	 * 引数「columnName」に該当する値をTimestamp型で返却します。
	 *
	 * @param columnName 項目名
	 * @return Timestamp
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public Timestamp getTimestamp(String columnName) throws DataAccessException {
		try {
			return resultSet.getTimestamp(columnName);
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_029,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_006,
							"Timestamp",
							sql,
							stringOfParameter,
							stringOfRowIndex,
							columnName),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
	}

	/**
	 * １レコード分のMap情報を返す。
	 *
	 * @return １レコード分のMap情報
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public Map<String, Object> toMap() throws DataAccessException {

		if (recordMap != null) {
			return recordMap;
		}

		recordMap = new HashMap<String, Object>();

		int columns = 0;
		try {
			columns = resultSet.getMetaData().getColumnCount();

			for (int index = 1; index <= columns; index++) {

				int type = resultSet.getMetaData().getColumnType(index);

				Object value = null;
				switch (type) {
				case java.sql.Types.DATE:
					Date date = resultSet.getDate(index);
					if (date != null) {
						value = new Date(date.getTime());
					}
					break;
				case java.sql.Types.TIMESTAMP:
					value = resultSet.getTimestamp(index);
					break;
				default:
					value = resultSet.getObject(index);
				}

				recordMap.put(resultSet.getMetaData().getColumnName(index), value);
			}
		} catch (SQLException e) {
			// DataAccessExceptionをスローする
			String stringOfParameter = (parameter == null ? "" : parameter.toString());
			String stringOfRowIndex = (row == 0 ? "" : Integer.toString(row));
			DataAccessException ex = new SQLStateSQLExceptionTranslator().translate(
					MESSAGE.getErrorMessage(
							ErrorCodeConstant.ACCESSOR_DBACCESS_020,
							LogMessageConstant.CB3_ACCESSOR_DBACCESS_005,
							sql,
							stringOfParameter,
							stringOfRowIndex),
					"",
					e);
			// infoでログを出力する
			LOG.info(ex.getMessage(), ex);
			// スローする
			throw ex;
		}
		return recordMap;
	}

	/**
	 * １レコード分のMap情報を返す。
	 *
	 * @return １レコード分のMap情報
	 * @throws DataAccessException データ操作時にエラーが発生した場合。
	 */
	public Map<String, String> toMapStringValue() throws DataAccessException {

		if (recordStringMap != null) {
			return recordStringMap;
		}

		recordStringMap = new HashMap<String, String>();
		for (Map.Entry<String, Object> entry : toMap().entrySet()) {
			String value = null;
			Object obj = entry.getValue();
			if (obj != null) {
				if (obj instanceof Timestamp) {
					value = DateUtil.formatTimestamp((Timestamp) obj);
				} else if (obj instanceof Date) {
					value = DateUtil.formatDate((Date) obj);
				} else {
					value = obj.toString();
				}
			}
			recordStringMap.put(entry.getKey(), value);
		}

		return recordStringMap;
	}
}
