/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JFUShokaishaCheckCC
*   ソースファイル名：JFUShokaishaCheckCC.java
*   作成者          ：富士通
*   日付            ：2015年4月7日
*＜機能概要＞
*   紹介者チェックコモンコンポーネント部品
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v14.00      2015/04/07   FJ）張本    新規作成
*   v41.00      2019/02/26   FJ）松原    【ANK-3548-00-00】紹介コードの事前発番対応
*   v50.00      2020/09/01   FJ) 美濃原  【ANK-3917-00-00】提携先企業向けエントリーコードの導入
*   v62.00      2022/11/16   FJ) 大槻    【ANK-4294-00-00】紹介CP仕組み変更対応
**********************************************************************/
package com.fujitsu.futurity.bp.custom.common;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

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 eo.common.constant.JFUStrConst;
import eo.common.constant.JPCModelConstant;
import eo.ejb.cbs.cbsmsg.EKK0081B532CBSMsg;
import eo.ejb.cbs.cbsmsg.EKK0081B532CBSMsg1List;
import eo.ejb.cbs.cbsmsg.EKK0311A010CBSMsg;
import eo.ejb.cbs.cbsmsg.EKK0311A010CBSMsg1List;

/**
 * 紹介者チェックコモンコンポーネント部品
 * 
 * <br>
 * @author 富士通
 */
@SuppressWarnings("unchecked")
public class JFUShokaishaCheckCC extends JFUBaseCC
{
	
	/* ■□ EKK0311A010_紹介一意照会 ■□ */
	/** テンプレートID(紹介一意照会) */
	private static final String TEMP_ID_EKK0311A010 = "EKK0311A010";
	/** テンプレートID(紹介一意照会明細) */
	private static final String TEMP_ID_DTL_EKK0311A010 = EKK0311A010CBSMsg.EKK0311A010CBSMSG1LIST;
	/** IN項目リスト(紹介一意照会) */
	private static final List<String> IN_COL_LIST_EKK0311A010 = Arrays.asList(EKK0311A010CBSMsg.KEY_INTR_CD);
	/** 関連チェックエラー項目(紹介一意照会) */
	private static final String ERR_COL_EKK0311A010 = EKK0311A010CBSMsg.KEY_INTR_CD_ERR;
	/** SC実行結果取得キー(紹介一意照会) */
	private static final String TEMP_TEMP_KEY_EKK0311A010 = TEMP_TEMPLATE_PRIFIX + TEMP_ID_EKK0311A010 + TEMP_TEMPLATE_PRIFIX_SEP;

	/* ■□ EKK0081B532_サービス契約一覧照会（紹介コード） ■□ */
	/** テンプレートID(サービス契約一覧照会（紹介コード）) */
	private static final String TEMP_ID_EKK0081B532 = "EKK0081B532";
	/** テンプレートID(サービス契約（紹介コード）明細) */
	private static final String TEMP_ID_DTL_EKK0081B532 = EKK0081B532CBSMsg.EKK0081B532CBSMSG1LIST;
	/** IN項目リスト(サービス契約一覧照会（紹介コード）) */
	private static final List<String> IN_COL_LIST_EKK0081B532 = Arrays.asList(EKK0081B532CBSMsg.KEY_INTR_CD);
	/** 関連チェックエラー項目(サービス契約一覧照会（紹介コード）) */
	private static final String ERR_COL_EKK0081B532 = EKK0081B532CBSMsg.KEY_INTR_CD_ERR;
	/** SC実行結果取得キー(サービス契約一覧照会（紹介コード）) */
	private static final String TEMP_TEMP_KEY_EKK0081B532 = TEMP_TEMPLATE_PRIFIX + TEMP_ID_EKK0081B532 + TEMP_TEMPLATE_PRIFIX_SEP;

	// ■ IN項目ID ■
	/** IN項目ID：紹介コード */
	private static final String IN_INTR_CD = "intr_cd";

	/** IN項目ID：クーポンコード */
	private static final String IN_COUPON_CD = "coupon_cd";

	/** IN項目ID：コード識別子 */
	private static final String IN_CD_SKBTS = "cd_skbts";

	/** IN項目ID：氏名（姓） */
	private static final String IN_NAME_LAST = "name_last";

	// ■ OUT項目ID ■
	/** OUT項目ID：結果コード */
	private static final String RETURN_CD = "return_cd";
	/** OUT項目ID：結果コード(画面からのクーポンコードチェック用) */
	private static final String RETURN_CD2 = "return_cd2";

	/** 紹介コード独自チェック対象コード */
	private static final String RETURN_TUJYO_CD = "return_tujyo_cd";
	/** 紹介コード独自チェック対象コード 1:紹介コード独自チェック対象、1以外：紹介コード独自チェック対象外 */
	private static final String RETURN_TUJYO_CD_1 = "1";

	/** 結果コード：正常 */
	private static final String RETURN_CD_0 = "0";
	/** 結果コード：データなしエラー */
	private static final String RETURN_CD_1 = "1";
	/** 結果コード：整合性エラー */
	private static final String RETURN_CD_2 = "2";
	/** 結果コード：有効期限切れエラー */
	private static final String RETURN_CD_3 = "3";
	/** 結果コード：使用済みエラー */
	private static final String RETURN_CD_4 = "4";
	/** 結果コード：コード識別子エラー */
	private static final String RETURN_CD_5 = "5";

	/* ■□ その他 ■□ */
	/** 紹介コードチェック */
	private static final String INTR_CD_CHECK = "[A-Z][0-9]{9}";

	/**
	 * 紹介コード／クーポンコードの有効性チェック実行処理
	 * 
	 * <br>
	 * @param handle セッションハンドル
	 * @param param リクエストパラメータ
	 * @param fixedText サービスメッセージ
	 * @return リクエストパラメータ管理クラス
	 * @throws Exception 例外
	 */
	public IRequestParameterReadWrite chkShokaishaName(SessionHandle handle, IRequestParameterReadWrite param, String fixedText) throws Exception
	{

		// ユーザデータ取得
		HashMap inMap = (HashMap)param.getData(fixedText);

		String inIntrCd = (String)inMap.get(IN_INTR_CD);
		String inCdSkbts = (String)inMap.get(IN_CD_SKBTS);
		String inCouponCd = (String)inMap.get(IN_COUPON_CD);

		// ●結果格納マップ
		HashMap resultMap = new HashMap();

		if (!JFUBPCommon.isNull(inIntrCd))
		{
			// 紹介コードが設定されている場合

			if (JFUStrConst.COUPON_CD_CD_SKBTS.equals(inCdSkbts))
			{
				// コード識別子が「01：クーポンコード」の場合

				//「FUIFE198_紹介コード有効性チェック」からの呼び出し時
				resultMap = chkIntrCd(handle, param, fixedText, inMap, resultMap, inCouponCd, true);
			}
			else
			{
				// コード識別子が紹介コードの場合

				// フロント(一般WEB／量販訪販WEB)画面で紹介コード入力時と「FUIFE198_紹介コード有効性チェック」からの呼び出し時
				resultMap = chkIntrCd(handle, param, fixedText, inMap, resultMap, inIntrCd, false);
			}
		}

		if (!JFUBPCommon.isNull(inCouponCd))
		{
			// クーポンコードの場合
			// ●結果格納マップ
			HashMap resultMap2 = new HashMap();

			// フロント(一般WEB／量販訪販WEB)画面でクーポンコード入力時
			resultMap2 = chkIntrCd(handle, param, fixedText, inMap, resultMap2, inCouponCd, true);
			// クーポンコードは「"return_cd2"」として結果を格納
			resultMap.put(RETURN_CD2, resultMap2.get(RETURN_CD));
		}

		// ●リクエストパラメータに結果を格納
		param.removeData(fixedText);
		param.setData(fixedText, resultMap);

		return param;
	}

	/**
	 * 紹介コード／クーポンコードの有効性チェック実行処理
	 * 
	 * @param handle セッションハンドル
	 * @param param リクエストパラメータ
	 * @param fixedText サービスメッセージ
	 * @param inMap リクエスト情報
	 * @param resultMap 処理結果Map
	 * @param inIntrCd 紹介コード、クーポンコード
	 * @param isCouponCd true:クーポンコード、false:紹介コード
	 * @return リクエストパラメータ管理クラス
	 * @throws Exception 例外
	 */
	private HashMap chkIntrCd(SessionHandle handle, 
			IRequestParameterReadWrite param, String fixedText, HashMap inMap, HashMap resultMap, String inIntrCd,
			boolean isCouponCd) throws Exception
	{
		resultMap.put(RETURN_TUJYO_CD, JFUStrConst.EMPTY);

		// ○EKK0311A010_紹介一意照会
		// ユーザデータ初期化
		initData(param, fixedText, IN_COL_LIST_EKK0311A010);
		// 上りマッピング
		setInMapEKK0311A010(param, fixedText, inIntrCd);
		//検索エラーなし設定
		ignoreSearchError(param, fixedText);
		// サービスIF実行
		executeSC(handle, param, fixedText, TEMP_ID_EKK0311A010, TEMP_ID_DTL_EKK0311A010, IN_COL_LIST_EKK0311A010, ERR_COL_EKK0311A010);

		// データが存在するか
		if (isExistsTemplateDetail(inMap, getMaxTempTempleteKey(inMap, TEMP_TEMP_KEY_EKK0311A010), TEMP_ID_DTL_EKK0311A010))
		{

			// マップを取得
			HashMap EKK0311A010Map = getTemplateListMap(inMap, getMaxTempTempleteKey(inMap, TEMP_TEMP_KEY_EKK0311A010), TEMP_ID_DTL_EKK0311A010, 0);
			// コード識別子を取得。紹介コード／クーポンコードかの判定用
			String cdSkbts = JFUBPCommon.nvl((String)EKK0311A010Map.get(EKK0311A010CBSMsg1List.CD_SKBTS), JFUStrConst.EMPTY).trim();

			// クーポンコード使用済みチェック
			// 紹介スキーマのサービス契約番号（申込者）が未設定の場合「true:未使用」、存在する場合「false:使用済」と判定。
			boolean isDisusedCouponCd =
					JFUBPCommon.isNull(JFUBPCommon.nvl((String)EKK0311A010Map.get(EKK0311A010CBSMsg1List.SVC_KEI_NO_MSKMSHA), JFUStrConst.EMPTY).trim());

			// 被紹介者名を取得
			String hishokaiName = JFUBPCommon.nvl((String)EKK0311A010Map.get(EKK0311A010CBSMsg1List.HISHOKAI_NM), JFUStrConst.EMPTY).trim();

			// 通常の紹介コードかの判定、業務パラメータから取得して前方一致するかを判定する。
			boolean isTujyoIntrCd = chkFrontMatch(JFUBPCommon.getWorkParamSplit(handle, param, JFUStrConst.KK_INTRCD_CHK_TG), inIntrCd);

			// eoエントリーコード（有効期限あり）かの判定、業務パラメータから取得して前方一致するかを判定する。
			boolean isEoEntryCd = chkFrontMatch(JFUBPCommon.getWorkParamSplit(handle, param, JFUStrConst.FU_EO_ENTRY_YK_KIGEN), inIntrCd);

			String inNameLast = JFUBPCommon.nvl((String)inMap.get(IN_NAME_LAST), JFUStrConst.EMPTY);

			if ((isCouponCd && !JFUStrConst.COUPON_CD_CD_SKBTS.equals(cdSkbts)) || (!isCouponCd && JFUStrConst.COUPON_CD_CD_SKBTS.equals(cdSkbts)))
			{
				// クーポンコードで紹介スキーマの識別子が「01:クーポンコード」以外の場合
				// またはクーポンコード以外で紹介スキーマの識別子が「01:クーポンコード」の場合

				// 結果コード：コード識別子エラー
				resultMap.put(RETURN_CD, RETURN_CD_5);
			}
			// ■eoエントリーコード（有効期限あり）の場合
			else if (isEoEntryCd)
			{
				// 有効期限年月日取得
				String ykKigenYmd = (String)EKK0311A010Map.get(EKK0311A010CBSMsg1List.YK_KIGEN_YMD);
				// 運用日付取得
				String opeDate = JFUBPCommon.getOpeDate(null);
				if (Integer.parseInt(opeDate) > nullToZero(ykKigenYmd))
				{
					// 結果コード：有効期限切れエラー
					resultMap.put(RETURN_CD, RETURN_CD_3);
				}
				else if (isDisusedCouponCd)
				{
					// クーポンコード未使用の場合

					// 結果コード：正常
					resultMap.put(RETURN_CD, RETURN_CD_0);
				}
				else
				{
					// クーポンコード使用済の場合

					// 結果コード：使用済みエラー
					resultMap.put(RETURN_CD, RETURN_CD_4);
				}
			}
			// ■紹介コードが｢英字1文字 + 数字9桁｣の場合（プレクラ用）
			else if (inIntrCd.matches(INTR_CD_CHECK))
			{
				// 有効期限年月日取得
				String ykKigenYmd = (String)EKK0311A010Map.get(EKK0311A010CBSMsg1List.YK_KIGEN_YMD);
				// 運用日付取得
				String opeDate = JFUBPCommon.getOpeDate(null);
				if (Integer.parseInt(opeDate) > nullToZero(ykKigenYmd))
				{
					// 結果コード：有効期限切れエラー
					resultMap.put(RETURN_CD, RETURN_CD_3);
				}
				else if (!JFUBPCommon.isNull(hishokaiName))
				{
					// 結果コード：使用済みエラー
					resultMap.put(RETURN_CD, RETURN_CD_4);
				}
				else
				{
					// 結果コード：正常
					resultMap.put(RETURN_CD, RETURN_CD_0);
				}
			}
			// ■通常の紹介コードの場合（紹介コード独自チェック対象）
			else if (isTujyoIntrCd)
			{
				// 有効期限年月日取得
				String ykKigenYmd = (String)EKK0311A010Map.get(EKK0311A010CBSMsg1List.YK_KIGEN_YMD);
				// 運用日付取得
				String opeDate = JFUBPCommon.getOpeDate(null);

				resultMap.put(RETURN_TUJYO_CD, RETURN_TUJYO_CD_1);

				if (Integer.parseInt(opeDate) > nullToZero(ykKigenYmd))
				{
					// 結果コード：有効期限切れエラー
					resultMap.put(RETURN_CD, RETURN_CD_3);
				}
				else if (!checkSvcKei(handle, param, fixedText, inIntrCd))
				{
					// 紹介コードが使用済の場合、結果コード：使用済みエラー を返す
					resultMap.put(RETURN_CD, RETURN_CD_4);
				}
				else
				{
					// 結果コード：正常
					resultMap.put(RETURN_CD, RETURN_CD_0);
				}
			}
			// ■その他の紹介コード
			else
			{
				if (isCouponCd)
				{
					// クーポンコードの場合（Amazonコード用の処理）

					if (isDisusedCouponCd)
					{
						// クーポンコード未使用の場合

						// 結果コード：正常
						resultMap.put(RETURN_CD, RETURN_CD_0);
					}
					else
					{
						// クーポンコード使用済の場合

						// 結果コード：使用済みエラー
						resultMap.put(RETURN_CD, RETURN_CD_4);
					}
				}
				else
				{
					// 被紹介者名が前方一致の場合
					if (hishokaiName.startsWith(inNameLast))
					{
						// 結果コード：正常
						resultMap.put(RETURN_CD, RETURN_CD_0);
					}
					else
					{
						// 結果コード：整合性エラー
						resultMap.put(RETURN_CD, RETURN_CD_2);
					}
				}
			}
		}
		else
		{
			// 結果コード：データなし
			resultMap.put(RETURN_CD, RETURN_CD_1);
		}

		return resultMap;
	}

	/**
	 * EKK0311A010_紹介一意照会の上りマッピング処理です。
	 * 
	 * <br>
	 * @param param リクエストパラメータ
	 * @param fixedText サービスメッセージ
	 * @param intrCd
	 * @throws RequestParameterException 
	 */
	private void setInMapEKK0311A010(IRequestParameterReadWrite param, String fixedText, String intrCd) throws RequestParameterException
	{
		// 機能コード設定(1)
		setFuncCode(param, fixedText, JPCModelConstant.FUNC_CD_1);

		// ユーザデータ取得
		HashMap inMap = (HashMap)param.getData(fixedText);

		// ＫＥＹ＿照会コード
		inMap.put(EKK0311A010CBSMsg.KEY_INTR_CD, intrCd);
	}
	
	/**
	 * チェック処理（共通処理）
	 * 
	 * <br>
	 * @param handle セッションハンドル
	 * @param param リクエストパラメータ
	 * @param fixedText サービスメッセージ
	 * @return リクエストパラメータ
	 * @throws Exception
	 */
	public HashMap<String, Object> getInvokeCBS(SessionHandle handle, IRequestParameterReadWrite param, String fixedText) throws Exception
	{
		return null;
	}

	/**
	 * 空文字の場合は0に変換する。
	 * 
	 * <br>
	 * @param sParam 文字列（数字）
	 * @return 数値
	 */
	private int nullToZero(String sParam)
	{
		String wStr = sParam;
		if (JFUBPCommon.isNull(sParam))
		{
			wStr = "0";
		}
		return Integer.parseInt(wStr);
	}

	/**
	 * 紹介コードが使用済かどうかサービス契約によって判定する。
	 * 
	 * @param handle セッションハンドル
	 * @param param リクエストパラメータ
	 * @param fixedText サービスメッセージ
	 * @param inIntrCd 紹介コード
	 * @return true：未使用、false：使用済
	 * @throws Exception
	 */
	private boolean checkSvcKei(SessionHandle handle, IRequestParameterReadWrite param, String fixedText, String inIntrCd) throws Exception {

		// ユーザデータ取得
		HashMap inMap = (HashMap)param.getData(fixedText);

		// ○EKK0081B532_サービス契約一覧照会（紹介コード）
		// ユーザデータ初期化
		initData(param, fixedText, IN_COL_LIST_EKK0081B532);
		// 上りマッピング
		setInMapEKK0081B532(param, fixedText, inIntrCd);
		//検索エラーなし設定
		ignoreSearchError(param, fixedText);
		// サービスIF実行
		executeSC(handle, param, fixedText, TEMP_ID_EKK0081B532, TEMP_ID_DTL_EKK0081B532, IN_COL_LIST_EKK0081B532, ERR_COL_EKK0081B532);

		// ●データが存在するか
		for (HashMap childMap : getTemplateList(inMap, getMaxTempTempleteKey(inMap, TEMP_TEMP_KEY_EKK0081B532), TEMP_ID_DTL_EKK0081B532))
		{
			// サービス契約番号
			String svcKeiNo = (String) childMap.get(EKK0081B532CBSMsg1List.SVC_KEI_NO);
			// サービス契約ステータス
			String svcKeiStat = (String) childMap.get(EKK0081B532CBSMsg1List.SVC_KEI_STAT);
			JFUBPCommon.printBpDebugLog(this.getClass(), "■■■ JFUShokaishaCheckCC ■■■ svcKeiNo[" + svcKeiNo + "] svcKeiStat[" + svcKeiStat + "]");

			// サービス契約ステータスが
			//「受付済（仮申込も含む）、照査済、締結済、サービス提供中、休止・中断中、停止中、解約済、キャンセル済」の場合（＝全ステータス）エラーとする。
			// ※フロントは画面の構成上、同一SYSIDの考慮なし。使用されている場合はエラーとなる。
			return false;
		}
		return true;
	}

	/**
	 * EKK0081B532_サービス契約一覧照会（紹介コード）の上りマッピング処理です。
	 * 
	 * <br>
	 * @param param リクエストパラメータ
	 * @param fixedText サービスメッセージ
	 * @param intrCd
	 * @throws RequestParameterException 
	 */
	private void setInMapEKK0081B532(IRequestParameterReadWrite param, String fixedText, String intrCd) throws RequestParameterException
	{
		// 機能コード設定(1)
		setFuncCode(param, fixedText, JPCModelConstant.FUNC_CD_1);

		// ユーザデータ取得
		HashMap inMap = (HashMap)param.getData(fixedText);

		// ＫＥＹ＿照会コード
		inMap.put(EKK0081B532CBSMsg.KEY_INTR_CD, intrCd);
	}

	/**
	 * value値にリスト内のkey値が前方一致するかを判定
	 * 
	 * @param list 前方一致
	 * @param value 値
	 * @return true：一致、false:不一致
	 */
	private static boolean chkFrontMatch(List<String> list, String value)
	{
		for (String key : list)
		{
			if (value.startsWith(key))
			{
				return true;
			}
		}
		return false;
	}
}
