/*********************************************************************
*   All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JEKK0401C180ETDA
*   ソースファイル名：JEKK0401C180ETDA.java
*   作成者          ：富士通
*   日付            ：2011年10月19日
*＜機能概要＞
*   サブオプションサービス契約解約確定のDBアクセス部品クラス
*＜修正履歴＞
*   バージョン  修正日      修正者      修正内容
*   v1.00.00    2011/10/19  富士通      新規作成
*   v4.00.00    2013/04/01  FJ)寺園     ST2-2013-0001542
*   v4.00.01    2013/05/02  FJ)寺本     IT1-2013-0001110
*   v5.00.00    2013/07/03  FJ）沖田    KT1-2013-0000691
*   v8.00.00    2014/06/11  FJ)小島     OM-2014-0002105
*
**********************************************************************/

package eo.ejb.common.db;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fujitsu.futurity.common.JCMConstants;
import com.fujitsu.futurity.model.base.CAANException;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.base.CAANRuntimeException;
import com.fujitsu.futurity.model.ejb.common.StatusCodes;
import com.fujitsu.futurity.model.ejb.common.fw.AgentDispatchContext;

import eo.common.util.JPCUtilCommon;
import eo.ejb.cbm.entity.KK0401ETMsg;
import eo.ejb.cbm.entity.KK1681ETMsg;
import eo.ejb.cbm.entity.KK1681LE;
import eo.ejb.cbs.cbsmsg.EKK0401C180CBSMsg;
import eo.ejb.cbs.mainproc.JKKejbIdoRsvUtil;
import eo.ejb.common.JKKModelCommon;
import eo.ejb.common.rule.JKKejbRule0083001;

/**
 * <p>
 * サブオプションサービス契約解約確定のDBアクセス部品クラスです。
 * </p>
 * @author 富士通
 */
public class JEKK0401C180ETDA
{
	/** 異動予約詳細コード サブオプション解約 */
	private static final String DTLCD_SBOPDISSOLVE = "018";
	
	/** 異動予約状態コード 反映済 */
	private static final String STATCD_DONE = "01";
	
	/** 異動予約状態コード 予約手続中 */
	private static final String STATCD_RSV_PROC = "03";
	
	/** 無効フラグ 有効 */
	private static final String MK_FLG_VALID = "0";
	
	/** 予約適用コード 予約確定 */
	private static final String RSVAPLY_DECIDED = "2";
	
	/** サブオプションサービス契約ステータス 解約済 */
	private static final String SBOP_STAT_DISSOLVE = "910";

	/** サブオプションサービス契約ステータス 締結済 */
	private static final String SBOP_STAT_TEIKETUZUMI = "030";
	
	/** スキーマID サブオプションサービス契約 */
	private static final String SCHEMAID_OP_SVCKEI = "KK0401";
	
	/** スキーマID 異動予約 */
	private static final String SCHEMAID_IDORSV = "KK1681";
	
	/**
	 * <p>
	 * 新しいJEKK0401C180ETDAを作成します。
	 * </p>
	 */
	public JEKK0401C180ETDA()
	{
	}

	/**
	 * <p>
	 * 相関ルールにて振舞判定を行い、サブオプションサービス契約または異動予約にDBアクセスを行います。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 */
	public void execDBAccess(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		// 相関ルールにて振舞うスキーマを判定
		JKKejbRule0083001 rule0083 = new JKKejbRule0083001(inCBSMsg);
		rule0083.setSvc_if_id(inCBSMsg.getString(JCMConstants.TEMPLATE_ID_KEY));
		
		String baseDate = inCBSMsg.getString(EKK0401C180CBSMsg.SVC_ENDYMD);
		String opeDate = JKKModelCommon.getOpeDate(inCBSMsg);
		
		rule0083.setBase_date(baseDate);
		rule0083.setOpe_date(opeDate);
		
		List<HashMap<String, Object>> ruleList = rule0083.referRuleEngine();
		
		if (ruleList == null)
		{
			// 相関ルールチェックの結果が0件の場合はエラーとする
			inCBSMsg.set(EKK0401C180CBSMsg.OP_SVC_KEI_NO_ERR, "EA");
			inCBSMsg.set(JCMConstants.STATUS_INT_KEY, StatusCodes.TEMPLATE_CORRELATION_ERR);
			return;
		}
		
		// 相関ルールチェック結果を格納
		new JKKejbIdoRsvUtil().setOnlyIdoRsvFlg(inCBSMsg, inContext, ruleList);
		
		CAANMsg updateInfo = null;
		
		for (HashMap<String, Object> hm : ruleList)
		{
			if (SCHEMAID_OP_SVCKEI.equals(hm.get(JKKejbRule0083001.TRGT_SCHEMA_ID)))
			{
				// サブオプションサービス契約に振舞う場合
				updateInfo = makeKK0401ETMsg(inCBSMsg, inContext);

				// 更新内容がnullの場合
				if (updateInfo == null)
				{
					return;
				}

				create(inCBSMsg, updateInfo);

				// サブオプションサービス契約に振舞った場合の個別出力項目の設定
				inCBSMsg.set(EKK0401C180CBSMsg.GENE_ADD_DTM, updateInfo.getString(KK0401ETMsg.GENE_ADD_DTM));
				inCBSMsg.set(EKK0401C180CBSMsg.SBOP_SVC_KEI_STAT, updateInfo.getString(KK0401ETMsg.SBOP_SVC_KEI_STAT));
			}
			if (SCHEMAID_IDORSV.equals(hm.get(JKKejbRule0083001.TRGT_SCHEMA_ID)))
			{
				// 異動予約に振舞う場合
				updateInfo = makeKK1681ETMsg(inCBSMsg, hm, DTLCD_SBOPDISSOLVE, STATCD_RSV_PROC);
				update(inCBSMsg, updateInfo);
			}
		}

		// 出力項目の設定
		setOutputItem(inCBSMsg, updateInfo);
	}
	
	/**
	 * <p>
	 * DBの登録を行います。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @param inETMsg 登録対象DBのメッセージキャリア(ETメッセージ)
	 */
	private void create(CAANMsg inCBSMsg, CAANMsg inETMsg)
	{
		JKKejbDBAUtil dba = new JKKejbDBAUtil(inCBSMsg);
		
		// レコード登録
		dba.create(inETMsg);
	}

	/**
	 * <p>
	 * DBの更新を行います。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @param inETMsg 更新対象DBのメッセージキャリア(ETメッセージ)
	 */
	private void update(CAANMsg inCBSMsg, CAANMsg inETMsg)
	{
		JKKejbDBAUtil dba = new JKKejbDBAUtil(inCBSMsg);
		
		// レコード更新
		dba.update(inETMsg);
	}
	
	/**
	 * <p>
	 * サブオプションサービス契約に設定するETメッセージを作成します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @return サービス契約に設定する内容が設定されたETメッセージ
	 */
	private CAANMsg makeKK0401ETMsg(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		String opSvcKeiNo = inCBSMsg.getString(EKK0401C180CBSMsg.OP_SVC_KEI_NO);
		String sbOpSvcKeiNo = inCBSMsg.getString(EKK0401C180CBSMsg.SBOP_SVC_KEI_NO);
		String geneAddDtm = (String)JKKModelCommon.getTransferGeneAddDtm(inCBSMsg, inContext);
		
		// 引継元となるカレントレコードを取得
		CAANMsg infoKK0401 = getCurKK0401(inCBSMsg);
		
		Object svcChrgStaymd = JKKModelCommon.getChrgStaYmdEKK0401C180(inCBSMsg, inContext);
		String sbopSvcKeiStat = infoKK0401.getString(KK0401ETMsg.SBOP_SVC_KEI_STAT);
		// サブオプションサービス契約ステータスが締結済以外かつサービス課金開始日が未設定の場合はエラーとする
		if (!SBOP_STAT_TEIKETUZUMI.equals(sbopSvcKeiStat) && (svcChrgStaymd == null || svcChrgStaymd.toString().length() == 0))
		{
			// 相関エラーのステータスを設定
			inCBSMsg.set(EKK0401C180CBSMsg.SBOP_SVC_KEI_NO_ERR, "EC");
			inCBSMsg.set(EKK0401C180CBSMsg.STATUS, StatusCodes.RELATION_ERR);
			return null;
		}
		
		// サブオプションサービス契約番号に紐付く「異動予約詳細コード」が"サブオプション解約"、
		// 「異動予約状態コード」が"予約手続中"の異動予約を取得
		CAANMsg infoKK1681 = getIdoRsv(sbOpSvcKeiNo, DTLCD_SBOPDISSOLVE, STATCD_RSV_PROC);
		
		// サブオプションサービス契約のETメッセージ
		infoKK0401.set(KK0401ETMsg.OP_SVC_KEI_NO, opSvcKeiNo);
		infoKK0401.set(KK0401ETMsg.SBOP_SVC_KEI_NO, sbOpSvcKeiNo);
		infoKK0401.set(KK0401ETMsg.GENE_ADD_DTM, geneAddDtm);
		infoKK0401.set(KK0401ETMsg.SBOP_SVC_KEI_STAT, SBOP_STAT_DISSOLVE);
		infoKK0401.set(KK0401ETMsg.MSKM_DTL_NO, infoKK1681.getString(KK1681ETMsg.MSKM_DTL_NO));
		String opedate = JKKModelCommon.getOpeDate(inCBSMsg);
		String rsvAplyYmd = null;
		// 運用日 ＞ サービス終了年月日の場合
		if (JPCUtilCommon.isPastDate(inCBSMsg.getString(EKK0401C180CBSMsg.SVC_ENDYMD), opedate, "1"))
		{
			rsvAplyYmd = opedate;
		}
		else
		{
			rsvAplyYmd = inCBSMsg.getString(EKK0401C180CBSMsg.SVC_ENDYMD);
		}
		infoKK0401.set(KK0401ETMsg.RSV_APLY_YMD, rsvAplyYmd);
		infoKK0401.setNull(KK0401ETMsg.RSV_CL_YMD);
		infoKK0401.set(KK0401ETMsg.RSV_APLY_CD, RSVAPLY_DECIDED);
		// プラン終了年月日
		String svcEndYmd = (String) JKKModelCommon.getYmdDslFix(inCBSMsg, inCBSMsg.getString(EKK0401C180CBSMsg.SVC_ENDYMD));
		infoKK0401.set(KK0401ETMsg.PLAN_ENDYMD, svcEndYmd);
		
		// サブオプションサービス契約ステータスが締結済の場合はカレント引継
		if (!SBOP_STAT_TEIKETUZUMI.equals(sbopSvcKeiStat)){
			infoKK0401.set(KK0401ETMsg.PLAN_CHRG_STAYMD, svcChrgStaymd);
		}
		// プラン課金終了年月日
		infoKK0401.set(KK0401ETMsg.PLAN_CHRG_ENDYMD, inCBSMsg.getString(EKK0401C180CBSMsg.SVC_CHRG_ENDYMD));
		
		// サブオプションサービス契約ステータスが締結済の場合はカレント引継
		if (!SBOP_STAT_TEIKETUZUMI.equals(sbopSvcKeiStat)){
			infoKK0401.set(KK0401ETMsg.SVC_CHRG_STAYMD, svcChrgStaymd);
		}
		infoKK0401.setNull(KK0401ETMsg.PLAN_END_SBT_CD);
		// サービス終了年月日
		infoKK0401.set(KK0401ETMsg.SVC_ENDYMD, svcEndYmd);
		// サービス課金終了年月日
		infoKK0401.set(KK0401ETMsg.SVC_CHRG_ENDYMD, inCBSMsg.getString(EKK0401C180CBSMsg.SVC_CHRG_ENDYMD));
		// サービス解約年月日
		infoKK0401.set(KK0401ETMsg.SVC_DSL_YMD, svcEndYmd);
		infoKK0401.set(KK0401ETMsg.SVC_DLRE_CD, inCBSMsg.getString(EKK0401C180CBSMsg.SVC_DLRE_CD));
		infoKK0401.set(KK0401ETMsg.SVC_DLRE_MEMO, inCBSMsg.getString(EKK0401C180CBSMsg.SVC_DLRE_MEMO));
		infoKK0401.setNull(KK0401ETMsg.SVC_DSL_TTDKI_FIN_FLG);
		infoKK0401.setNull(KK0401ETMsg.KAIHK_YMD);
		infoKK0401.setNull(KK0401ETMsg.SVC_DSL_CL_YMD);
		infoKK0401.set(KK0401ETMsg.PNLTY_HASSEI_CD, infoKK1681.getString(KK1681ETMsg.PNLTY_HASSEI_CD));
		infoKK0401.set(KK0401ETMsg.IDO_DIV, infoKK1681.getString(KK1681ETMsg.IDO_DIV));
		infoKK0401.set(KK0401ETMsg.ADD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		infoKK0401.set(KK0401ETMsg.ADD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		infoKK0401.set(KK0401ETMsg.UPD_DTM, inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		infoKK0401.set(KK0401ETMsg.UPD_OPEACNT, inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));
		infoKK0401.setNull(KK0401ETMsg.DEL_DTM);
		infoKK0401.setNull(KK0401ETMsg.DEL_OPEACNT);
		infoKK0401.set(KK0401ETMsg.MK_FLG, MK_FLG_VALID);
		
		return infoKK0401;
	}
	
	/**
	 * <p>
	 * 異動予約に設定するETメッセージを作成します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param ruleMap 相関ルールチェック結果のマップクラス
	 * @param idoRsvDtlCd 検索する異動予約詳細コード
	 * @param idoRsvStatCd 検索する異動予約状態コード
	 * @return 異動予約に設定する内容が設定されたETメッセージ
	 */
	private CAANMsg makeKK1681ETMsg(CAANMsg inCBSMsg, Map<String, Object> ruleMap
										, String idoRsvDtlCd, String idoRsvStatCd)
	{
		// 異動予約番号を取得
//2011.10.26 仕様変更のため、コメントアウト
//		String opSvcKeiNo = inCBSMsg.getString(EKK0401C180CBSMsg.OP_SVC_KEI_NO);
//		CAANMsg infoKK1681 = getIdoRsv(opSvcKeiNo, idoRsvDtlCd, idoRsvStatCd);
		String sbOpSvcKeiNo = inCBSMsg.getString(EKK0401C180CBSMsg.SBOP_SVC_KEI_NO);
		CAANMsg infoKK1681 = getIdoRsv(sbOpSvcKeiNo, idoRsvDtlCd, idoRsvStatCd);
		
		String ruleStatCd = (String)ruleMap.get(JKKejbRule0083001.IDO_RSV_STAT_CD);
		
		// 異動予約のETメッセージ
		CAANMsg kk1681ETMsg = new CAANMsg(KK1681ETMsg.class.getName());
		kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_NO, infoKK1681.getString(KK1681ETMsg.IDO_RSV_NO));
		String opedate = JKKModelCommon.getOpeDate(inCBSMsg);
		String rsvAplyYmd = null;
		// 運用日 ＞ サービス終了年月日の場合
		if (JPCUtilCommon.isPastDate(inCBSMsg.getString(EKK0401C180CBSMsg.SVC_ENDYMD), opedate, "1"))
		{
			rsvAplyYmd = opedate;
		}
		else
		{
			rsvAplyYmd = inCBSMsg.getString(EKK0401C180CBSMsg.SVC_ENDYMD);
		}
		kk1681ETMsg.set(KK1681ETMsg.RSV_APLY_YMD, rsvAplyYmd);

		if (STATCD_DONE.equals(ruleStatCd))
		{
			// 即時反映(異動予約状態コードが反映済)の場合、異動予約反映年月日を設定
			kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_HANEI_YMD, rsvAplyYmd);
		}
		
		kk1681ETMsg.set(KK1681ETMsg.IDO_RSV_STAT_CD, ruleMap.get(JKKejbRule0083001.IDO_RSV_STAT_CD));
		kk1681ETMsg.set(KK1681ETMsg.UPD_DTM , inCBSMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		kk1681ETMsg.set(KK1681ETMsg.UPD_OPEACNT , inCBSMsg.getString(JCMConstants.OPERATOR_ID_KEY));

		// 異動区分、申込明細番号を出力に設定
		inCBSMsg.set(EKK0401C180CBSMsg.IDO_DIV, infoKK1681.getString(KK1681ETMsg.IDO_DIV));
		inCBSMsg.set(EKK0401C180CBSMsg.MSKM_DTL_NO, infoKK1681.getString(KK1681ETMsg.MSKM_DTL_NO));
		
		return kk1681ETMsg;
	}
	
	/**
	 * <p>
	 * CBSメッセージの出力項目に値を設定します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @param inETMsg DBに設定した内容を持っているETメッセージ
	 */
	private void setOutputItem(CAANMsg inCBSMsg, CAANMsg inETMsg)
	{
		inCBSMsg.set(EKK0401C180CBSMsg.UPD_DTM, inETMsg.getString(JCMConstants.OPERATE_DATETIME_KEY));
		inCBSMsg.set(EKK0401C180CBSMsg.UPD_OPEACNT, inETMsg.getString(JCMConstants.OPERATOR_ID_KEY));
	}

	/**
	 * <p>
	 * サブオプションサービス契約のカレントレコードを取得します。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア(CBSメッセージ)
	 * @return オプションサービス契約のカレントレコード
	 */
	private CAANMsg getCurKK0401(CAANMsg inCBSMsg)
	{
		// サブオプションサービス契約のカレントレコードを取得
		CAANMsg et = new CAANMsg(KK0401ETMsg.class.getName());
		et.set(KK0401ETMsg.OP_SVC_KEI_NO, inCBSMsg.getString(EKK0401C180CBSMsg.OP_SVC_KEI_NO));
		et.set(KK0401ETMsg.SBOP_SVC_KEI_NO, inCBSMsg.getString(EKK0401C180CBSMsg.SBOP_SVC_KEI_NO));
		et.set(KK0401ETMsg.RSV_APLY_YMD, JKKModelCommon.getOpeDate(inCBSMsg));
		
		CAANMsg curKK0401 = new JKKejbKK0401DBABase().findByCurrent(et);

		return curKK0401;
	}

	/**
	 * <p>
	 * 下記項目を条件に異動予約を取得します。
	 * <br>・サブオプションサービス契約番号
	 * <br>・異動予約詳細コード
	 * <br>・異動予約状態コード
	 * </p>
	 * @param sbopSvcKeiNo 検索するサブオプションサービス契約番号
	 * @param idoRsvDtlCd 検索する異動予約詳細コード
	 * @param idoRsvStatCd 検索する異動予約状態コード
	 * @return 条件に該当する異動予約
	 *          条件に該当する異動予約がない場合、nullを返却
	 */
	private CAANMsg getIdoRsv(String sbopSvcKeiNo, String idoRsvDtlCd, String idoRsvStatCd)
	{
		// 条件を設定
		KK1681LE le = new KK1681LE();
		CAANMsg conditionETMsg = new CAANMsg(KK1681ETMsg.class.getName());
//2011.10.26 仕様変更のため、コメントアウト
//		conditionETMsg.set(KK1681ETMsg.OP_SVC_KEI_NO, kktkSvcKeiNo);
		conditionETMsg.set(KK1681ETMsg.SBOP_SVC_KEI_NO, sbopSvcKeiNo);
		conditionETMsg.set(KK1681ETMsg.IDO_RSV_DTL_CD, idoRsvDtlCd);
		conditionETMsg.set(KK1681ETMsg.IDO_RSV_STAT_CD, idoRsvStatCd);
		conditionETMsg.set(KK1681ETMsg.MK_FLG, MK_FLG_VALID);
		
		CAANMsg[] kk1681MsgList = null;

		try
		{
			kk1681MsgList = le.findByCondition(conditionETMsg);
		}
		catch (CAANException ce)
		{
			// エラーが発生した場合、nullを返却
			return null;
		}

		/* ----------------------------------------------------------------------------------------------------
		 * 複数の「異動予約」(異動予約詳細コード＝"解約")が存在する場合、
		 * 異動区分、申込明細番号などを入力項目(必須)として、更新対象の「異動予約」を特定する必要があるが、
		 * 現時点では、入力値が存在しないため、異動予約番号が最大の「異動予約」を更新対象とする。
		 * ---------------------------------------------------------------------------------------------------- */
		// 更新対象「異動予約」
		CAANMsg updTgKK1681Msg = null;
		// 更新対象「異動予約」の異動予約番号
		String updTgIdoRsvNo = null;

		for (CAANMsg kk1681Msg : kk1681MsgList)
		{
			String idoRsvNo = kk1681Msg.getString(KK1681ETMsg.IDO_RSV_NO);
			if (updTgIdoRsvNo == null || updTgIdoRsvNo.compareTo(idoRsvNo) < 0)
			{
				updTgIdoRsvNo = idoRsvNo;
				updTgKK1681Msg = kk1681Msg;
			}
		}
		if (updTgKK1681Msg == null)
		{
			throw new CAANRuntimeException("解約確定対象のサブオプションサービス契約に対する異動予約が存在しません。サブオプションサービス契約番号:" + sbopSvcKeiNo);
		}

		return updTgKK1681Msg;
	}
}
