/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JCKEoAplCtrlBaseCC
*   ソースファイル名：JCKEoAplCtrlBaseCC.java
*   作成者          ：富士通
*   日付            ：2023年01月06日
*＜機能概要＞
*  指定された条件からeoアプリ制御を行う共通CCです。
*
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v64.00.00   2023/01/06   FJ)張本     【ANK-4316-00-00】ｅｏアプリ対応
**********************************************************************/
package com.fujitsu.futurity.bp.custom.common;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.fujitsu.futurity.bp.x21.bpm.ServiceComponentRequestInvoker;
import com.fujitsu.futurity.bp.x21.bpm.db.SessionHandle;
import com.fujitsu.futurity.bp.x21.bpm.exception.RequestParameterException;
import com.fujitsu.futurity.bp.x21.bpm.parameter.IRequestParameterReadWrite;
import com.fujitsu.futurity.bp.x21.cc.AbstractCommonComponent;
import com.fujitsu.futurity.bp.x21.cc.exception.SCCallException;
import com.fujitsu.futurity.common.JCMConstants;
import com.fujitsu.futurity.common.x01.sc.SCControlMapKeys;
import com.fujitsu.futurity.mapping.bp.common.TemplateErrorUtil;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.common.JCMAPLConstMgr;

import eo.common.constant.JKKStrConst;
import eo.common.constant.JPCModelConstant;
import eo.common.util.JKKStringUtil;
import eo.ejb.cbs.cbsmsg.ECK0011A010CBSMsg;
import eo.ejb.cbs.cbsmsg.EKK0021A010CBSMsg;
import eo.ejb.cbs.cbsmsg.EKK0021A010CBSMsg1List;
import eo.ejb.cbs.cbsmsg.EKK3291B010CBSMsg;
import eo.ejb.cbs.cbsmsg.EKK3291B010CBSMsg1List;

/**
*  指定された条件からeoアプリ制御を行う共通CCです。
 * <BR>
 * @ author 富士通
 */
public abstract class JCKEoAplCtrlBaseCC extends AbstractCommonComponent
{

	/**
	 * 開通済フラグ 初期値（空文字列）
	 */
	static final String OPEN_ZENGO_FLG_EMPTY = "";
	/**
	 * 開通済フラグが0
	 */
	static final String OPEN_ZENGO_FLG_0 = "0";
	/**
	 * 開通済フラグが1
	 */
	static final String OPEN_ZENGO_FLG_1 = "1";

	/** 作業用マップのキー：サービス契約一覧照会(SYSID) */
	static final String WORK_KEY_EKK0081B557CBSMSGLIST = "EKK0081B557CBSMsg1List";

	/** テンプレートID：申込情報一意照会 */
	private static final String TEMPLATE_ID_EKK0021A010 = "EKK0021A010";
	/** テンプレートID：コンテンツ申込情報一覧照会 */
	private static final String TEMPLATE_ID_EKK3291B010 = "EKK3291B010";
	/** テンプレートID：お客様一意照会 */
	private static final String TEMPLATE_ID_ECK0011A010 = "ECK0011A010";
	/** リターンメッセージ取得キー */
	private static final String RETURN_MESSAGE_STRING = "RETURN_MESSAGE_";
	/** リターンメッセージの書式指定文字列 */
	private static final String RETURN_MESSAGE_FORMAT = "%1$04d";
	/** エラー項目接尾辞 */
	private static final String ERRITEM_SUFFIX = "_err";

	/**
	 * 対象サービス判定 <br>
	 * @param svcCd サービスコード
	 * @param prcGrpCd 料金グループコード
	 * @param pcrsCd 料金コースコード
	 * @return
	 */
	protected boolean judgeTgSvc(String svcCd, String prcGrpCd, String pcrsCd)
	{
		return // eo光ネット/eoメールアドレス サービスコードと料金グループコードで判定
		(JKKStrConst.CD00130_01.equals(svcCd) && Arrays.asList(JKKStrConst.CD00133_02, JKKStrConst.CD00133_03, JKKStrConst.CD00133_04,
				JKKStrConst.CD00133_16).contains(prcGrpCd))
				||
				//  eo光TV（再送信除く/再送信多ch含む/KCN除く） 
				//   サービスコード＝テレビサービス(03) かつ 料金コースコード≠再送信(A23)かつ 料金グループコード≠KCN(12)
				(JKKStrConst.CD00130_03.equals(svcCd) && !JKKStrConst.CD00134_A23.equals(pcrsCd) && !JKKStrConst.CD00133_12.equals(prcGrpCd)) ||
				// eo光電話/eo電気/mineo
				Arrays.asList(JKKStrConst.CD00130_02, JKKStrConst.CD00130_05, JKKStrConst.CD00130_51).contains(svcCd);
	}

	/**
	 * 回線対象サービス判定 <br>
	 * @param svcCd サービスコード
	 * @param prcGrpCd 料金グループコード
	 * @param pcrsCd 料金コースコード
	 * @return
	 */
	protected boolean judgeTgKaisenSvc(String svcCd, String prcGrpCd, String pcrsCd)
	{
		return
		// eo光ネット サービスコードと料金グループコードで判定
		(JKKStrConst.CD00130_01.equals(svcCd) && Arrays.asList(JKKStrConst.CD00133_02, JKKStrConst.CD00133_03, JKKStrConst.CD00133_04).contains(
				prcGrpCd))
				||
				//  eo光TV（再送信除く/再送信多ch含む） サービスコード＝テレビサービス(03) かつ 料金コースコード≠再送信(A23)
				(JKKStrConst.CD00130_03.equals(svcCd) && !JKKStrConst.CD00134_A23.equals(pcrsCd)) ||
				// eo光電話
				Arrays.asList(JKKStrConst.CD00130_02).contains(svcCd);
	}

	/**
	 * 回線以外対象サービス判定 <br>
	 * @param svcCd サービスコード
	 * @param prcGrpCd 料金グループコード
	 * @return
	 */
	protected boolean judgeWithoutKaisenSvc(String svcCd, String prcGrpCd)
	{
		return
		// eoメールアドレス サービスコードと料金グループコードで判定
		(JKKStrConst.CD00130_01.equals(svcCd) && JKKStrConst.CD00133_16.equals(prcGrpCd)) ||
		// eo電気/mineo
				Arrays.asList(JKKStrConst.CD00130_05, JKKStrConst.CD00130_51).contains(svcCd);
	}

	/**
	 * 未開始同時申込コンテンツ判定 <br>
	 * @param svcCd サービスコード
	 * @param mskmDtlNo 申込明細番号
	 * @param sysid SYSID
	 * @return
	 * @throws Throwable 
	 */
	protected boolean judgeContMkmInfStcd01(SessionHandle handle, IRequestParameterReadWrite param, String fixedText, String mskmDtlNo, String sysid)
			throws Throwable
	{

		// 申込明細一意照会
		CAANMsg eKK0021A010CBSMsg = callEKK0021A010SC(handle, param, fixedText, mskmDtlNo);

		String mskmNo = eKK0021A010CBSMsg.getString(EKK0021A010CBSMsg1List.MSKM_NO);

		// パラメタのSYSIDと、申込情報のSYSIDが異なる場合
		if (!sysid.equals(eKK0021A010CBSMsg.getString(EKK0021A010CBSMsg1List.SYSID)))
		{
			// 判定対象外とする
			return false;
		}

		// コンテンツ申込情報一覧照会（申込番号）
		CAANMsg[] eKK3291B010CBSMsg1List = callEKK3291B010SC(handle, param, fixedText, mskmNo);

		int length = eKK3291B010CBSMsg1List != null ? eKK3291B010CBSMsg1List.length : 0;

		for (int i = 0; i < length; i++)
		{
			CAANMsg eKK3291B010CBSMsg = eKK3291B010CBSMsg1List[i];

			if ("01".equals(eKK3291B010CBSMsg.getString(EKK3291B010CBSMsg1List.CONT_MKM_INF_STCD)))
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * 申込情報一意照会サービスインターフェースを呼び出します。
	 * <br>
	 * @param handle セッションマネージャなどを持ったハンドル
	 * @param param モデルグループ、コントロールマップを含むパラメータオブジェクト
	 * @param fixedText ユーザ任意文字列
	 * @param mskmNo 申込明細番号
	 * @throws Throwable
	 */
	protected CAANMsg callEKK0021A010SC(SessionHandle handle, IRequestParameterReadWrite param, String fixedText, String mskmDtlNo) throws Throwable
	{
		// SC呼び出し部品のインスタンス生成
		ServiceComponentRequestInvoker scCall = new ServiceComponentRequestInvoker();

		Object[][] paramIn = { { EKK0021A010CBSMsg.TEMPLATEID, TEMPLATE_ID_EKK0021A010 }
		// 機能コード
				, { EKK0021A010CBSMsg.FUNC_CODE, JPCModelConstant.FUNC_CD_2 }
				// ＫＥＹ＿申込明細番号
				, { EKK0021A010CBSMsg.KEY_MSKM_DTL_NO, mskmDtlNo } };
		// サービスIF実行
		CAANMsg[] eKK0021A010CBSMsg1List = callSC(handle, scCall, param, fixedText, paramIn).getCAANMsgList(EKK0021A010CBSMsg.EKK0021A010CBSMSG1LIST);

		return eKK0021A010CBSMsg1List[0];
	}

	/**
	 * コンテンツ申込情報一覧照会サービスインターフェースを呼び出します。
	 * <br>
	 * @param handle セッションマネージャなどを持ったハンドル
	 * @param param モデルグループ、コントロールマップを含むパラメータオブジェクト
	 * @param fixedText ユーザ任意文字列
	 * @param mskmNo 申込番号
	 * @throws Throwable
	 */
	protected CAANMsg[] callEKK3291B010SC(SessionHandle handle, IRequestParameterReadWrite param, String fixedText, String mskmNo) throws Throwable
	{
		// SC呼び出し部品のインスタンス生成
		ServiceComponentRequestInvoker scCall = new ServiceComponentRequestInvoker();

		Object[][] paramIn = { { EKK3291B010CBSMsg.TEMPLATEID, TEMPLATE_ID_EKK3291B010 }
		// 機能コード
				, { EKK3291B010CBSMsg.FUNC_CODE, JPCModelConstant.FUNC_CD_1 }
				// ＫＥＹ＿申込番号
				, { EKK3291B010CBSMsg.KEY_MSKM_NO, mskmNo } };
		// サービスIF実行
		CAANMsg[] eKK3291B010CBSMsg1List = callSC(handle, scCall, param, fixedText, paramIn).getCAANMsgList(EKK3291B010CBSMsg.EKK3291B010CBSMSG1LIST);

		return eKK3291B010CBSMsg1List;
	}

	/**
	 * お客様一意照会サービスインターフェースを呼び出します。
	 * <br>
	 * @param handle セッションマネージャなどを持ったハンドル
	 * @param param モデルグループ、コントロールマップを含むパラメータオブジェクト
	 * @param fixedText ユーザ任意文字列
	 * @param sysid SYSID
	 * @param opeDate 運用日
	 * @return
	 * @throws Throwable
	 */
	protected CAANMsg[] callECK0011A010SC(SessionHandle handle, IRequestParameterReadWrite param, String fixedText, String sysid, String opeDate)
			throws Throwable
	{
		// SC呼び出し部品のインスタンス生成
		ServiceComponentRequestInvoker scCall = new ServiceComponentRequestInvoker();

		// 関連チェック(SYSID存在チェック)
		// お客様一意照会
		Object[][] eck0011a010In = { { ECK0011A010CBSMsg.TEMPLATEID, TEMPLATE_ID_ECK0011A010 }
		// 機能コード
				, { ECK0011A010CBSMsg.FUNC_CODE, JPCModelConstant.FUNC_CD_2 }
				// ＫＥＹ＿ＳＹＳＩＤ
				, { ECK0011A010CBSMsg.KEY_SYSID, sysid }
				// ＫＥＹ＿予約適用年月日
				, { ECK0011A010CBSMsg.KEY_RSV_APLY_YMD, opeDate } };

		// サービスIF実行
		CAANMsg[] eck0011a010MsgList = callSC(handle, scCall, param, fixedText, eck0011a010In).getCAANMsgList(ECK0011A010CBSMsg.ECK0011A010CBSMSG1LIST);

		return eck0011a010MsgList;
	}

	/**
	 * SC(サービスインターフェイス）を呼び出します。
	 * @param handle セッションハンドル
	 * @param scCall SC呼び出し部品
	 * @param param リクエストパラメータ
	 * @param dataMapKey パラメータキー
	 * @param mappingData マッピングデータ
	 * @return サービスインターフェイス実行結果
	 * @throws Throwable 例外が発生した場合
	 */
	@SuppressWarnings("unchecked")
	protected CAANMsg callSC(SessionHandle handle, ServiceComponentRequestInvoker scCall, IRequestParameterReadWrite param, String dataMapKey,
			Object[][] mappingData) throws Throwable
	{
		HashMap<String, Object> paramMap = editInMsg(param, mappingData);

		Map<?, ?> result = scCall.run(paramMap, handle);

		CAANMsg[] templates = (CAANMsg[])result.get(JCMConstants.TEMPLATE_LIST_KEY);

		CAANMsg msg = templates[0];

		// リターンコード取得
		Object RETURN_CODE = result.get(JCMConstants.RET_CD_INT_KEY);

		int status = msg.getInt(JCMConstants.STATUS_INT_KEY);

		editErrorInfoCom(param, templates, (Integer)RETURN_CODE, dataMapKey);

		//エラー情報のマップを取得
		ArrayList<Object> errList = (ArrayList<Object>)param.getControlMapData(SCControlMapKeys.ERROR_INFO);

		if (null == errList)
		{
			errList = new ArrayList<Object>();
		}

		// コントロールマップに設定
		param.setControlMapData(SCControlMapKeys.ERROR_INFO, TemplateErrorUtil.getErrorInfo(result, errList));

		// 異常の場合、SCCallExceptionを生成してスローする
		if (!("0".equals(RETURN_CODE.toString()) && 0 == status))
		{
			throw new SCCallException("戻り値不正", RETURN_CODE.toString(), status);
		}

		return msg;
	}

	/**
	 * 共通項目のメッセージを作成します。
	 * @param param リクエストパラメータ
	 * @param mappingData マッピングデータ
	 * @return HashMap<String, Object>
	 * @throws RequestParameterException リクエストパラメータの操作でエラーが発生した場合
	 */
	private HashMap<String, Object> editInMsg(IRequestParameterReadWrite param, Object[][] mappingData) throws RequestParameterException
	{
		HashMap<String, Object> paramMap = new HashMap<String, Object>();

		// 【取得元：電文ヘッダ(ヘッダ)】
		// 電文ID
		paramMap.put(JCMConstants.TRANZACTION_ID_KEY, param.getTelegramID());

		// ユースケースID
		paramMap.put(JCMConstants.USECASE_ID_KEY, param.getUsecaseID());

		// オペレーションID
		paramMap.put(JCMConstants.OPERATION_ID_KEY, param.getOperationID());

		// サービス呼び出し区分
		paramMap.put(JCMConstants.CALL_TYPE_KEY, param.getCallType());

		// 【取得元：ユーザエリア(コントロールマップ)】
		// 依頼先ホスト名
		paramMap.put(JCMConstants.CLIENT_HOST_NAME_KEY, param.getControlMapData(SCControlMapKeys.REQ_HOSTNAME));

		// 依頼元IPアドレス
		paramMap.put(JCMConstants.CLIENT_IP_ADDRESS_KEY, param.getControlMapData(SCControlMapKeys.REQ_HOSTIP));

		// 依頼元画面ID
		paramMap.put(JCMConstants.INVOKE_GAMEN_ID_KEY, param.getControlMapData(SCControlMapKeys.REQ_VIEWID));

		// オペレータID
		paramMap.put(JCMConstants.OPERATOR_ID_KEY, param.getControlMapData(SCControlMapKeys.OPERATOR_ID));

		String svcIf = (String)mappingData[0][1];

		CAANMsg template = new CAANMsg(String.format("eo.ejb.cbs.cbsmsg.%sCBSMsg", svcIf));

		// オペレータID
		template.set(JCMConstants.OPERATOR_ID_KEY, param.getControlMapData(SCControlMapKeys.OPERATOR_ID));

		// 運用日付
		template.set(JCMConstants.OPERATE_DATE_KEY, param.getControlMapData(SCControlMapKeys.OPE_DATE));

		// 運用日時
		template.set(JCMConstants.OPERATE_DATETIME_KEY, param.getControlMapData(SCControlMapKeys.OPE_TIME));

		for (int i = 0; i < mappingData.length; i++)
		{
			if (mappingData[i][1] instanceof CAANMsg[])
			{
				template.set((String)mappingData[i][0], (CAANMsg[])mappingData[i][1]);
			}
			else
			{
				if ("".equals(mappingData[i][1]))
				{
					template.setNull((String)mappingData[i][0]);
				}
				else
				{
					template.set((String)mappingData[i][0], mappingData[i][1]);
				}
			}
		}

		CAANMsg[] templates = new CAANMsg[1];

		templates[0] = template;

		paramMap.put(JCMConstants.TEMPLATE_LIST_KEY, templates);

		return paramMap;
	}

	/**
	 * エラー情報を取得します。
	 * @param param リクエストパラメータ
	 * @param templates CAANMsgクラス
	 * @param errorCode リターンコード
	 * @param dataMapKey パラメータキー
	 * @return IRequestParameterReadWrite
	 * @throws RequestParameterException リクエストパラメータの操作でエラーが発生した場合
	 */
	@SuppressWarnings("unchecked")
	private IRequestParameterReadWrite editErrorInfoCom(IRequestParameterReadWrite param, CAANMsg[] templates, int errorCode, String dataMapKey)
			throws RequestParameterException
	{
		CAANMsg template = templates[0];

		int templateStatus = template.getInt(JCMConstants.STATUS_INT_KEY);

		if (0 != errorCode)
		{
			templateStatus = 9000;
		}

		if (null == JCMAPLConstMgr.getString(RETURN_MESSAGE_STRING + String.format(RETURN_MESSAGE_FORMAT, templateStatus)))
		{
			templateStatus = 0;
		}

		int bpStatus = 0;

		Object obj = param.getControlMapData(SCControlMapKeys.RETURN_CODE);

		if (null == obj)
		{
			bpStatus = -1;
		}
		else
		{
			bpStatus = Integer.parseInt((String)param.getControlMapData(SCControlMapKeys.RETURN_CODE));
		}

		if (templateStatus > bpStatus)
		{
			// BPにサービスコンポーネントのステータスを設定する。
			String formatStatus = String.format(RETURN_MESSAGE_FORMAT, templateStatus);

			String message = JCMAPLConstMgr.getString(RETURN_MESSAGE_STRING + formatStatus);

			param.setControlMapData(SCControlMapKeys.RETURN_CODE, formatStatus);

			param.setControlMapData(SCControlMapKeys.RETURN_MESSAGE, message);
		}

		// ユーザデータ情報
		HashMap<String, Object> inMap = (HashMap<String, Object>)param.getData(dataMapKey);

		HashMap map = template.getHashMap();
		Iterator it = map.keySet().iterator();
		while (it.hasNext())
		{
			String key = (String)it.next();
			Object value = map.get(key);
			if (value instanceof HashMap[])
			{
				HashMap[] childMapList = (HashMap[])value;
				for (HashMap childMap : childMapList)
				{
					Iterator childIt = childMap.keySet().iterator();
					while (childIt.hasNext())
					{
						String childKey = (String)childIt.next();
						if (childKey.endsWith(ERRITEM_SUFFIX))
						{
							int keyIdx = childKey.lastIndexOf(ERRITEM_SUFFIX);
							if (inMap.containsKey(childKey.substring(0, keyIdx)))
							{
								inMap.put(childKey, childMap.get(childKey));
							}
						}
					}
				}
			}
			else
			{
				if (key.endsWith(ERRITEM_SUFFIX))
				{
					int keyIdx = key.lastIndexOf(ERRITEM_SUFFIX);
					if (inMap.containsKey(key.substring(0, keyIdx)))
					{
						inMap.put(key, map.get(key));
					}
				}
			}
		}

		return param;
	}

	/**
	 * 値がブランクのものを除外して設定。<br/>
	 * @param map パラメータ
	 */
	@SuppressWarnings("unchecked")
	public static void setMapString(Map map, String key, String value)
	{
		if (!JKKStringUtil.isNullBlank(value))
		{
			map.put(key, value);
		}
	}

	/**
	 * 値がブランクのものを除外して設定。<br/>
	 * @param map パラメータ
	 */
	@SuppressWarnings("unchecked")
	public static void setMapObject(Map map, String key, Object value)
	{
		if (value != null)
		{
			map.put(key, value);
		}
	}
}