/*******************************************************************************
*	All Rights reserved,Copyright (c) K-Opticom
********************************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*	モジュール名	：JECKA0010001TPMA
*	ソースファイル名：JECKA0010001TPMA.java
*	作成者			：FJ）星野
*	日付			：2021年05月07日
*＜機能概要＞
*	パスワードハッシュ化独自処理部品です。
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v53.00.00	2021/05/07	FJ）星野	【ANK-4009-00-00】CX戦略WG方針対応
********************************************************************************/
package eo.ejb.cbs.mainproc;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.common.JCMAPLConstMgr;
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.JCKStrConst;
import eo.ejb.cbs.cbsmsg.ECKA0010001CBSMsg;
import eo.ejb.common.JCCModelCommon;
import eo.ejb.common.JCKLcsRenkeiUtil;


/**
 * パスワードハッシュ化独自処理部品です。
 * <br>
 * @author FJ
 *
 */
public class JECKA0010001TPMA implements TemplateMainHandler
{

	/** 外部インターフェースID */
	private static final String IF_ID = "CKIFE062";

	/** エラーフラグ(EA：設定値取得エラー) */
	private static final String EA_ERR_FLAG = "EA";
	
	/** エラーフラグ(EB：応答コードエラー) */
	private static final String EB_ERR_FLAG = "EB";
	
	/** エラーフラグ(EC：実行時エラー) */
	private static final String EC_ERR_FLAG = "EC";
	
	/** モード取得用キー */
	private static final String IDA_MODE_KEY = "LCS_IDA_WEB_API_TEST_MODE";
	
	/** ダミーHTTPステータス取得用キー */
	private static final String STUB_HTTP_STATUS_KEY = "CK_IDA_DUMMY_HTTP_STATUS";
	
	/**
	 * JSON_PATH
	 */
	protected static final String IDA_CONNECTION_MODE_TEST_DIR = "IDA_CONNECTION_MODE_TEST_DIR";

	/** 応答コードOK */
	private static final String CODE_OK = "000000";
	/** 応答コードOK(その他) */
	private static final String CODE_OK_OTHER = "000001";
	
	/** 【パラメータ一覧】  */
	/** CCMG実行結果 HTTPStatus */
	public static final String EXE_STATUS = "status";
	/** エラーコード */
	private static final String RETURN_CODE = "RETURN_CODE";
	
	
	/** API送信 項目名 */
	private static final String[][] CKIFE062_REQ_INFO = new String[][]{
		{"COOPERATION_SYSTEM_CODE", ECKA0010001CBSMsg.COOPERATION_SYSTEM_CODE}	// 連携先システムコード
		, {"ORG_ID", ECKA0010001CBSMsg.ORG_ID}									// 体系ID
		, {"LOGIN_PASSWORD", ECKA0010001CBSMsg.LOGIN_PASSWORD}					// ログインパスワード
	};
	
	/** API受信 項目名 */
	private static final String[][] CKIFE062_RES_INFO = new String[][]{
		{RETURN_CODE, ECKA0010001CBSMsg.RETURN_CODE}							// 戻りコード
		, {"RETURN_MSG", ECKA0010001CBSMsg.RETURN_MSG}							// 返却メッセージ
		, {"API_PID", ECKA0010001CBSMsg.API_PID}								// APIプロセスID
		, {"HASHED_LOGIN_PASSWORD", ECKA0010001CBSMsg.HASHED_LOGIN_PASSWORD}	// ハッシュ化済みログインパスワード
	};
	
	/**
	 * パスワードハッシュ化を行います。
	 * 
	 * @param inCBSMsg パスワードハッシュ化メッセージ
	 * @param inContext AgentDispatchContext
	 */
	public static void call_CKIFE062(CAANMsg inCBSMsg, AgentDispatchContext inContext)
	{
		// 開始ログ出力を実施。
		JSYejbLog.println(JSYejbLog.DEBUG, JECKA0010001TPMA.class, "JECKA0010001TPMA#invoke start");
		
		Hashtable<String, Object> response = new Hashtable<String, Object>();
		
		/** 接続先などの判定に使用
		*   OFF： 本番・検証、ON: 開発
		*/
		String mode = JCMAPLConstMgr.getString(IDA_MODE_KEY);
		// アプリケーションプロパティ設定チェック
		if(isNullBlank(mode))
		{
			// ステータス設定（設定値取得エラー）
			inCBSMsg.set(ECKA0010001CBSMsg.STATUS, StatusCodes.RELATION_ERR);
			inCBSMsg.set(ECKA0010001CBSMsg.LOGIN_PASSWORD_ERR, EA_ERR_FLAG);
			return;
		}
		
		try
		{
			/*
			 * 送信パラメータ作成
			 */
			//JSON形式の文字列を作成する。
			String reqData = requestParamMake(inCBSMsg);
			
			if (JCKStrConst.AXM_REQUEST_TEST_MODE_OFF.equals(mode))
			{
				// iDAに対してリクエストを送信する。
				response = callGet(reqData);

				

			}
			else
			{
				// ダミーjsonを呼ぶ。
				response = callDummyJson(inCBSMsg);
			}
			
			// 連携実行結果判定
			if(isNormal(response))
			{
				// ステータス設定（0:正常終了）
				inCBSMsg.set(ECKA0010001CBSMsg.STATUS, StatusCodes.NORMAL_END);
			}
			else
			{
				// ステータス設定（応答コードエラー）
				inCBSMsg.set(ECKA0010001CBSMsg.STATUS, StatusCodes.RELATION_ERR);
				inCBSMsg.set(ECKA0010001CBSMsg.LOGIN_PASSWORD_ERR, EB_ERR_FLAG);
			}

		}
		catch (Exception e)
		{
// IT1-2021-0000050対応 20210610 MOD START
//			e.printStackTrace();
			printErrorLog(e);
// IT1-2021-0000050対応 20210610 MOD END
			// ステータス設定（実行時エラー）
			inCBSMsg.set(ECKA0010001CBSMsg.STATUS, StatusCodes.RELATION_ERR);
			inCBSMsg.set(ECKA0010001CBSMsg.LOGIN_PASSWORD_ERR, EC_ERR_FLAG);
			return;
		}
		
		
		editOutMsg(inCBSMsg, response, mode);

		// 終了ログ出力を実施。
		JSYejbLog.println(JSYejbLog.DEBUG, JECKA0010001TPMA.class, "JECKA0010001TPMA#invoke end");
	}
	
// IT1-2021-0000050対応 20210610 ADD START
	/**
	 * エラーログ出力
	 * @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, JECKA0010001TPMA.class, sb.toString());
	}
// IT1-2021-0000050対応 20210610 ADD END

	
	/**
	 * 連携実行結果判定
	 */
	private static boolean isNormal(Hashtable<String, Object> response) 
	{
		if(response==null)
		{
			return false;
		}
		
		// HTTPステータスをログ出力
		JSYejbLog.println(JSYejbLog.EXECUTION, JECKA0010001TPMA.class, "JECKA0010001TPMA#http_status=" + response.get(EXE_STATUS) );
		
		// HTTPステータス確認
		if( !Integer.toString(HttpURLConnection.HTTP_OK).equals(response.get(EXE_STATUS)))
		{
			return false;
		}
		
		// 応答コード（00000:正常）の確認
		if ( !CODE_OK.equals(response.get(RETURN_CODE)) && !CODE_OK_OTHER.equals(response.get(RETURN_CODE)) )
		{
			return false;
		}
		
		// ここまで来たら正常終了
		return true;
	}

	/**
	 * パスワードハッシュ化APIに対して送信するリクエストパラメータを作成する。
	 * @param inCBSMsg CAANメッセージ
	 * @param inContext コンテキスト
	 * @param mode 処理区分
	 * @return リクエストパラメータを返却する。
	 */
	private static String requestParamMake(CAANMsg inCBSMsg)
	{
		// リクエストパラメータ作成
		JSONObject json1kaisoMap = new JSONObject();
		
		for(String[] item : CKIFE062_REQ_INFO)
		{
			String itemName = item[0];
			String itemValue = inCBSMsg.getString(item[1]);
			
			if( !isNullBlank(itemValue) )
			{
				try {
					json1kaisoMap.put(itemName, itemValue);
				} catch (JSONException e) {
					e.printStackTrace();
				} 
			}
		}
		String jsonStr = json1kaisoMap.toString();
		if (jsonStr != null && jsonStr.trim().length()>0)
		{
			String logStr = jsonStr.replaceAll("\\s+", " ");
			logStr = maskJson(logStr, "LOGIN_PASSWORD", 64);
			JSYejbLog.println(JSYejbLog.EXECUTION, JECHA0010001TPMA.class , "JECKA0010001TPMA#request=" + logStr);
		}

		return jsonStr;
	}
	
	/**
	 * JSONをマスク
	 * 
	 * @param json マスクするJSON
	 * @param maskKey マスクするキー
	 * @param count マスクする文字数
	 * @return マスク後の文字列
	 */
	private static String maskJson(String json, String maskKey, int count)
	{
		String ret = "";
		
		if (json != null && json.trim().length()>0)
		{
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < count; i++)
			{
				sb.append("\\*");
			}
			ret = json.replaceAll("(\"" + maskKey + "\"\\s*:\\s*\")[^\"]*\"", "$1" + sb.toString() + "\"");
		}
		
		return ret;
	}

	
	/**
	 * レスポンス電文を設定します。
	 */
	private static void editOutMsg(CAANMsg inCBSMsg, Hashtable<String, Object> response, String mode)
	{
		if (response != null)
		{
			for( String[] item : CKIFE062_RES_INFO )
			{
				String itemName = item[1];
				Object itemValue = response.get(item[0]);
				inCBSMsg.set(itemName, itemValue);
			}
		}
	}
	
	/**
	 * パスワードハッシュ化APIに対して送信するリクエストパラメータを作成する。
	 */
	private static Hashtable<String, Object> callGet(String reqDataStr) throws Exception
	
	{
		Hashtable<String, Object> ret = new Hashtable<String, Object>();
		

		String httpStatus = "500";
		
		Map<String, Object> idaMap =  new HashMap<String, Object>();

		//iDA接続情報マップ作成を作成する。
		idaMap = JCKLcsRenkeiUtil.makeIdaConnectInfo("5");
		//iDAのパスワードハッシュ化APIに対してリクエスト送信する。
		
// ST-2021-0000007対応 20210529 星野 MOD START
//		String[] responseArray = JCKLcsRenkeiUtil.sendHttpRequest(idaMap, new HashMap<String, Object>(), reqData);
		
		Map<String, Object> reqData =  new HashMap<String, Object>();
		reqData.put("receiveData",reqDataStr);
		String[] responseArray = JCKLcsRenkeiUtil.sendHttpRequest(idaMap, reqData);
// ST-2021-0000007対応 20210529 星野 MOD END

		// 処理結果の取得
		httpStatus   = responseArray[0];
		String responseJson = responseArray[1];
		
		ObjectMapper mapper = new ObjectMapper();
		JsonNode root = mapper.readTree(responseJson);
		
		/**
		 * レスポンス読込処理
		 */
		ret.putAll( read(root) );

		StringBuffer sb = new StringBuffer();
		sb.append("iDA連携結果 HttpStatus=[");
		sb.append(httpStatus + "]   ");
		sb.append(ret.toString());
		// レスポンスをログ出力
// IT1-2021-0000050対応 20210610 ADD START
		JSYejbLog.println(JSYejbLog.EXECUTION, JECKA0010001TPMA.class , ("JECKA0010001TPMA#responseJson=" + 
				responseJson).replaceAll("\\s+", " ") );
//IT1-2021-0000050対応 20210610 ADD END
		JSYejbLog.println(JSYejbLog.EXECUTION, JECKA0010001TPMA.class ,("JECKA0010001TPMA#response=" +
				sb.toString()).replaceAll("\\s+", " "));
		
		
		/*
		 * HTTP 応答メッセージから状態コードを取得し設定する。 
		 * HTTP/1.0 200 OK
		 * HTTP/1.0 401 Unauthorized
		 */
		ret.put(EXE_STATUS, httpStatus);
		
		return ret;
	}

	/**
	 * ダミーjsonをコールする
	 * @param response レスポンス設定値
	 * @return レスポンス設定値
	 * @throws IOException 
	 */
	private static Hashtable<String, Object> callDummyJson(CAANMsg inCBSMsg) throws IOException
	{
		Hashtable<String, Object> response = new Hashtable<String, Object>();
		
		// HTTPステータス
		String httpStatus = JCMAPLConstMgr.getString(STUB_HTTP_STATUS_KEY);
		response.put(EXE_STATUS, httpStatus);
		
		// オペレータ_ID
		String operatorId = inCBSMsg.getString(ECKA0010001CBSMsg.OPERATORID);
		if(operatorId == null)
		{
			operatorId = "";
		}

		// JSON_PATHを取得
		String path = (String)JCCModelCommon.getApplicationConst(IDA_CONNECTION_MODE_TEST_DIR) 
							+ "/" + operatorId;
		// フォルダが存在しない場合、該当フォルダを作成する
		File dir = new File(path);
		if(!dir.exists()){
			dir.mkdirs();
		}
		
		/**
		 * レスポンスjson読込
		 */		
		String receiveFilePath = path + "/" + IF_ID + "_receive.json";
		File file = new File(receiveFilePath);
		if(!file.exists()){
			// ダミーjsonがなかった時のためのデフォルト設定
			response.put(RETURN_CODE, CODE_OK);
			
			return response;
		}
		
		ObjectMapper mapper = new ObjectMapper();
		JsonNode root = mapper.readTree(file);
		response.putAll( read(root) );

		StringBuffer sb = new StringBuffer();
		sb.append("CCMGダミーjson連携結果 HttpStatus=[");
		sb.append(httpStatus + "]   ");
		sb.append(response.toString());
		// レスポンスをログ出力
		JSYejbLog.println(JSYejbLog.EXECUTION, JECKA0010001TPMA.class ,("JECKA0010001TPMA#response=" +
				sb.toString()).replaceAll("\\s+", " "));
		
		return response;
	}
	
	/**
	 * 電文読み込み処理
	 * @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();

			// Arrayの場合
			if(fieldValue.isArray())
			{
				List<Map<String, Object>> Bodynodelist = new ArrayList<Map<String, Object>>();
				Iterator<JsonNode> itr = elem.elements();
				while(itr.hasNext())
				{
					JsonNode node = itr.next();
						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
			{
				resultMap.put(fieldName, fieldValue.textValue());
			}
		}
		
		return resultMap;
	}


	/**
	 * null又は空文字の場合、trueを返却する
	 * 
	 * @param str 検査対象文字列
	 * @return true:null、又は空文字／false:左記以外
	 */
	public static boolean isNullBlank(String str)
	{
		if (str == null || "".equals(str))
		{
			return true;
		}
		return false;
	}
}
