/*******************************************************************************
 * All Rights reserved,Copyright (c) K-Opticom
********************************************************************************
*＜プログラム内容＞
* システム名        ：eo顧客基幹システム
* モジュール名      ：JCNPrcChgAddCCMGCC
* ソースファイル名  ：JCNPrcChgAddCCMGCC.java
* 作成者            ：富士通
* 日付              ：2023年09月17日
*＜機能概要＞
* 課金情報取得取得コモンコンポーネント部品
*＜修正履歴＞
* バージョン    修正日      修正者      修正内容
* ｖ1.00.00
*  v65.00.01	2024/02/09	FJ渋谷	【ST-2024-0000002】エラーハンドリング対応
*	v65.00.01	2024/03/15	FJ 渋谷		【#84105】SIFエラーがＣＣＭＧエラーとして表示される
********************************************************************************/

package com.fujitsu.futurity.bp.custom.common;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

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.CCException;
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 com.fujitsu.futurity.model.ejb.common.StatusCodes;

import eo.common.constant.JKKStrConst;
import eo.common.constant.JPCModelConstant;
import eo.common.util.JCNStringUtil;
import eo.ejb.cbs.cbsmsg.ECNA0190001CBSMsg1List;
import eo.ejb.cbs.cbsmsg.ECNA0190001CBSMsg;
import eo.ejb.cbs.cbsmsg.ECNA0200001CBSMsg;
import eo.ejb.cbs.cbsmsg.ECNA0200001CBSMsg1List;


/**
 * 料金訂正登録・変更コモンコンポーネント部品.<br>
 * 
 * @author user
 *
 */
public class JCNPrcChgAddCCMGCC extends AbstractCommonComponent
{
	/*
	 * ==================
	 * CC入出力パラメータ
	 * ==================
	 */
	/** 
	 *  CC入力パラメータ：機能コード
	 *  1：コンテンツ料金調整登録呼出(課金参照／課金契約情報取得)
	 *  2：コンテンツ請求照会画面呼出(課金参照／課金契約情報取得(LaLaCallのみ))
	 */
	public static final String FUNC_CODE = "func_code";
	
	



	/** CC出力パラメータ：処理結果コード */
	public static final String RETURN_CODE = "return_code";

	/** CC出力パラメータ：エラー機能識別コード */
	public static final String ERR_SKBT_CODE = "err_skbt_code";
	// ST-2024-0000002 ADD START
	/** CC出力パラメータ：ステータスコード */
	public static final String STATUS = "status";
	// ST-2024-0000002 ADD END




	/*
	 * ============
	 * サービスIFID
	 * ============
	 */
	/** テンプレートID（処理番号発行） */
	private static final String TEMPLATE_ID_ECNA0190001 = "ECNA0190001";

	/** テンプレートID（料金訂正登録・変更） */
	private static final String TEMPLATE_ID_ECNA0200001 = "ECNA0200001";


	/*
	 * ========
	 * 固有定数
	 * ========
	 */
	/** 機能コード 新規登録 */
	private static final String FUNC_CODE_1 = "1";
	/** 機能コード 更新 */
	private static final String FUNC_CODE_2 = "2";
	/** リターンコード 正常値 */
	private static final String RETURN_CODE_OK = "00000";
	/** エラー機能識別コード 0（エラーなし） */
	private static final String ERR_SKBT_CD_0 = "0";
	/** エラー機能識別コード 1（処理番号発行） */
	private static final String ERR_SKBT_CD_1 = "1";
	/** エラー機能識別コード 2（料金調整登録・変更）*/
	private static final String ERR_SKBT_CD_2 = "2";
	/** 訂正区分（1：取消）*/
	private static final String CORRECTED_DIVISION_1 = "1";
	/** 訂正区分（2：売上減）*/
	private static final String CORRECTED_DIVISION_2 = "2";


	/*
	 * ========
	 * 共通定数
	 * ========
	 */
	/** リターンメッセージ取得キー */
	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>
	 * <br>
	 * 課金参照、コンテンツ事業クレジット照会サービスIFを呼び出し、コンテンツ請求情報を取得する。
	 * 
	 * @param handle セッションハンドル
	 * @param param リクエストパラメータ
	 * @param fixedText サービスメッセージ
	 * @return リクエストパラメータ
	 * @throws Throwable 
	 */
	public IRequestParameterReadWrite execute(SessionHandle handle, IRequestParameterReadWrite param, String fixedText) throws Throwable
	{
		
		// CCパラメータ
		HashMap<String, Object> ccMsg = (HashMap<String, Object>)param.getData(fixedText);
		String ope_id = (String)param.getControlMapData(SCControlMapKeys.OPERATOR_ID);
		// SC呼び出し部品のインスタンス生成
		ServiceComponentRequestInvoker scCall = new ServiceComponentRequestInvoker();
		
		String funcCode =  (String)ccMsg.get(FUNC_CODE);
		
		try
		{
			
			/*******************/
			/** 処理番号発行 **/
			/******************/
			Object[][] ecna0190001in = editShoriNmberHakkoInMsg(ccMsg);
			
			// サービスIF実行
			// 処理番号発行明細
			CAANMsg ecna0190001CBSMsg = callSC(handle, scCall, param, fixedText, ecna0190001in);
			
			// 処理番号発行 処理番号発行情報明細
			CAANMsg[] ecna0190001Msg1List = ecna0190001CBSMsg.getCAANMsgList(ECNA0190001CBSMsg.ECNA0190001CBSMSG1LIST);
			
			
			String operationId = null;
			// ST-2024-0000002 ADD START
			int status = ecna0190001CBSMsg.getInt(ECNA0190001CBSMsg.STATUS);
			String statusStr = String.valueOf(status);
			ccMsg.put(STATUS , statusStr);
			// ST-2024-0000002 ADD END
			
			// 結果が取得できていれば取得する。
			if (ecna0190001Msg1List != null && ecna0190001Msg1List.length > 0)
			{
				CAANMsg ecna0019001Msg1ListMap = ecna0190001Msg1List[0];
				
				operationId = ecna0019001Msg1ListMap.getString(ECNA0190001CBSMsg1List.OPERATION_ID);
				// API実行結果の取得
				String errCd = ecna0019001Msg1ListMap.getString(ECNA0190001CBSMsg1List.ERR_CD);
				// ST-2024-0000002 ADD START
				ccMsg.put(RETURN_CODE , errCd);
				// ST-2024-0000002 ADD END
				// リターンコードが正常終了以外の場合、後続処理を実施しない。
				if ( !RETURN_CODE_OK.equals(errCd) )
				{
					// #84105 ADD START
					// エラーコードがNULLまたは、空の場合、CCMG連携エラー
					if(errCd == null && "".equals(errCd))
					{
						ccMsg.put("CCMG_ERR_FLG", "1");
						ccMsg.put(RETURN_CODE , "");
						return param;
					}
					// #84105 ADD END
					
					// エラー識別コードに "1":処理番号発行でのエラー を設定
					ccMsg.put(ERR_SKBT_CODE , ERR_SKBT_CD_1);
					ccMsg.put(RETURN_CODE , errCd);
					return param;
				}
				if(!JCNStringUtil.isNullBlank(operationId))
				{
					/**********************/
					/**料金訂正登録・変更**/
					/**********************/
					Object[][] ecna0200001in = editContIcrnInfoInMsg(ccMsg, operationId, ope_id);
					
					// サービスIF実行
					// 料金訂正登録・変更明細
					CAANMsg ecna0200001CBSMsg = callSC(handle, scCall, param, fixedText, ecna0200001in);
					// ST-2024-0000002 ADD START
					status = ecna0200001CBSMsg.getInt(ECNA0200001CBSMsg.STATUS);
					statusStr = String.valueOf(status);
					ccMsg.put(STATUS , statusStr);
					// ST-2024-0000002 ADD END
					// #84105 ADD START
					// ステータスが"1100"の場合、CCMG連携エラー
					if ("1100".equals(statusStr))
					{
						ccMsg.put(RETURN_CODE, "");
						ccMsg.put("CCMG_ERR_FLG", "1");
						return param;
					}					
					// #84105 ADD END
					// 料金訂正登録・変更 料金訂正登録・変更情報明細
					CAANMsg[] ecna0200001Msg1List = ecna0200001CBSMsg.getCAANMsgList(ECNA0200001CBSMsg.ECNA0200001CBSMSG1LIST);
					
					// API実行結果の取得
					if(ecna0200001Msg1List != null && ecna0200001Msg1List.length > 0)
					{
						errCd = ecna0200001Msg1List[0].getString(ECNA0200001CBSMsg1List.ERR_CD);
						// ST-2024-0000002 ADD START
						ccMsg.put(RETURN_CODE , errCd);
						// ST-2024-0000002 ADD END
						// リターンコードが正常終了以外の場合、後続処理を実施しない。
						if ( !RETURN_CODE_OK.equals(errCd) )
						{
							// エラー識別コードに "2":料金訂正登録・変更でのエラー を設定
							ccMsg.put(ERR_SKBT_CODE , ERR_SKBT_CD_2);
							ccMsg.put(RETURN_CODE , errCd);
							return param;
						}
						
					}
					else
					{
						// エラー識別コードに "2":料金訂正登録・変更でのエラー を設定
						ccMsg.put(ERR_SKBT_CODE , ERR_SKBT_CD_2);
						ccMsg.put(RETURN_CODE , "");
						return param;
					}
				}
				else
				{
					// エラー識別コードに "1":処理番号発行でのエラー を設定
					ccMsg.put(ERR_SKBT_CODE , ERR_SKBT_CD_1);
					ccMsg.put(RETURN_CODE , "");
					return param;
				}
			}
			else
			{
				// #84105 MOD START
//				// エラー識別コードに "1":処理番号発行でのエラー を設定
//				ccMsg.put(ERR_SKBT_CODE , ERR_SKBT_CD_1);
				ccMsg.put("CCMG_ERR_FLG", "1");
				// #84105 MOD END
				ccMsg.put(RETURN_CODE , "");
				return param;
			}
			
			// 正常終了
			ccMsg.put(RETURN_CODE , RETURN_CODE_OK );
			param.setControlMapData(SCControlMapKeys.RETURN_CODE, JKKStrConst.RETURN_CD_0000);
			param.setControlMapData(SCControlMapKeys.RETURN_MESSAGE, null);
		}
		// サービスインターフェース呼び出しでエラーが発生した場合
		catch (SCCallException scCallEx)
		{
			// システムエラーを設定する
			param.setControlMapData(SCControlMapKeys.RETURN_CODE, JKKStrConst.RETURN_CD_9000);
			param.setControlMapData(SCControlMapKeys.RETURN_MESSAGE, JKKStrConst.RETURN_MESSAGE_SYSTEM_ERROR);
		}
		return param;
	}

	private Object[][] editShoriNmberHakkoInMsg(HashMap<String, Object> ccMsg) {
		
		Object[][] ecna0190001in = 
		{
			  {ECNA0190001CBSMsg.TEMPLATEID, TEMPLATE_ID_ECNA0190001}				// テンプレートＩＤ
			, {ECNA0190001CBSMsg.FUNC_CODE, JPCModelConstant.FUNC_CD_1}				// 機能コード
			
		};
		
		return ecna0190001in;
	}

	private Object[][] editContIcrnInfoInMsg(HashMap<String, Object> ccMsg, String operationId, String ope_id) {
		
		String correctedDivision = "";
		
		if(!JCNStringUtil.isNullBlank((String)ccMsg.get(ECNA0200001CBSMsg.CORRECTED_DIVISION)))
		{
			// 訂正区分が売上減の場合、"2"（売上減）を設定
			if("1".equals(JCNStringUtil.nullToBlank((String)ccMsg.get(ECNA0200001CBSMsg.CORRECTED_DIVISION))))
			{
				correctedDivision = CORRECTED_DIVISION_2;
			}
			// 訂正区分が取消の場合、"1"（取消）を設定
			else if("2".equals(JCNStringUtil.nullToBlank((String)ccMsg.get(ECNA0200001CBSMsg.CORRECTED_DIVISION))))
			{
				correctedDivision = CORRECTED_DIVISION_1;
			}
		}


		Object[][] ecna0020001in =
		{
			  {ECNA0200001CBSMsg.TEMPLATEID, TEMPLATE_ID_ECNA0200001}										// テンプレートＩＤ
			, {ECNA0200001CBSMsg.FUNC_CODE, JPCModelConstant.FUNC_CD_1}										// 機能コード
			, {ECNA0200001CBSMsg.CONTRACT_NO, ccMsg.get(ECNA0200001CBSMsg.CONTRACT_NO)}						// 契約番号
			, {ECNA0200001CBSMsg.TARGET_DATE, ccMsg.get(ECNA0200001CBSMsg.TARGET_DATE)}						// 対象年月
			, {ECNA0200001CBSMsg.OPERATION_ID, operationId}													// 処理番号
			, {ECNA0200001CBSMsg.UPDATE_ID, ope_id}															// 更新者ID
			, {ECNA0200001CBSMsg.CORRECTED_DIVISION, correctedDivision}										// 訂正区分
			, {ECNA0200001CBSMsg.DISCOUNT_AMOUNT, ccMsg.get(ECNA0200001CBSMsg.DISCOUNT_AMOUNT)}				// 値引額
			, {ECNA0200001CBSMsg.CORRECTED_NOTES, ccMsg.get(ECNA0200001CBSMsg.CORRECTED_NOTES)}				// 訂正記事
			, {ECNA0200001CBSMsg.ADD_UPD_JUDGE_FLG, ccMsg.get(ECNA0200001CBSMsg.ADD_UPD_JUDGE_FLG)}			// 訂正記事
		
		};
		
		return ecna0020001in;

	}

	/**
	 * SC(サービスインターフェイス）を呼び出します。
	 * @param handle セッションハンドル
	 * @param scCall SC呼び出し部品
	 * @param param リクエストパラメータ
	 * @param dataMapKey パラメータキー
	 * @param mappingData マッピングデータ
	 * @return サービスインターフェイス実行結果
	 * @throws Throwable 例外が発生した場合
	 */
	private 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を生成してスローする
		// ST-2024-0000002 DEL START
//		if (!("0".equals(RETURN_CODE.toString()) && 0 == status))
//		{
//			throw new SCCallException("戻り値不正", RETURN_CODE.toString(), status);
//		}
		// ST-2024-00000021 DEL END
		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;
	}
	
	// #84105 ADD START
	/**
	 * SCの実行ステータスの取得処理を行います。
	 * <br>
	 * @param param
	 * @return SCの実行ステータス
	 * @throws Exception
	 */
	protected int getReturnCode(IRequestParameterReadWrite param) throws Exception
	{
		return Integer.parseInt((String)param.getControlMapData(SCControlMapKeys.RETURN_CODE));
	}
	// #84105 ADD END
}
