/*******************************************************************************
*	All Rights reserved,Copyright (c) K-Opticom
********************************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*	モジュール名	：JECNA0240001CBSMsgTPMA
*	ソースファイル名：JECNA0240001CBSMsgTPMA.java
*	作成者			：FJ）渋谷
*	日付			：2023年8月31日
*＜機能概要＞
*	コンテンツ契約変更独自処理部品です。
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v65.00.00	2023/11/02	FJ張	【ANK-4346-00-00】【eo定期】CCMG再構築対応
*   v65.00.01	2023/08/31	FJ 渋谷	【ST-2024-0000002】エラーハンドリング対応
********************************************************************************/
package eo.ejb.cbs.mainproc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.fujitsu.futurity.model.base.CAANMsg;
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.common.constant.JCNStrConst;
import eo.common.util.JCNStringUtil;
import eo.common.util.JKKStringUtil;
import eo.ejb.cbs.cbsmsg.ECKA9040001CBSMsg;
import eo.ejb.cbs.cbsmsg.ECN0021B005CBSMsg;
import eo.ejb.cbs.cbsmsg.ECNA0170001CBSMsg;
import eo.ejb.cbs.cbsmsg.ECNA0170001CBSMsg2List;
import eo.ejb.cbs.cbsmsg.ECNA0240001CBSMsg;
import eo.ejb.cbs.cbsmsg.ECNA0240001CBSMsg1List;
import eo.ejb.cbs.cbsmsg.ECNA0240001CBSMsg2List;
import eo.ejb.cbs.cbsmsg.ECNA0240001CBSMsg3List;

import eo.ejb.common.JCCModelCommon;
import eo.ejb.common.JCNCtrlCcmgConnectInfoImpl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * コンテンツ契約変更依頼独自処理部品です。
 * <br>
 * @author FJ
 *
 */
public class JECNA0240001TPMA implements TemplateMainHandler
{	
	/** 接続モード **/
	private static final String CCMG_CNIFE056_CONNECTION_MODE  = "CCMG_CNIFE056_CONNECTION_MODE";
	/** 接続URL */
	private static final String CCMG_CNIFE056_URL  = "CCMG_CNIFE056_URL";
	/** 接続APIID */
	private static final String CCMG_CNIFE056_APIID  = "CNIFE056";
	/** 接続メソッド */
	private static final String CCMG_CNIFE056_METHOD  = "CCMG_CNIFE056_METHOD";
	/** タイムアウト時間 */
	private static final String CCMG_CNIFE056_TIMEOUT  = "CCMG_CNIFE056_TIMEOUT";
	/** リトライカウント */
	private static final String CCMG_CNIFE056_RETRYCOUNT  = "CCMG_CNIFE056_RETRYCOUNT";
	/** リトライインターバル */
	private static final String CCMG_CNIFE056_RETRYINTERVAL  = "CCMG_CNIFE056_RETRYINTERVAL";
	/** HTTPステータス（正常） */
	private static final String HTTP_STAT_200  = "200";
	/** エラーコード（正常） */
	private static final String ERR_CD_00000  = "00000";
	/** コンテンツ契約情報要否（0：不要 固定値） */
	private static final String RETURN_CONTRACT_NO_0 = "0";
	/** 直近課金情報要否（0：不要 固定値） */
	private static final String RETURN_CHARGE_NO_0 = "0";
	/** API受信 項目名 */
	private static final String[][] CNIFE056_RES_LIST1_INFO = new String[][]{
		  {"err_cd",								ECNA0240001CBSMsg2List.ERR_CD}                              // エラーコード
		, {"contracts",				                ECNA0240001CBSMsg2List.ECNA0240001CBSMSG3LIST}				// 処理番号発行配列明細
		
	};
	/** API受信 項目名（コンテンツ契約変更情報配列） */
	private static final String[][] CNIFE056_RES_LIST2_INFO = new String[][]{
		  {"sysid",									ECNA0240001CBSMsg3List.SYSID}								// SYSID
		, {"contract_no",							ECNA0240001CBSMsg3List.CONTRACT_NO}							// コンテンツ契約番号
		, {"contents_start_date",					ECNA0240001CBSMsg3List.CONTENTS_START_DATE}	                //コンテンツ開始日時
		, {"contents_end_date",					    ECNA0240001CBSMsg3List.CONTENTS_END_DATE}	                // コンテンツ終了日時
		, {"service_id",					        ECNA0240001CBSMsg3List.SERVICE_ID}	                        //  コンテンツサービスID
		, {"service_name",					        ECNA0240001CBSMsg3List.SERVICE_NAME}	                    //  コンテンツサービス名称
		, {"contents_id",							ECNA0240001CBSMsg3List.CONTENTS_ID}							// コンテンツID
		, {"contents_name",							ECNA0240001CBSMsg3List.CONTENTS_NAME}						// コンテンツ名称
		, {"contents_err_cd",						ECNA0240001CBSMsg3List.CONTENTS_ERR_CD}						// コンテンツエラーコード
	};
	// ST-2024-0000002 ADD START
	/** 正常終了エラーコード */
	private static final String[] NOMAL_END_ERR_CD  = {"00000","" };
	// ST-2024-0000002 ADD END

	
	/**
	 * コンテンツ契約変更依頼を行います。
	 * 
	 * @param inCBSMsg コンテンツ契約変更依頼メッセージ
	 * @param inContext AgentDispatchContext
	 */
	public static void call_CNIFE056(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		CAANMsg reqMsg = new CAANMsg();
		HashMap<String,Object> connect = new HashMap<String, Object>();
		HashMap<String,Object> reqInfo = new HashMap<String, Object>();
		Map<String, Object> body = new HashMap<String, Object>();
		
		// body部マッピング
		setBody(inCBSMsg,body);
		// 接続モード
		connect.put(JCNCtrlCcmgConnectInfoImpl.CONNECTINFO_CONNECTMODE, JKKStringUtil.nullToBlank(JCCModelCommon.getApplicationConst(CCMG_CNIFE056_CONNECTION_MODE)));
		//接続URL
		connect.put(JCNCtrlCcmgConnectInfoImpl.CONNECTINFO_URL, JKKStringUtil.nullToBlank(JCCModelCommon.getApplicationConst(CCMG_CNIFE056_URL)));
		//接続APIID
		connect.put(JCNCtrlCcmgConnectInfoImpl.CONNECTINFO_APIID, CCMG_CNIFE056_APIID);
		//接続メソッド
		connect.put(JCNCtrlCcmgConnectInfoImpl.CONNECTINFO_CONNECTMETHOD, JKKStringUtil.nullToBlank(JCCModelCommon.getApplicationConst(CCMG_CNIFE056_METHOD)));
		//タイムアウト時間
		connect.put(JCNCtrlCcmgConnectInfoImpl.CONNECTINFO_TIMEOUT, JKKStringUtil.nullToBlank(JCCModelCommon.getApplicationConst(CCMG_CNIFE056_TIMEOUT)));
		//リトライカウント
		connect.put(JCNCtrlCcmgConnectInfoImpl.CONNECTINFO_RETRYCOUNT, JKKStringUtil.nullToBlank(JCCModelCommon.getApplicationConst(CCMG_CNIFE056_RETRYCOUNT)));
		//リトライインターバル
		connect.put(JCNCtrlCcmgConnectInfoImpl.CONNECTINFO_RETRYINTERVAL, JKKStringUtil.nullToBlank(JCCModelCommon.getApplicationConst(CCMG_CNIFE056_RETRYINTERVAL)));
		//BODY
		reqInfo.put(JCNCtrlCcmgConnectInfoImpl.RESINFO_BODY, body);
		
		reqMsg.setPrivate(JCNCtrlCcmgConnectInfoImpl.CONNECTINFO, (Object)connect);
		reqMsg.setPrivate(JCNCtrlCcmgConnectInfoImpl.REQINFO, (Object)reqInfo);
		
		// コマンド発行部品のインスタンスを取得
		JCNCtrlCcmgConnectInfoImpl instance = new JCNCtrlCcmgConnectInfoImpl();
		
		Hashtable<String, Object> jsonResult = new Hashtable<String, Object>();
		try
		{
			JSYejbLog.println(JSYejbLog.EXECUTION, JECNA0240001TPMA.class , "JECNA0240001TPMA#request postParameter=" + inCBSMsg);
			// 共通API連携
			Map<String, Object> resServiceMap = instance.ctrlCcmgConnect(reqMsg);
			
			if(resServiceMap == null)
			{
				resServiceMap = new HashMap<String, Object>();
			}
			// 接続結果
			Map<String, Object> connectResult = (Map<String, Object>) resServiceMap.get(JCNCtrlCcmgConnectInfoImpl.CONNECTRESULT);
			// レスポンス情報
			Map<String, Object> resInfo = (Map<String, Object>) resServiceMap.get(JCNCtrlCcmgConnectInfoImpl.RESINFO);
			JsonNode resultBody = (JsonNode)resInfo.get(JCNCtrlCcmgConnectInfoImpl.RESINFO_BODY);
			jsonResult = read(resultBody);
			// エラーコード
			String errCode = "";
			// HTTPステータス
			String httpStatus = JKKStringUtil.nullToBlank((String) connectResult.get("httpStatus"));
			if (jsonResult.get(ECNA0240001CBSMsg2List.ERR_CD) != null)
			{
				errCode = (String) jsonResult.get(ECNA0240001CBSMsg2List.ERR_CD);
			}
			// ST-2024-0000002 ADD START
			// HTTPステータスが500の場合、接続エラー
			if("500".equals(httpStatus) && "".equals(errCode))
			{
				// ステータス設定（実行時エラー）
				inCBSMsg.set(ECKA9040001CBSMsg.STATUS, StatusCodes.RELATION_ERR);
				inCBSMsg.set(ECKA9040001CBSMsg.ECKA9040001CBSMSG1LIST, new CAANMsg[0]);
				return;
			}
			// ST-2024-0000002 ADD END
			// 共通API連携実行結果判定
			// 正常終了の場合
			// ST-2024-0000002 MOD START
//			if (httpStatus.equals(HTTP_STAT_200) && errCode.equals(ERR_CD_00000))
			if(httpStatus.startsWith("2") && Arrays.asList(NOMAL_END_ERR_CD).contains(errCode))
			// ST-2024-0000002 MOD END
			{
				// ステータス設定（0:正常終了）
				inCBSMsg.set(ECNA0240001CBSMsg.STATUS, StatusCodes.NORMAL_END);
			}
			// 上記以外の場合
			else
			{
				// 正常終了または異常終了のステータス以外で返却された場合
				inCBSMsg.set(ECNA0240001CBSMsg.STATUS, StatusCodes.EXTERNAL_IF_ERR1);
			}

			// レスポンス電文を設定　※異常が発生している場合でも空で作成する
			editOutMsg(inCBSMsg, jsonResult, httpStatus);
		}
		catch(Exception e)
		{
			printErrorLog(e);
			// ステータス設定（実行時エラー）
			inCBSMsg.set(ECNA0240001CBSMsg.STATUS, StatusCodes.RELATION_ERR);
			inCBSMsg.set(ECNA0240001CBSMsg.ECNA0240001CBSMSG1LIST, new CAANMsg[0]);
			return;
		}
		
		// 終了ログ出力を実施。
		JSYejbLog.println(JSYejbLog.DEBUG, JECNA0240001TPMA.class, "JECNA0240001TPMA#call_CNIFE056 end");
	}
	
	
	/**
	 * 共通APIのリクエスト電文を設定します。
	 * <br>
	 * @param inCBSMsg コンテンツ契約変更依頼メッセージ
	 * @param resServiceMap レスポンスサービスマップ
	 */
	private static void setBody(CAANMsg inCBSMsg, Map<String, Object> body)
	{
		// SYSID
		body.put("sysid",inCBSMsg.getObject(ECNA0240001CBSMsg.KEY_SYSID));
		
		CAANMsg[] templateArray = null;
		ArrayList<HashMap> dataList = new ArrayList<HashMap>();
		HashMap<String, String> list = new HashMap<String, String>() ;

		templateArray = inCBSMsg.getCAANMsgList(ECNA0240001CBSMsg.ECNA0240001CBSMSG1LIST);
		
		
		for(CAANMsg str : templateArray)
		{
		    list.put("contract_no", JCNStringUtil.nullToBlank(str.getString("key_contract_no")));
			dataList.add(list);
		}
		body.put("cancel",objNullToBlank(dataList));
		
		String cancelChainFlg = "0";
		if(inCBSMsg.getString(ECNA0240001CBSMsg.CANCEL_CHAIN_FLG) == null)
		{
			cancelChainFlg = "0";
		}
		else
		{
			cancelChainFlg = inCBSMsg.getString(ECNA0240001CBSMsg.CANCEL_CHAIN_FLG);	// 共連れ解約フラグ
		}
		
		
		// メール送信フラグ
		body.put(ECNA0240001CBSMsg.MAIL_SEND_FLG,JCNStringUtil.nullToBlank(inCBSMsg.getString(ECNA0240001CBSMsg.MAIL_SEND_FLG)));
		// 共連れ解約実施フラグ
		body.put(ECNA0240001CBSMsg.CANCEL_CHAIN_FLG,cancelChainFlg);
		// 更新者ID
		body.put(ECNA0240001CBSMsg.UPDATE_ID,JCNStringUtil.nullToBlank(inCBSMsg.getString(ECNA0240001CBSMsg.UPDATE_ID)));
		// 更新者
		body.put(ECNA0240001CBSMsg.UPDATE_NAME,JCNStrConst.API_CONTENTS_UPDATE_NAME);
		// コンテンツ契約情報要否
		body.put(ECNA0240001CBSMsg.RETURN_CONTRACT,RETURN_CONTRACT_NO_0);
		// 直近課金情報要否
		body.put(ECNA0240001CBSMsg.RETURN_CHARGE,RETURN_CHARGE_NO_0);
	}
	
	/**
	 * 共通APIのレスポンス電文を設定します。
	 * <br>
	 * @param inCBSMsg コンテンツ契約変更依頼メッセージ
	 * @param resServiceMap レスポンスサービスマップ
	 */
	private static void editOutMsg(CAANMsg inCBSMsg, Hashtable<String, Object> resultBody,String httpStat)
	{
	
		
		
		if(resultBody != null)
		{
			List<CAANMsg> msgList = new ArrayList<CAANMsg>();
			CAANMsg msg = new CAANMsg(ECNA0240001CBSMsg2List.class.getName());
			for(String[] item : CNIFE056_RES_LIST1_INFO)
			{
				String itemName = item[1];
				Object itemValue = resultBody.get(item[0]);
				//コンテンツ契約変更情報配列の場合
				// ADD START
				if(itemValue == null)
				{
					msg.setNull(itemName);
				}
				
				else if(itemName.equals(ECNA0240001CBSMsg2List.ECNA0240001CBSMSG3LIST))
				{   List<CAANMsg> msg1List = new ArrayList<CAANMsg>();
					List<Map<String, Object>> list1 = (List<Map<String, Object>>) itemValue;
					
					for(Map<String, Object> record1 : list1)
					{   
						CAANMsg msg1 = new CAANMsg(ECNA0240001CBSMsg3List.class.getName());
						for(String[] item1 : CNIFE056_RES_LIST2_INFO)
						{
							String itemName1 = item1[1];
							Object itemValue1 = record1.get(item1[0]);
							msg1.set(itemName1, (String) itemValue1);
						}
						msg1List.add(msg1);
					}
					msg.set(itemName, msg1List.toArray(new CAANMsg[msg1List.size()]));
				}
				else
				{
					msg.set(itemName, (String)itemValue);
				}
			}
			msg.set(ECNA0240001CBSMsg2List.HTTPSTATUS, httpStat);
			msgList.add(msg);
			inCBSMsg.set(ECNA0240001CBSMsg.ECNA0240001CBSMSG2LIST, msgList.toArray(new CAANMsg[msgList.size()]));
			
		}
		
	}
	
		
	/**
	 * 電文読み込み処理
	 * @param jsonResponse
	 * @return json電文解析結果
	 */
	private static Hashtable<String, Object> read(JsonNode jsonResponse) 
	{
		if(jsonResponse == null)
		{
			return null;
		}
		Hashtable<String, Object> result = analyzeJson(jsonResponse);

		return result;
	}
	
	/**
	 * コマンド送信戻り電文解析処理
	 * @param elem コマンド解析電文rootjson要素
	 * @param rootflag ルートフラグ
	 * @return json解析結果
	 */
	private static Hashtable<String, Object> analyzeJson(JsonNode elem)
	{
		
		Hashtable<String, Object> resultMap = new Hashtable<String, Object>();
		
		Iterator<Map.Entry<String, JsonNode>> fields = elem.fields();
		while(fields.hasNext())
		{
			Map.Entry<String, JsonNode> field = fields.next();
			
			String fieldName = field.getKey();
			JsonNode fieldValue = field.getValue();
			
			
			if(fieldValue.isNull())
			{
				//何もしない
			}
			// Arrayの場合
			else if(fieldValue.isArray())
			{
				ArrayList<Object> Bodynodelist = new ArrayList<Object>();
				Iterator<JsonNode> itr = fieldValue.elements();
				while(itr.hasNext())
				{
					JsonNode node = itr.next();
					if(node.isValueNode())
					{
						Bodynodelist.add(node.textValue());
					}
					else
					{
						Hashtable<String, Object> resultinfo = analyzeJson(node);
						if (resultinfo != null && !resultinfo.isEmpty())
						{
							Bodynodelist.add(resultinfo);
						}
					}
				}
				
				resultMap.put( fieldName, Bodynodelist);
			}
			// 子要素を持つ場合は再帰処理
			else if( fieldValue.isObject() )
			{
				resultMap.put(fieldName, analyzeJson(fieldValue) );
			}
			// 以外は値を設定
			else
			{
				if(fieldValue.isInt())
				{
					resultMap.put(fieldName, fieldValue.bigIntegerValue().toString());
				}
				else if(fieldValue.isTextual())
				{
					resultMap.put(fieldName, fieldValue.textValue());
				}
				else
				{
					//何もしない
				}
			}
		}
		
		return resultMap;
	}
	

/**
	 * 引数で受け取った値がNULLの場合、空を設定し返却する。
	 * <br>
	 * @param Object 
	 */
	private static Object objNullToBlank(Object obj)
	{
		if(obj == null)
		{
			return JCNStrConst.S_BLANK;
		}
			return obj;
	}	
	/**
	 * エラーログ出力
	 * @param e 発生した例外
	 * @param params 指示書パラメータ(1〜50)
	 * @param errTitle エラータイトル
	 * @param sjishoNo 指示書番号
	 * @param sjishoNaiyoSeq 指示書内容枝番
	 */
	static private void printErrorLog(Exception e)
	{
		StringBuffer sb = new StringBuffer();
		sb.append(e.getMessage()+ "\n");
		sb.append(e.getClass().getName()+ "\n");
		StackTraceElement[] steAll = e.getStackTrace();
		for (StackTraceElement ste : steAll) {
			sb.append("	at " + ste.getClassName() + "." + ste.getMethodName() + "(" + ste.getFileName() + ":" + ste.getLineNumber()+")"+ "\n");
		}
		JSYejbLog.println(JSYejbLog.ERROR, JECNA0240001TPMA.class, sb.toString());
	}

}
