/*********************************************************************
*	All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*	モジュール名	：JPCejbDBABase
*	ソースファイル名：JPCejbDBABase.java
*	作成者			：富士通
*	日付			：2011年03月14日
*＜機能概要＞
*	データベースアクセス共通部品のスーパークラス
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v1.00.00	2011/03/14	富士通		新規作成
*   v7.00.00    2014/03/25  FJ          OM-2014-0000782 メール送信が遅い
*   v33.00.00	2017/08/29	FJ)孫		ANK-3035-00-00 未来予約データ存在時のお客様スキーマの挙動
*
**********************************************************************/

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 java.util.Date;
import java.util.HashMap;

import com.fujitsu.futurity.common.JCCWebAddTrnId;
import com.fujitsu.futurity.common.JCMConstants;
import com.fujitsu.futurity.common.JCMTraceLog;
import com.fujitsu.futurity.common.JSYLogBase;
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.JSYejbLog;
import com.fujitsu.futurity.model.ejb.common.fw.TemplateSQLEntity;

import eo.ejb.cbm.entity.CK0201ETMsg;

/**
 * <p>
 * データベースアクセス共通部品のスーパークラスです。<br>
 * 必ず内部スキーマ単位で本クラスを継承したサブクラスを実装して使用してください。
 * </p>
 * @author 富士通
 */
public abstract class JPCejbDBABase 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";
	
	// ANK-3035-00-00 2017/09/22 ADD START
	/** スキーマテーブル名の取得メソッド名 */
	private static final String SET_SYSID = "SYSID";
	
	/** スキーマテーブル名の取得メソッド名 */
	private static final String SET_GENE_ADD_DTM = "GENE_ADD_DTM";
	
	/** お客様情報変更のサービスID. */
	private static final String SERVICE_ID_CUST_INFO_MOD = "CKSV9025";
	// ANK-3035-00-00 2017/09/22 ADD END


	/**
	 * <p>
	 * 新しいJPCejbDBABaseを作成します。
	 * </p>
	 */
	public JPCejbDBABase()
	{
	}

	/**
	 * <p>
	 * 新しいJPCejbDBABaseを作成します。
	 * </p>
	 */
	public JPCejbDBABase(String arg0)
	{
		super();
		setSchemaInfo(arg0);
	}

	/**
	 * <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 isReserveStateMgr();

	/**
	 * <p>
	 * 予約の状態を管理するカラム名を取得します。
	 * </p>
	 * @return 予約の状態を管理するカラム名
	 */
	protected abstract String getReserveStateColumn();

	/**
	 * <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 findByKeyForUpdate(CAANMsg inMsg)
	{
		try
		{
			return super.findByKeyForUpdate(inMsg);
		}
		catch (CAANFinderException cfe)
		{
			return null;
		}
	}

	/**
	 * <p>
	 * カレントレコードの検索処理を行います。
	 * </p>
	 * @param inMsg カレントレコードの検索キーが格納されたメッセージキャリア
	 * @return 検索結果を格納したメッセージキャリア
	 */
	public CAANMsg findByCurrent(CAANMsg inMsg)
	{
		// v7.00.00 出力ログ追加
		long dt0 = (new Date()).getTime();

		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());
			// v7.00.00 出力ログ追加
			long dt1 = (new Date()).getTime();

			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 (isReserveStateMgr())
			{
				// 予約状態を管理するエンティティは予約状態を条件に設定
				sql.append(" and ").append(getReserveStateColumn()).append("='2'");
			}

			sql.append(" and ").append(getInvalidColumn()).append("='0'");
			sql.append(" order by ");

			if (isReserveMgr())
			{
				sql.append(getCurrentColumn()).append(" desc,");
			}

			sql.append(getGenerationColumn()).append(" desc)");
			sql.append(" where rownum = 1)");

			// 2012/05/17 ログ出力レベルを変更 start
			//CAANLog.println(CAANLog.LEVEL_FW, "sql = [" + sql + "]");
			CAANLog.println(CAANLog.DBACCESS, sql);
			// 2012/05/17 ログ出力レベルを変更 end
			
			pstmt = cnct.prepareStatement(sql.toString());

			// 検索条件設定
			setParameters(pstmt, 0, updKeyList[0], inMsg);

			if (isReserveMgr())
			{
				// カレント判定項目の検索値設定
				CAANJDBCUtil.setParam(pstmt, updKeyList[0].length + 1, inMsg.getString(getCurrentColumn()));
			}

			// v7.00.00 出力ログ追加
			long dt2 = (new Date()).getTime();

			// SQLの実行
			rslt = pstmt.executeQuery();

			// v7.00.00 出力ログ追加
			long dt3 = (new Date()).getTime();

			// 検索結果が0件の場合
			if (!rslt.next())
			{
				return null;
			}

			// ResultSetの値をメッセージキャリアに転記
			CAANMsg rtnMsg = new CAANMsg(getSchemaName());
			mapMessage(rslt, selList[0], rtnMsg);

			// v7.00.00 出力ログ追加
			long dt4 = (new Date()).getTime();
			JSYejbLog.println(JSYLogBase.EXECUTION, getClass(), "JPCejbDBABase.findByCurrent() 所要時間=" + (dt4 - dt0)
					+ "( getConnection=" + (dt1 - dt0) + ", SQL文作成=" + (dt2 - dt1)
					+ ", SQL実行=" + (dt3 - dt2) + ", CAANMsg作成=" + (dt4 - dt3) + " )");

			// 正常終了。
			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>
	 * 予約レコードの検索処理を行います。
	 * </p>
	 * @param inMsg 予約レコードの検索キーが格納されたメッセージキャリア
	 * @return 検索結果を格納したメッセージキャリア
	 */
	public CAANMsg[] findByReserve(CAANMsg inMsg)
	{
		CAANLog.println(CAANLog.LEVEL_FW, "CALL: JPCejbDBABase#findByReserve");
		JCMTraceLog.logging("JPCejbDBABase#findByReserve");
		
		Connection cnct = null;
		PreparedStatement pstmt = null;
		ResultSet rslt = null;

		String[][] selList = getSelectColumnList();
		String[][] keyList = getKeyColumnList();

		try
		{
			// コネクションの取得
			cnct = getConnection(getTableName());

			String[][] updKeyList = getPrimaryKeyList(inMsg, keyList);

			StringBuffer sql = new StringBuffer();

			// 対象テーブルの全カラムを検索
			sql.append(" select ").append(getSelectColumnListString(selList[1]));
			sql.append(" from ").append(getTableName());

			// 予約レコードを抽出する条件設定
			sql.append(" where ").append(getWhereKeyColumnListString(updKeyList[1]));
			sql.append(" and (").append(getCurrentColumn()).append(">?");
			sql.append(" or ").append(getCurrentColumn()).append(" is null)");

			if (isReserveStateMgr())
			{
				sql.append(" and ").append(getReserveStateColumn()).append(" in ('1','2')");
			}

			sql.append(" and ").append(getInvalidColumn()).append("='0'");
			sql.append(" order by ");
			sql.append(getCurrentColumn()).append(",");
			sql.append(getGenerationColumn());

			// 2012/05/17 ログ出力レベルを変更 start
			//CAANLog.println(CAANLog.LEVEL_FW, "sql = [" + sql + "]");
			CAANLog.println(CAANLog.DBACCESS, sql);
			// 2012/05/17 ログ出力レベルを変更 end
			pstmt = cnct.prepareStatement(sql.toString());

			// 検索条件設定
			setParameters(pstmt, 0, updKeyList[0], inMsg);

			// カレント判定項目の検索値設定
			CAANJDBCUtil.setParam(pstmt, updKeyList[0].length + 1, inMsg.getString(getCurrentColumn()));

			// SQLの実行
			rslt = pstmt.executeQuery();

			// ResultSetの値をメッセージキャリアに転記
			return mapMessageList(rslt, selList[0], 0);
		}
		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>
	 * 履歴レコードの検索処理を行います。
	 * </p>
	 * @param inMsg 履歴レコードの検索キーが格納されたメッセージキャリア
	 * @return 検索結果を格納したメッセージキャリア
	 */
	public CAANMsg[] findByHistory(CAANMsg inMsg)
	{
		CAANLog.println(CAANLog.LEVEL_FW, "CALL: JPCejbDBABase#findByHistory");
		JCMTraceLog.logging("JPCejbDBABase#findByHistory");

		Connection cnct = null;
		PreparedStatement pstmt = null;
		ResultSet rslt = null;

		String[][] selList = getSelectColumnList();
		String[][] keyList = getKeyColumnList();

		try
		{
			// コネクションの取得
			cnct = getConnection(getTableName());

			String[][] updKeyList = getPrimaryKeyList(inMsg, keyList);

			StringBuffer sql = new StringBuffer();

			// 対象テーブルの全カラムを検索
			sql.append(" select ").append(getSelectColumnListString(selList[1]));
			sql.append(" from ( select rownum as row_num, alias.* from (");
			sql.append(" select ").append(getSelectColumnListString(selList[1]));
			sql.append(" from ").append(getTableName());

			// 予約レコードを抽出する条件設定
			sql.append(" where ").append(getWhereKeyColumnListString(updKeyList[1]));

			if (isReserveMgr())
			{
				// 予約を管理するエンティティは予約適用基準日を条件に設定
				sql.append(" and ").append(getCurrentColumn()).append("<=?");
			}

			if (isReserveStateMgr())
			{
				sql.append(" and ").append(getReserveStateColumn()).append("='2'");
			}

			sql.append(" and ").append(getInvalidColumn()).append("='0'");
			sql.append(" order by ");

			if (isReserveMgr())
			{
				sql.append(getCurrentColumn()).append(" desc,");
			}

			sql.append(getGenerationColumn()).append(" desc) alias)");
			sql.append(" where row_num > 1 ");
			
			// 2012/05/17 ログ出力レベルを変更 start
			//CAANLog.println(CAANLog.LEVEL_FW, "sql = [" + sql + "]");
			CAANLog.println(CAANLog.DBACCESS, sql);
			// 2012/05/17 ログ出力レベルを変更 end
			
			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();

			// ResultSetの値をメッセージキャリアに転記
			return mapMessageList(rslt, selList[0], 0);
		}
		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 (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 };
	}
	// ANK-3035-00-00 2017/09/22 ADD START
	/**
	 * <p>
	 * 予約レコードの検索処理を行います。
	 * </p>
	 * @param inMsg 予約レコードの検索キーが格納されたメッセージキャリア
	 * @return 検索結果を格納したメッセージキャリア
	 */
	public CAANMsg[] findByReserveRrks(CAANMsg inMsg)
	{
		CAANLog.println(CAANLog.LEVEL_FW, "CALL: JPCejbDBABase#findByReserveRrks");
		JCMTraceLog.logging("JPCejbDBABase#findByReserveRrks");
		
		Connection cnct = null;
		PreparedStatement pstmt = null;
		ResultSet rslt = null;
		
		//selectリスト取得する
		String[][] selList = getSelectColumnList();
		//SYSID,GENE_ADD_DTM固定値を取得する
		String[][] keyList = getKeyColumnListSysid();
		
		try
		{
			// コネクションの取得
			cnct = getConnection(getTableName());

			String[][] updKeyList = getPrimaryKeyList(inMsg, keyList);

			StringBuffer sql = new StringBuffer();

			// 対象テーブルの全カラムを検索
			sql.append(" select ").append(getSelectColumnListString(selList[1]));
			sql.append(" from ").append(getTableName());

			// 予約レコードを抽出する条件設定
			sql.append(" where ").append(getWhereKeyColumnListString(updKeyList[1]));
			sql.append(" and (").append(getCurrentColumn()).append(">?");
			sql.append(" or ").append(getCurrentColumn()).append(" is null)");
			
			if(null == inMsg.getString(CK0201ETMsg.MLAD))
			{
				sql.append(" and ").append("RRK_WAY_CD").append("='003'");
			}
			if(null == inMsg.getString(CK0201ETMsg.TELNO))
			{
				sql.append(" and ").append("RRK_WAY_CD").append("='001'");
			}
			sql.append(" and ").append("RRKS_SBT_CD").append("='1'");
			sql.append(" and ").append("RRKS_BUNRUI_CD").append("='1'");

			if (isReserveStateMgr())
			{
				sql.append(" and ").append(getReserveStateColumn()).append(" in ('1','2')");
			}

			sql.append(" and ").append(getInvalidColumn()).append("='0'");
			sql.append(" order by ");
			sql.append(getCurrentColumn()).append(",");
			sql.append(getGenerationColumn());

			CAANLog.println(CAANLog.DBACCESS, sql);
			pstmt = cnct.prepareStatement(sql.toString());

			// 検索条件設定
			setParameters(pstmt, 0, updKeyList[0], inMsg);

			// カレント判定項目の検索値設定
			CAANJDBCUtil.setParam(pstmt, updKeyList[0].length + 1, inMsg.getString(getCurrentColumn()));

			// SQLの実行
			rslt = pstmt.executeQuery();

			// ResultSetの値をメッセージキャリアに転記
			return mapMessageList(rslt, selList[0], 0);
		}
		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>
	 * @return プライマリキーとなるリスト
	 */
	private String[][] getKeyColumnListSysid()
	{
		ArrayList<String> msgList = new ArrayList<String>();
		ArrayList<String> dbList = new ArrayList<String>();
		msgList.add(SET_GENE_ADD_DTM);
		msgList.add(SET_SYSID);
		dbList.add(SET_GENE_ADD_DTM);
		dbList.add(SET_SYSID);
		
		String[] msgClm = (String[])msgList.toArray(new String[0]);
		String[] dbClm  = (String[])dbList.toArray(new String[0]);

		return new String[][] { msgClm, dbClm };
	}
	// ANK-3035-00-00 2017/09/22 ADD END
}
