/*********************************************************************
*	All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*	モジュール名	：JTUejbDBABaseForMaster
*	ソースファイル名：JTUejbDBABaseForMaster.java
*	作成者			：FJ
*	日付			：2011年06月14日
*＜機能概要＞
*	データベースアクセス共通部品のスーパークラス
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v3.00.00	2011/06/14	FJ)楠神		新規作成
*
**********************************************************************/

package eo.ejb.common.db;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import com.fujitsu.futurity.common.JCMTraceLog;
import com.fujitsu.futurity.model.base.CAANFinderException;
import com.fujitsu.futurity.model.base.CAANJDBCUtil;
import com.fujitsu.futurity.model.base.CAANLog;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.base.CAANRuntimeException;
import com.fujitsu.futurity.model.ejb.common.fw.TemplateSQLEntity;
import eo.ejb.common.JTUModelCommon;

/**
 * <p>
 * データベースアクセス共通部品のスーパークラスです。<br>
 * 必ず内部スキーマ単位で本クラスを継承したサブクラスを実装して使用してください。
 * </p>
 * @author FJ
 */
public abstract class JTUejbDBABaseForMaster extends TemplateSQLEntity
{
	/** スキーマ名 */
	private String schemaName = null;

	/** スキーマ定義情報 */
	private Object[][] contents = null;

	/** テーブル名 */
	private String tableName = null;

	/** スキーマ定義情報の取得メソッド名 */
	private static final String GET_CONTENTS = "getContents";

	/** スキーマテーブル名の取得メソッド名 */
	private static final String GET_TABLE = "getTableName";

	/**
	 * <p>
	 * 新しいJTUejbDBABaseForMasterを作成します。
	 * </p>
	 */
	public JTUejbDBABaseForMaster()
	{
	}

	/**
	 * <p>
	 * 新しいJTUejbDBABaseForMasterを作成します。
	 * </p>
	 * @param arg0
	 */
	public JTUejbDBABaseForMaster(String arg0)
	{
		super();
		setSchemaInfo(arg0);
	}


	/**
	 * <p>
	 * 世代を管理するエンティティか判定します。
	 * </p>
	 * @return 世代を管理するエンティティの場合はtrue
	 */
	protected abstract boolean isGenerationMgr();

	/**
	 * <p>
	 * 世代を管理するカラム名を取得します。
	 * </p>
	 * @return 世代を管理するカラム名
	 */
	protected abstract String getGenerationColumn();

	/**
	 * <p>
	 * 無効状態を管理するカラム名を取得します。
	 * </p>
	 * @return 無効状態を管理するカラム名
	 */
	protected abstract String getInvalidColumn();

	/**
	 * <p>
	 * 予約を管理するエンティティか判定します。
	 * </p>
	 * @return 予約を管理するエンティティの場合はtrue
	 */
	protected abstract boolean isReserveMgr();

	/**
	 * <p>
	 * 予約適用基準日となるカラム名を取得します。
	 * </p>
	 * @return 予約適用基準日となるカラム名
	 */
	protected abstract String getCurrentColumn();

	/**
	 * <p>
	 * 適用年月日の状態を管理するエンティティか判定します。
	 * </p>
	 * @return 適用年月日の状態を管理するエンティティの場合はtrue
	 */
	protected abstract boolean istymdMgr();

	/**
	 * <p>
	 * 適用開始年月日を管理するカラム名を取得します。
	 * </p>
	 * @return 適用開始年月日を管理するカラム名
	 */
	protected abstract String gettstaymdColumn();

	/**
	 * <p>
	 * 適用終了年月日を管理するカラム名を取得します。
	 * </p>
	 * @return 適用終了年月日を管理するカラム名
	 */
	protected abstract String gettendymdColumn();

	/**
	 * <p>
	 * スキーマ名を取得します。
	 * </p>
	 * @return スキーマ名
	 */
	protected String getSchemaName()
	{
		return this.schemaName;
	}

	/**
	 * <p>
	 * スキーマの定義情報を取得します。
	 * </p>
	 * @return スキーマの定義情報
	 */
	protected Object[][] getSchemaContents()
	{
		return this.contents;
	}

	/**
	 * <p>
	 * スキーマのテーブル名を取得します。
	 * </p>
	 * @return スキーマのテーブル名
	 */
	protected String getTableName()
	{
		return this.tableName;
	}

	/**
	 * <p>
	 * スキーマ情報を設定します。
	 * パラメータのスキーマ名から対象スキーマの定義情報、テーブル名を設定します。
	 * </p>
	 * @param arg0 スキーマ名
	 */
	private void setSchemaInfo(String arg0)
	{
		this.schemaName = arg0;
		setSchemaContents();
		setTableName();
	}

	/**
	 * <p>
	 * スキーマの定義情報を設定します。
	 * </p>
	 */
	private void setSchemaContents()
	{
		try
		{
			Class<?> cls = Class.forName(this.schemaName);
			Object instance = cls.newInstance();
			Method method = cls.getMethod(GET_CONTENTS, (Class<?>[])null);
			this.contents = (Object[][])method.invoke(instance, (Object[])null);
		}
		catch (Exception e)
		{
			throw new CAANRuntimeException(e);
		}
	}

	/**
	 * <p>
	 * スキーマのテーブル名を設定します。
	 * </p>
	 */
	private void setTableName()
	{
		try
		{
			Class<?> cls = Class.forName(this.schemaName);
			Object instance = cls.newInstance();
			Method method = cls.getMethod(GET_TABLE, (Class<?>[])null);
			this.tableName = (String)method.invoke(instance, (Object[])null);
		}
		catch (Exception e)
		{
			throw new CAANRuntimeException(e);
		}
	}

	/**
	 * <p>
	 * プライマリレコードの検索処理を行います。
	 * </p>
	 * @param inMsg プライマリレコードの検索キーが格納されたメッセージキャリア
	 * @return 検索結果を格納したメッセージキャリア
	 */
	public CAANMsg findByPrimaryKey(CAANMsg inMsg)
	{
		try
		{
			return super.findByPrimaryKey(inMsg);
		}
		catch (CAANFinderException cfe)
		{
			return null;
		}
	}

	/**
	 * <p>
	 * カレントレコードの検索処理を行います。
	 * </p>
	 * @param inMsg カレントレコードの検索キーが格納されたメッセージキャリア
	 * @return 検索結果を格納したメッセージキャリア
	 */
	public CAANMsg findByCurrent(CAANMsg inMsg)
	{
		CAANLog.println(CAANLog.LEVEL_FW, "CALL: JPCejbDBABase#findByCurrent");
		JCMTraceLog.logging("JPCejbDBABase#findByCurrent");

		Connection cnct = null;
		PreparedStatement pstmt = null;
		ResultSet rslt = null;

		try
		{
			// コネクションの取得
			cnct = getConnection(getTableName());

			String[][] selList = getSelectColumnList();
			String[][] keyList = getKeyColumnList();
			String[][] updKeyList = getPrimaryKeyList(inMsg, keyList);

			StringBuffer sql = new StringBuffer();

			// 対象テーブルの全カラムを検索
			sql.append(" select ").append(getSelectColumnListString(selList[1]));
			sql.append(" from ").append(getTableName());

			// カレントレコードを抽出する条件設定
			sql.append(" where rowid = ");
			sql.append(" ( select row_id from ( select rowid as row_id ");
			sql.append(" from ").append(getTableName());
			sql.append(" where ").append(getWhereKeyColumnListString(updKeyList[1]));

			if (isReserveMgr())
			{
				// 予約を管理するエンティティは予約適用基準日を条件に設定
				sql.append(" and ").append(getCurrentColumn()).append("<=?");
			}

			if (istymdMgr())
			{
				String opedate = "";
				
				opedate = JTUModelCommon.getOpeDate(inMsg, null);
				
				// 適用年月日を管理するエンティティは適用年月日を条件に設定
				sql.append(" and ").append(gettstaymdColumn()).append("<='" + opedate + "'");
				sql.append(" and ").append(gettendymdColumn()).append(">='" + opedate + "'");
			}

			sql.append(" and ").append(getInvalidColumn()).append("='0'");
			sql.append(" order by ");

			if (isReserveMgr())
			{
				sql.append(getCurrentColumn()).append(" desc,");
			}

			if(isGenerationMgr())
			{
				sql.append(getGenerationColumn()).append(" desc)");
			}
			sql.append(" where rownum = 1)");

			CAANLog.println(CAANLog.LEVEL_FW, "sql = [" + sql + "]");
			pstmt = cnct.prepareStatement(sql.toString());

			// 検索条件設定
			setParameters(pstmt, 0, updKeyList[0], inMsg);

			if (isReserveMgr())
			{
				// カレント判定項目の検索値設定
				CAANJDBCUtil.setParam(pstmt, updKeyList[0].length + 1, inMsg.getString(getCurrentColumn()));
			}

			// SQLの実行
			rslt = pstmt.executeQuery();

			// 検索結果が0件の場合
			if (!rslt.next())
			{
				return null;
			}

			// ResultSetの値をメッセージキャリアに転記
			CAANMsg rtnMsg = new CAANMsg(getSchemaName());
			mapMessage(rslt, selList[0], rtnMsg);

			// 正常終了。
			return rtnMsg;
		}
		catch (SQLException e)
		{
			throw new CAANRuntimeException(e);
		}
		finally
		{
			// このメソッドで確保した資源の解放
			try
			{
				if (rslt != null)
				{
					rslt.close();
				}
				if (pstmt != null)
				{
					pstmt.close();
				}
				if (cnct != null)
				{
					closeConnection(cnct);
				}
			}
			catch (SQLException e)
			{
				throw new CAANRuntimeException(e);
			}
		}
	}

	/**
	 * <p>
	 * エンティティのプライマリキーのリストを取得します。<br>
	 * プライマリキーに世代管理カラム名が存在する場合は、リストには含めません。
	 * </p>
	 * @param inMsg エンティティの情報を格納したメッセージキャリア
	 * @param keyList プライマリキー項目のスキーマ項目名とDBカラム名のリスト
	 * @return プライマリキーとなるリスト
	 */
	private String[][] getPrimaryKeyList(CAANMsg inMsg, String[][] keyList)
	{
		ArrayList<String> msgList = new ArrayList<String>(keyList.length);
		ArrayList<String> dbList = new ArrayList<String>(keyList.length);

		for (int i = 0; i < keyList[0].length; i++)
		{
			if (isGenerationMgr() && keyList[0][i].equals(getGenerationColumn()))
			{
				continue;
			}

			if (keyList[0][i].equals(getCurrentColumn()))
			{
				continue;
			}

			if (inMsg.containsKeyOfMsgData(keyList[0][i]))
			{
				msgList.add(keyList[0][i]);
				dbList.add(keyList[1][i]);
			}
		}

		String[] msgClm = msgList.toArray(new String[0]);
		String[] dbClm = dbList.toArray(new String[0]);
		return new String[][] { msgClm, dbClm };
	}

}
