/*******************************************************************************
 *	All Rights reserved,Copyright (c) K-Opticom
 ********************************************************************************
 *＜プログラム内容＞
 *	システム名		：eo顧客基幹システム
 *	モジュール名	：JCKejbExclusiveProcCK0011
 *	ソースファイル名：JCKejbExclusiveProcCK0011.java
 *	作成者			：富士通
 *	日付			：2011年11月22日
 *＜機能概要＞
 *	お客様を起点とするルートの排他処理部品。
 *＜修正履歴＞
 *	バージョン	修正日		修正者		修正内容
 *	ｖ1.00.00	2011/11/22	富士通		新規作成
 *	ｖ4.00.00	2013/05/14	FJ)竹内		IT1-2013-0001199
 *
 ********************************************************************************/

package eo.ejb.common.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import com.fujitsu.futurity.model.base.CAANConnectionMgr;
import com.fujitsu.futurity.model.base.CAANJDBCUtil;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.base.CAANRuntimeException;
import com.fujitsu.futurity.model.ejb.common.JSYejbConnection;
import com.fujitsu.futurity.model.ejb.common.JSYejbLog;

import eo.ejb.cbm.entity.CK0011ETMsg;
import eo.ejb.cbm.entity.KK1681ETMsg;
import eo.ejb.common.JKKModelCommon;

/**
 * <p>
 * お客様を起点とするルートの排他処理部品です。
 * </p>
 * @author 富士通
 *
 */
public class JCKejbExclusiveProcCK0011
{
	
	/** 更新用キー項目結合用文字（,） */
	private static final String KEY_JOIN_WORD = ",";

	/**
	 * 更新系インターフェイス使用時の処理を行います（SYSID指定）。
	 * レコードのロック、タイムスタンプの実施、ロック対象レコードの更新を行います。
	 * @param inETMsg 処理内で使用する項目を保持しているメッセージ
	 * @param key SYSID
	 * @param updDtmBf タイムスタンプチェック用更新年月日時分秒（更新前）
	 * @param funcCd 機能コード
	 * @return 処理が正常に終了し、タイムスタンプチェックが正常の場合はtrue。
	 */
	public boolean isExProcSysid(CAANMsg inETMsg, String key, String updDtmBf, String funcCd)
	{
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JCKejbExclusiveProcCK0011#isExProcSysid");

		// SYSIDが未設定の場合はtrueを返却する。
		if(null == key)
		{
			return true;
		}

		// 更新年月日時分秒(更新前)が未設定の場合はtrueを返却する。
		if(null == updDtmBf)
		{
			return true;
		}

		ArrayList<String> updArray = new ArrayList<String>();
		
		ArrayList<String> keyArrayCK0011 = new ArrayList<String>();
		
		// レコードロックの実行
		try 
		{
			// 処理対象のSYSIDの最終更新年月日時分秒のレコードを取得
			ArrayList<HashMap<String, String>> resultList = getLastUpdRecordCK0011(key);
			if(resultList.size() == 0)
			{
				return true;
			}
			
			for(HashMap<String, String> hm : resultList)
			{
				// お客様をロック
				CAANMsg msg = new CAANMsg(CK0011ETMsg.class.getName());
				msg.set(CK0011ETMsg.SYSID, hm.get(CK0011ETMsg.SYSID));
				msg.set(CK0011ETMsg.GENE_ADD_DTM, hm.get(CK0011ETMsg.GENE_ADD_DTM));
				new JKKejbDBAUtil(msg).findByKeyForUpdate(msg);
				
				// キー情報の格納
				StringBuffer primary = new StringBuffer();
				primary.append(hm.get(CK0011ETMsg.SYSID));
				primary.append(KEY_JOIN_WORD);
				primary.append(hm.get(CK0011ETMsg.GENE_ADD_DTM));
				keyArrayCK0011.add(primary.toString());
				
				// 更新年月日時分秒の格納
				updArray.add(hm.get(CK0011ETMsg.UPD_DTM));
			}
		}
		catch (CAANRuntimeException ce)
		{
			// レコードロックに失敗した場合はfalseを返却する
			return false;
		}
		
		// データが取得できなかった場合は処理を終了する
		if(keyArrayCK0011.size() < 1)
		{
			return true;
		}
		
		// 共通処理のインスタンスを生成
		JKKejbExclusiveProcCommon epc = new JKKejbExclusiveProcCommon();
		
		// タイムスタンプチェックを行い、チェックエラーの場合はfalseを返却する。
		if (!epc.isTimeStampCheck(updArray, updDtmBf))
		{
			return false;
		}

		// 機能コードが実行モードの場合はロック対象レコード更新処理を行う
		if (!epc.isFuncMode(funcCd))
		{
			epc.updateCK0011(inETMsg, keyArrayCK0011);
		}

		return true;
	}

	/**
	 * 更新系インターフェイス使用時の処理を行います（SYSIDリスト指定）。
	 * レコードのロック、タイムスタンプの実施、ロック対象レコードの更新を行います。
	 * @param inETMsg 処理内で使用する項目を保持しているメッセージ
	 * @param keyList SYSIDのリスト
	 * @param updDtmBf タイムスタンプチェック用更新年月日時分秒（更新前）
	 * @param funcCd 機能コード
	 * @return 処理が正常に終了し、タイムスタンプチェックが正常の場合はtrue。
	 */
	public boolean isExProcSysidList(CAANMsg inETMsg, ArrayList<String> keyList, String updDtmBf, String funcCd)
	{
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JCKejbExclusiveProcCK0011#isExLockSysid");

		// SYSIDのリストが0件の場合はtrueを返却する。
		if(keyList.size() < 1)
		{
			return true;
		}

		// 更新年月日時分秒(更新前)が未設定の場合はtrueを返却する。
		if(null == updDtmBf)
		{
			return true;
		}

		ArrayList<String> updArray = new ArrayList<String>();
		
		ArrayList<String> keyArrayCK0011 = new ArrayList<String>();
		
		// レコードロックの実行
		try 
		{
			for (int i = 0; i < keyList.size(); i++)
			{
				// 処理対象のSYSIDの最終更新年月日時分秒のレコードを取得
				ArrayList<HashMap<String, String>> resultList = getLastUpdRecordCK0011(keyList.get(i));
				if(resultList.size() == 0)
				{
					return true;
				}
				
				for(HashMap<String, String> hm : resultList)
				{
					// お客様をロック
					CAANMsg msg = new CAANMsg(CK0011ETMsg.class.getName());
					msg.set(CK0011ETMsg.SYSID, hm.get(CK0011ETMsg.SYSID));
					msg.set(CK0011ETMsg.GENE_ADD_DTM, hm.get(CK0011ETMsg.GENE_ADD_DTM));
					new JKKejbDBAUtil(msg).findByKeyForUpdate(msg);
					
					// キー情報の格納
					StringBuffer primary = new StringBuffer();
					primary.append(hm.get(CK0011ETMsg.SYSID));
					primary.append(KEY_JOIN_WORD);
					primary.append(hm.get(CK0011ETMsg.GENE_ADD_DTM));
					keyArrayCK0011.add(primary.toString());
					
					// 更新年月日時分秒の格納
					updArray.add(hm.get(CK0011ETMsg.UPD_DTM));
				}
			}
		}
		catch (CAANRuntimeException ce)
		{
			// レコードロックに失敗した場合はfalseを返却する
			return false;
		}
		
		// データが取得できなかった場合は処理を終了する
		if(keyArrayCK0011.size() < 1)
		{
			return true;
		}

		// 共通処理のインスタンスを生成
		JKKejbExclusiveProcCommon epc = new JKKejbExclusiveProcCommon();
		
		// タイムスタンプチェックを行い、チェックエラーの場合はfalseを返却する。
		if (!epc.isTimeStampCheck(updArray, updDtmBf))
		{
			return false;
		}

		// 機能コードが実行モードの場合はロック対象レコード更新処理を行う
		if (!epc.isFuncMode(funcCd))
		{
			epc.updateCK0011(inETMsg, keyArrayCK0011);
		}

		return true;
	}

	/**
	 * 照会系インターフェイス使用時の処理を行います（SYSID）。
	 * 指定されたキーに紐付く親テーブルを各ルートから検索し、
	 * その中で最大の更新年月日時分秒を取得します。
	 * @param inMsg 処理対象のメッセージ
	 * @param key SYSID
	 * @return 指定したキーに紐付く最終更新年月日時分秒。
	 */
	public String getLastUpdDtmSysId(CAANMsg inMsg, String key)
	{
		// ログの出力
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JCKejbExclusiveProcCK0011#getLastUpdDtmSysId");
		JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), "call:JCKejbExclusiveProcCK0011#key=" + key);
		
		ArrayList<String> updArray = new ArrayList<String>();
		
		ArrayList<HashMap<String, String>> resultList = getLastUpdRecordCK0011(key);
		for(HashMap<String, String> hm : resultList)
		{
			updArray.add(hm.get(CK0011ETMsg.UPD_DTM));
		}

		// データが取得できなかった場合はエラーとする
		if(updArray.size() < 1)
		{
			return null;
		}

		// 最終更新年月日時分秒を取得する
		String maxUpdDtm = new JKKejbExclusiveProcCommon().getLastUpdDtm(updArray);

		return maxUpdDtm;
	}

	// 2013/5/14 IT1-2013-0001199障害対応 START お客様併合・分割先(元)の「お客様」については排他ロック対象外とする。
//	/**
//	 * ロック対象キーの取得を行います。
//	 * @param inMsg 処理対象のメッセージ
//	 * @param key SYSID
//	 * @return ロック対象のSYSIDリスト
//	 */
//	private ArrayList<String> getLockTgt(CAANMsg inMsg, String key)
//	{
//		ArrayList<String> retList = new ArrayList<String>();
//		
//		// keyを結果リストに詰める
//		retList.add(key); 
//
//		for (int i = 0; i < retList.size(); i++)	
//		{	
//			// ロック対象リストに設定されたSYSIDに異動予約の以下の項目に対して検索を行う。
//			// @SYSIDに対する検索
//			// A併合先SYSIDに対する検索
//			// B分割先SYSIDに対する検索
//			ArrayList<HashMap<String, String>> resultList = searchSysid(retList.get(i), JKKModelCommon.getOpeDate(inMsg));
//			
//			if(resultList.size() != 0)
//			{
//				// 検索結果をロック対象リストに反映
//				setList(retList, resultList);
//			}
//		}
//		
//		return retList;
//	}
//	
//	/**
//	 * 検索結果の値をリストに追加する。
//	 * @param keyLst ロック対象リスト
//	 * @param tgtLst 検索結果
//	 */
//	private void setList(ArrayList<String> keyLst, ArrayList<HashMap<String, String>> tgtLst)
//	{
//		
//		// 設定済みSYSID保持用
//		HashMap<String, String> hash = new HashMap<String, String>();
//		
//		for (int k = 0; k < keyLst.size(); k++)
//		{
//			// 現在のkey情報の詰め替え
//			hash.put(keyLst.get(k), keyLst.get(k));
//		}
//		
//		for (int i = 0; i < tgtLst.size(); i++)
//		{
//			String tgtSysid = tgtLst.get(i).get(KK1681ETMsg.SYSID);
//			String tgtHgskSysid = tgtLst.get(i).get(KK1681ETMsg.HEIGO_SK_SYSID);
//			String tgtBkskSysid = tgtLst.get(i).get(KK1681ETMsg.BUNKATSU_SK_SYSID);
//			
//			// 検索結果のkeyLst内の存在判定を行う
//			// SYSID
//			if(tgtSysid != null && !"".equals(tgtSysid))
//			{
//				if(!hash.containsKey(tgtSysid))
//				{
//					// 一致する値が存在しない場合にkeyLstに追加する
//					hash.put(tgtSysid, tgtSysid);
//					keyLst.add(tgtSysid);
//				}
//			}
//			
//			// 併合先SYSID
//			if(tgtHgskSysid != null && !"".equals(tgtHgskSysid))
//			{
//				if(!hash.containsKey(tgtHgskSysid))
//				{
//					hash.put(tgtHgskSysid, tgtHgskSysid);
//					keyLst.add(tgtHgskSysid);
//				}
//			}
//			
//			// 分割先SYSID
//			if(tgtBkskSysid != null && !"".equals(tgtBkskSysid))
//			{
//				if(!hash.containsKey(tgtBkskSysid))
//				{
//					hash.put(tgtBkskSysid, tgtBkskSysid);
//					keyLst.add(tgtBkskSysid);
//				}
//			}		
//		}
//	}
//
//	/**
//	 * 異動予約に対するSYSIDの検索を行う。
//	 * @param key SYSID
//	 * @param opeDate 運用日時
//	 * @return 検索結果
//	 */
//	private ArrayList<HashMap<String, String>> searchSysid(String key, String opeDate)
//	{
//		
//		// コネクション
//		Connection con = null;
//		// プリペアステートメント
//		PreparedStatement pstmt = null;
//		// リザルトセット
//		ResultSet rsltQuery = null;
//		// SQL文
//		StringBuffer sbSql = new StringBuffer();
//		
//		sbSql.append(" SELECT ");
//		sbSql.append("    NULL SYSID, ");
//		sbSql.append("    KK1681.HEIGO_SK_SYSID, ");
//		sbSql.append("    KK1681.BUNKATSU_SK_SYSID ");
//		sbSql.append(" FROM ");
//		sbSql.append("    KK_T_IDO_RSV KK1681 ");
//		sbSql.append(" WHERE KK1681.SYSID = ? ");
//		sbSql.append(" AND   KK1681.RSV_APLY_YMD > ?  ");
//		sbSql.append(" UNION ");
//		sbSql.append(" SELECT ");
//		sbSql.append("    KK1681.SYSID, ");
//		sbSql.append("    NULL HEIGO_SK_SYSID, ");
//		sbSql.append("    NULL BUNKATSU_SK_SYSID ");
//		sbSql.append(" FROM ");
//		sbSql.append("    KK_T_IDO_RSV KK1681 ");
//		sbSql.append(" WHERE KK1681.HEIGO_SK_SYSID = ? ");
//		sbSql.append(" AND   KK1681.RSV_APLY_YMD > ?  ");
//		sbSql.append(" UNION ");
//		sbSql.append(" SELECT ");
//		sbSql.append("    KK1681.SYSID, ");
//		sbSql.append("    NULL HEIGO_SK_SYSID, ");
//		sbSql.append("    NULL BUNKATSU_SK_SYSID ");
//		sbSql.append(" FROM ");
//		sbSql.append("    KK_T_IDO_RSV KK1681 ");
//		sbSql.append(" WHERE KK1681.BUNKATSU_SK_SYSID = ? ");
//		sbSql.append(" AND   KK1681.RSV_APLY_YMD > ?  ");
//
//		try
//		{
//			// 対象テーブルのコネクション取得
//			con = JSYejbConnection.getConnection(KK1681ETMsg.getTableName());
//
//			// prepareStatementにSQL文をセット
//			pstmt = con.prepareStatement(sbSql.toString());
//
//			// ログ出力(SQL文の出力)
//			JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), sbSql);
//
//			// バインド変数設定
//			CAANJDBCUtil.setParam(pstmt, 1, key);
//			CAANJDBCUtil.setParam(pstmt, 2, opeDate);
//			
//			CAANJDBCUtil.setParam(pstmt, 3, key);
//			CAANJDBCUtil.setParam(pstmt, 4, opeDate);
//			
//			CAANJDBCUtil.setParam(pstmt, 5, key);
//			CAANJDBCUtil.setParam(pstmt, 6, opeDate);
//
//			// ResultSetの取得
//			rsltQuery = pstmt.executeQuery();
//
//			// 格納マップの生成
//			ArrayList<HashMap<String, String>> rsltList = new ArrayList<HashMap<String, String>>();
//			
//			// 取得結果をマップに格納
//			while (rsltQuery.next())
//			{
//				// 格納マップの生成
//				HashMap<String, String> mapRslt = new HashMap<String, String>();
//				mapRslt.put(KK1681ETMsg.SYSID, rsltQuery.getString(1));
//				mapRslt.put(KK1681ETMsg.HEIGO_SK_SYSID, rsltQuery.getString(2));
//				mapRslt.put(KK1681ETMsg.BUNKATSU_SK_SYSID, rsltQuery.getString(3));
//
//				rsltList.add(mapRslt);
//			}
//			
//			// 取得した情報を返却
//			return rsltList;
//
//		}
//		catch (SQLException e)
//		{
//			throw new CAANRuntimeException(e);
//		}
//		finally
//		{
//			// 資源の解放
//			try
//			{
//				if (rsltQuery != null)
//				{
//					rsltQuery.close();
//				}
//				if (pstmt != null)
//				{
//					pstmt.close();
//				}
//				if (con != null)
//				{
//					CAANConnectionMgr.getInstance().close(con);
//				}
//			}
//			catch (SQLException e1)
//			{
//				throw new CAANRuntimeException(e1);
//			}
//		}
//		
//	}
	// 2013/5/14 IT1-2013-0001199障害対応 END

	/**
	 * <p>
	 * パラメータで渡されたSYSIDに該当する
	 * お客様テーブル、異動予約テーブルで最後に更新されたレコードを取得する。
	 * </p>
	 * @param  primaryKey SYSID
	 * @return rsltList   検索結果
	 */
	public ArrayList<HashMap<String, String>> getLastUpdRecordCK0011(String primaryKey)
	{
		// コネクション
		Connection con = null;
		// プリペアステートメント
		PreparedStatement pstmt = null;
		// リザルトセット
		ResultSet rsltQuery = null;
		// SQL文
		StringBuffer sbSql = new StringBuffer();

		sbSql.append(" SELECT ");
		sbSql.append("    CK0011.SYSID, ");
		sbSql.append("    CK0011.GENE_ADD_DTM, ");
		sbSql.append("    CK0011.UPD_DTM ");
		sbSql.append(" FROM ");
		sbSql.append("    CK_T_CUST CK0011 ");
		sbSql.append(" WHERE   CK0011.SYSID = ? ");
		sbSql.append(" AND     CK0011.UPD_DTM =  ");
		sbSql.append("          (SELECT MAX(CK0011_01.UPD_DTM) AS CK0011_MAX ");
		sbSql.append("           FROM   CK_T_CUST CK0011_01 ");
		sbSql.append("           WHERE  CK0011_01.SYSID = CK0011.SYSID ) ");
		
		try
		{
			// 対象テーブルのコネクション取得
			con = JSYejbConnection.getConnection(CK0011ETMsg.getTableName());

			// prepareStatementにSQL文をセット
			pstmt = con.prepareStatement(sbSql.toString());

			// ログ出力(SQL文の出力)
			JSYejbLog.println(JSYejbLog.DEBUG, this.getClass(), sbSql);

			// バインド変数設定
			CAANJDBCUtil.setParam(pstmt, 1, primaryKey);

			// ResultSetの取得
			rsltQuery = pstmt.executeQuery();

			// 格納マップの生成
			ArrayList<HashMap<String, String>> rsltList = new ArrayList<HashMap<String, String>>();
			
			// 取得結果をマップに格納
			while (rsltQuery.next())
			{
				// 格納マップの生成
				HashMap<String, String> mapRslt = new HashMap<String, String>();

				//お客様の情報を返却
				mapRslt.put(CK0011ETMsg.SYSID, rsltQuery.getString(1));
				mapRslt.put(CK0011ETMsg.GENE_ADD_DTM, rsltQuery.getString(2));
				mapRslt.put(CK0011ETMsg.UPD_DTM, rsltQuery.getString(3));
				rsltList.add(mapRslt);
			}

			// 取得した情報を返却
			return rsltList;

		}
		catch (SQLException e)
		{
			throw new CAANRuntimeException(e);
		}
		finally
		{
			// 資源の解放
			try
			{
				if (rsltQuery != null)
				{
					rsltQuery.close();
				}
				if (pstmt != null)
				{
					pstmt.close();
				}
				if (con != null)
				{
					CAANConnectionMgr.getInstance().close(con);
				}
			}
			catch (SQLException e1)
			{
				throw new CAANRuntimeException(e1);
			}
		}
	}
	
}
