/*******************************************************************************
*	All Rights reserved,Copyright (c) K-Opticom
********************************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*	モジュール名	：JKK0451TPMA
*	ソースファイル名：JKK0451TPMA.java
*	作成者			：富士通
*	日付			：2011年11月22日
*＜機能概要＞
*	割引サービス契約のサービスIF顧客独自処理部品
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v1.00.00	2011/11/22	富士通		新規作成
*
********************************************************************************/

package eo.ejb.cbs.mainproc;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

import com.fujitsu.futurity.common.JCMConstants;
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.StatusCodes;
import com.fujitsu.futurity.model.ejb.common.fw.AgentDispatchContext;
import com.fujitsu.futurity.model.ejb.common.fw.TemplateMainHandler;

import eo.ejb.cbm.entity.KK0451ETMsg;
import eo.ejb.cbm.entity.KK2111ETMsg;
import eo.ejb.common.db.JKKejbDBAUtil;
import eo.ejb.common.db.JKKejbExclusiveProcKK0161;
import eo.ejb.common.db.JKKejbExclusiveProcKK0341;
import eo.ejb.common.db.JKKejbExclusiveProcKK0351;
import eo.ejb.common.db.JKKejbExclusiveProcKK0481;
import eo.ejb.common.db.JKKejbExclusiveProcKK2111;

/**
 * <p>
 * 割引サービス契約のサービスIF顧客独自処理部品クラスです。
 * </p>
 * @author 富士通
 */
public class JKK0451TPMA implements TemplateMainHandler
{

	/** CBS層 割引サービス契約番号キー項目名 */
	private static final String CBS_PK_NAME = "wrib_svc_kei_no";

	/** CBS層 更新年月日時分秒（更新前）キー項目名 */
	private static final String CBS_UPD_BF_NAME = "upd_dtm_bf";

	/** CBS層 サービス契約番号キー項目名 */
	private static final String CBS_SVC_KEI_NAME = "svc_kei_no";

	/** CBS層 サービス契約内訳番号キー項目名 */
	private static final String CBS_SVC_UCWK_NAME = "svc_kei_ucwk_no";

	/** CBS層 オプションサービス契約番号キー項目名 */
	private static final String CBS_OP_SVC_KEI_NAME = "op_svc_kei_no";

	/** CBS層 機器提供サービス契約番号キー項目名 */
	private static final String CBS_KK_SVC_KEI_NAME = "kktk_svc_kei_no";

	/** データ取得結果設定項目名（サービス契約番号） */
	private static final String SET_PRIMARY = "SET_PRIMARY";

	/** データ取得結果設定項目名（更新年月日時分秒） */
	private static final String SET_UPD_DTM = "SET_UPD_DTM";
	
	/**
	 * リスト処理の対象
	 */
	private static final HashMap<String, String> TEMPLATE_LIST_MAP = new HashMap<String, String>();

	static
	{
		TEMPLATE_LIST_MAP.put("EKK0451D010", "EKK0451D010CBSMsg1List");
	}

	/** エラーフラグ */
	private static final String ERR_FLG = "EA";

	/** エラーフラグ設定項目名 */
	private static final String ERR_CONTENTS = "upd_dtm_bf_err";

	/**
	 * <p>
	 * 割引サービス契約のスキーマのロック、タイムスタンプチェック、およびタイムスタンプ更新を行います。
	 * 請求契約のスキーマのロックを行います。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 */
	public void execExclusiveProc(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		// 必要な項目を保持したETMsgを作成する
		CAANMsg inETMsg = new CAANMsg(KK0451ETMsg.class.getName());

		// プライマリキーを設定
		inETMsg.set(KK0451ETMsg.WRIB_SVC_KEI_NO, inCBSMsg.getString(CBS_PK_NAME));

		// 更新情報の設定
		inETMsg.set(KK0451ETMsg.UPD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		inETMsg.set(KK0451ETMsg.UPD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));

		// メイン処理の呼び出し
		boolean ret = this.execExclusiveMain(inETMsg, inCBSMsg.getString(CBS_UPD_BF_NAME), inCBSMsg.getString(JCMConstants.FUNC_CODE_KEY));

		// 処理結果がfalseの場合は関連制約エラーとする
		if (!ret)
		{
			inCBSMsg.set(ERR_CONTENTS, ERR_FLG);
			inCBSMsg.set(JCMConstants.STATUS_INT_KEY, StatusCodes.RELATION_ERR);
			return;
		}
	}

	/**
	 * <p>
	 * 割引サービス契約のスキーマのロック、タイムスタンプチェック、およびタイムスタンプ更新を行います（リスト単位）。
	 * 請求契約のスキーマのロックを行います。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 */
	public void execExclusiveProcList(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		// サービスインターフェイスIDの取得
		String templateId = inCBSMsg.getString(JCMConstants.TEMPLATE_ID_KEY);

		// 指定されたサービスインターフェイスが対象外の場合は処理を行わない
		if (!TEMPLATE_LIST_MAP.containsKey(templateId))
		{
			return;
		}

		// 使用する項目の取得
		CAANMsg[] keyList = inCBSMsg.getCAANMsgList(TEMPLATE_LIST_MAP.get(templateId));
		String updDtmBf = inCBSMsg.getString(CBS_UPD_BF_NAME);

		// 必要な項目を保持したETMsgを作成する
		CAANMsg inETMsg = new CAANMsg(KK0451ETMsg.class.getName());

		// 更新情報の設定
		inETMsg.set(KK0451ETMsg.UPD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		inETMsg.set(KK0451ETMsg.UPD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));

		// ログの出力
		outLogList(inCBSMsg, keyList, updDtmBf);

		// 結果設定用リスト
		ArrayList<String> keyArray = new ArrayList<String>();
		ArrayList<String> updArray = new ArrayList<String>();

		try
		{
			// 結果設定用MAP
			HashMap<String, ArrayList<String>> retMap = new HashMap<String, ArrayList<String>>();

			// 明細の件数分処理を行う
			for(int i = 0; i < keyList.length; i++)
			{
				// 入力された項目に対応するロック対象レコードの情報を取得する
				if (!keyList[i].isNull(CBS_SVC_KEI_NAME))
				{
					retMap = new JKKejbExclusiveProcKK2111().getRecordSvcKeiNo(inETMsg, keyList[i].getString(CBS_SVC_KEI_NAME));
				}
				else if (!keyList[i].isNull(CBS_SVC_UCWK_NAME))
				{
					retMap = new JKKejbExclusiveProcKK0161().getRecordSvcKeiUcwkNo(inETMsg, keyList[i].getString(CBS_SVC_UCWK_NAME));
				}
				else if (!keyList[i].isNull(CBS_OP_SVC_KEI_NAME))
				{
					retMap = new JKKejbExclusiveProcKK0351().getRecordOpSvcKeiNo(inETMsg, keyList[i].getString(CBS_OP_SVC_KEI_NAME));
				}
				else if (!keyList[i].isNull(CBS_KK_SVC_KEI_NAME))
				{
					retMap = new JKKejbExclusiveProcKK0341().getRecordKktkSvcKeiNo(inETMsg, keyList[i].getString(CBS_KK_SVC_KEI_NAME));
				}
				else
				{
					continue;
				}

				// 取得結果をリストに格納する
				keyArray.addAll(retMap.get(SET_PRIMARY));
				updArray.addAll(retMap.get(SET_UPD_DTM));
			}
		}
		catch(CAANRuntimeException ce)
		{
			// ロック失敗の場合は関連制約エラーとする
			setError(inCBSMsg);
			return;
		}

		// データが取得できなかった場合は処理を終了する
		if(keyArray.size() < 1)
		{
			return;
		}

		// タイムスタンプチェックを行い、チェックエラーの場合関連制約エラーとする
		if (!this.isTimeStampCheck(updArray, updDtmBf))
		{
			setError(inCBSMsg);
			return;
		}

		// 機能コードが実行モードの場合はロック対象レコード更新処理を行う
		if (!this.isFuncMode(inCBSMsg.getString(JCMConstants.FUNC_CODE_KEY)))
		{
			this.updateKK2111(inETMsg, keyArray);
		}
	}

	/**
	 * <p>
	 * 割引サービス契約のスキーマのロック、タイムスタンプチェック、およびタイムスタンプ更新を行います。
	 * </p>
	 * @param inETMsg 処理対象のメッセージキャリア（ET）
	 * @param updDtmBf 更新年月日時分秒（更新前）
	 * @param funcCd 機能コード
	 * @return スキーマのロック、タイムスタンプチェック、およびタイムスタンプ更新が正常終了の場合はtrue。
	 */
	private boolean execExclusiveMain(CAANMsg inETMsg, String updDtmBf, String funcCd)
	{
		// ログの出力
		outLog(inETMsg, updDtmBf);

		boolean ret = true;

		// 割引サービス対象契約排他処理部品（割引サービス対象契約番号）の呼び出し
		ret = new JKKejbExclusiveProcKK0481().isExProcWribSvcKeiNo(inETMsg, inETMsg.getString(KK0451ETMsg.WRIB_SVC_KEI_NO), updDtmBf, funcCd);

		return ret;
	}

	/**
	 * <p>
	 * ログの出力を行います。
	 * </p>
	 * @param inETMsg 処理対象のメッセージキャリア（ET）
	 * @param updDtmBf 更新年月日時分秒（更新前）
	 */
	private void outLog(CAANMsg inETMsg, String updDtmBf)
	{
		// プライマリキーの出力
		JSYejbLog.println(JSYejbLog.DEBUG, getClass(), "JKK0451TPMA.wrib_svc_kei_no=" + inETMsg.getString(KK0451ETMsg.WRIB_SVC_KEI_NO));

		// 更新年月日時分秒（更新前）の出力
		JSYejbLog.println(JSYejbLog.DEBUG, getClass(), "JKK0451TPMA.upd_dtm_bf=" + updDtmBf);
	}

	/**
	 * <p>
	 * ログの出力を行います（リスト用）。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param msgList キー項目明細
	 * @param updDtmBf 更新年月日時分秒（更新前）
	 */
	private void outLogList(CAANMsg inCBSMsg, CAANMsg[] msgList, String updDtmBf)
	{
		// プライマリキーの出力
		JSYejbLog.println(JSYejbLog.DEBUG, getClass(), "JEKK0461D010TPMA.wrib_svc_kei_no=" + inCBSMsg.getString(CBS_PK_NAME));

		// リスト項目の出力
		for (int i = 0; i < msgList.length; i++)
		{
			JSYejbLog.println(JSYejbLog.DEBUG, getClass(), "JKK0451TPMA.List_" + i);
			JSYejbLog.println(JSYejbLog.DEBUG, getClass(), "JKK0451TPMA.svc_kei_no=" + msgList[i].getString(CBS_SVC_KEI_NAME));
			JSYejbLog.println(JSYejbLog.DEBUG, getClass(), "JKK0451TPMA.svc_kei_ucwk_no=" + msgList[i].getString(CBS_SVC_UCWK_NAME));
			JSYejbLog.println(JSYejbLog.DEBUG, getClass(), "JKK0451TPMA.op_svc_kei_no="	+ msgList[i].getString(CBS_OP_SVC_KEI_NAME));
			JSYejbLog.println(JSYejbLog.DEBUG, getClass(), "JKK0451TPMA.kktk_svc_kei_no=" + msgList[i].getString(CBS_KK_SVC_KEI_NAME));
		}

		// 更新年月日時分秒（更新前）の出力
		JSYejbLog.println(JSYejbLog.DEBUG, getClass(), "JEKK0461D010TPMA.upd_dtm_bf=" + updDtmBf);
	}

	/**
	* <p>
	* 機能コードがチェックのみの実行モードか判定します。<br>
	* 制約上、奇数は実行モード、偶数はチェックモードとして扱います。
	* </p>
	* @param func 機能コード
	* @return チェックモードの場合はtrue
	*/
	private boolean isFuncMode(String func)
	{
		int in = Integer.parseInt(func);
		boolean ret = (in % 2) == 0;
		return ret;
	}

	/**
	 * 取得したメッセージ内の最終更新年月日時分秒と更新年月日時分秒（更新前）が一致しているかを判定します。
	 * @param inList 更新年月日時分秒を保持しているリスト。
	 * @param updDtmBf タイムスタンプチェック用更新年月日時分秒（更新前）
	 * @return 指定された更新年月日時分秒（更新前）が最終更新年月日時分秒と一致した場合true。一致しない場合false。
	 */
	private boolean isTimeStampCheck(ArrayList<String> inList, String updDtmBf)
	{
		// 最終更新年月日時分秒を取得する
		String maxUpdDtm = getLastUpdDtm(inList);

		// 更新年月日時分秒(更新前)が未設定の場合はtrueを返却する。
		if(null == updDtmBf)
		{
			return true;
		}

		// 最終更新年月日時分秒と更新年月日時分秒（更新前）が一致している場合はtrueを返却する
		if (updDtmBf.equals(maxUpdDtm))
		{
			return true;
		}

		return false;
	}

	/**
	 * 対象のメッセージ内の更新年月日時分秒で最大のものを取得します。
	 * @param inList 更新年月日時分秒を保持しているリスト。
	 * @return 最終更新年月日時分秒。
	 */
	private String getLastUpdDtm(ArrayList<String> inList)
	{
		// 処理対象のリストをソートし、昇順になったソート順を降順に逆転させる
		Collections.sort(inList);
		Collections.reverse(inList);

		// 最大値を取得して返却
		return inList.get(0);
	}
	
	/**
	 * レコードロック対象となったサービス契約排他制御の全てのレコードを更新します。
	 * 更新対象項目は「最終更新年月日時分秒」、「更新年月日時分秒」、「更新オペレータアカウント」です。
	 * @param inMsg 更新年月日時分秒、オペレータアカウントを保持するETメッセージ。
	 * @param retList ロック対象のPK情報を保持するリスト（サービス契約排他制御）。
	 */
	private void updateKK2111(CAANMsg inMsg, ArrayList<String> retList)
	{
		// ロック対象全てのレコードの更新を行う
		for (int i = 0; i < retList.size(); i++)
		{
			// ETMsgを作成する
			CAANMsg inETMsg = new CAANMsg(KK2111ETMsg.class.getName());

			// 更新情報を設定
			inETMsg.set(KK2111ETMsg.SVC_KEI_NO, retList.get(i));
			inETMsg.set(KK2111ETMsg.LAST_UPD_DTM, inMsg.getString(KK2111ETMsg.UPD_DTM));
			inETMsg.set(KK2111ETMsg.UPD_DTM, inMsg.getString(KK2111ETMsg.UPD_DTM));
			inETMsg.set(KK2111ETMsg.UPD_OPEACNT, inMsg.getString(KK2111ETMsg.UPD_OPEACNT));

			// 更新処理を行う
			new JKKejbDBAUtil(inMsg).update(inETMsg);
		}
	}

	/**
	 * 関連制約エラーの設定を行います
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 */
	private void setError(CAANMsg inCBSMsg)
	{
		inCBSMsg.set(ERR_CONTENTS, ERR_FLG);
		inCBSMsg.set(JCMConstants.STATUS_INT_KEY, StatusCodes.RELATION_ERR);
	}

}