/*********************************************************************
*  All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名			：eo顧客基幹システム
*	モジュール名		：JBSbatKKCrecardYkRsltNgHosei
*	ソースファイル名	：JBSbatKKCrecardYkRsltNgHosei.java
*	作成者				：富士通　
*	作成日				：2024年10月16日
*＜機能概要＞
*　クレジットカード有効性結果NG補正
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v72.00.00	2024/10/16	GDC)J.Zabala		【ANK-4606-00-00】代行オーソリ結果の洗替反映対応
*********************************************************************/
package eo.business.service;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import com.fujitsu.futurity.model.common.check.LengthCheck;

import eo.business.common.JBSbatBusinessService;
import eo.business.common.JCCBatCommon;
import eo.business.util.file.JBSbatKKIFM972;
import eo.common.constant.JKKStrConst;
import eo.common.constant.JPCBatchMessageConstant;
import eo.common.util.JKKCommonUtil;
import eo.framework.application.JBSbatBusinessException;
import eo.framework.file.JBSbatInputFileUtil;
import eo.framework.item.JBSbatCommonItem;
import eo.framework.item.JBSbatOutputItem;
import eo.framework.item.JBSbatServiceInterfaceMap;
import eo.framework.util.JBSbatStringUtil;
import eo.common.util.JKKStringUtil;
/**
* (クラスの機能概要) <p>
*<BR>
* @author 富士通
*/
public class JBSbatKKCrecardYkRsltNgHosei extends JBSbatBusinessService
{
	/**▼▼▼▼▼▼ツールから生成した宣言です 開始▼▼▼▼▼▼*/
	/**▲▲▲▲▲▲ツールから生成した宣言です 終了▲▲▲▲▲▲*/

	/** レコードサイズ */
	private static final int ITEM_SIZE = 2;
	
	/** 有効性確認結果：0：有効性OK */
	private static final String YK_CFM_RSLT_OK = "0";
	
	/** 有効性確認結果：5:有効性チェック非対応カード会社 */
	private static final String YK_CFM_RSLT_UNSUPPORTED = "5";
	
	/** 有効性確認結果：X:(有効性NG(UP LOAD分) */
	private static final String YK_NG_UPLOAD_BUN = "X";

	/** エラーコード */
	private static String errCd = "";
	
	/** 置き換え文字 */
	private static String[] msgCkanMoji = null;
	
	/** 出力ファイル名 */
	private static final String INPUT_FILE = "KKIFM013002";
	
	/** 出力ファイル名 */
	private static final String OUTPUT_FILE = "KKIFM972001";

	/** 必須 */
	private static final String IS_REQUIRED = "IS_REQUIRED";

	/** 属性: 半角数字1 */
	private static final String ATTR_HLFWD_NUM_1 = "半角数字1";
	
	/** 属性: 半角英数字1 */
	private static final String ATTR_HLFWD_ALP_1 = "半角英数字1";
	
	/** 属性: 半角英数字2 */
	private static final String ATTR_HLFWD_ALP_2 = "半角英数字2";

	/** 顧客ＩＤの格納用リスト */
	private static final Set<String> custIdSet = new HashSet<String>();
	
	/** コンシューマ有効性結果補正ファイル */
	private static ArrayList<String> consCorrectionList = new ArrayList<String>();
	
	/** コンシューマ有効性チェック結果ファイル読み込み用のリスト */
	private ArrayList<String> consResultList = new ArrayList<String>();
	
	private static String KAKOIMOJI = "\"";
	
	/** コンシューマ有効性結果補正ファイル存在フラグ */
	private boolean consCorrectionExistFlg = false;
	
	/** コンシューマ有効性結果補正ファイルチェックエラーチェック結果フラグ */
	private boolean consCorrectionChkErrResultFlg = true;
	
	/** コンシューマ有効性結果補正ファイルチェックエラーコード */
	private static String consCorrectionChkErrCode = "";
	
	/** コンシューマ有効性結果補正ファイルチェック置き換え文字 */
	private static String[] consCorrectionChkMsgCkanMoji = null;
	
	/** コンシューマ有効性結果補正預かりＩＤ未存在リスト */
	private static final ArrayList<String> missingCredIdList = new ArrayList<String>();
	
	/**
	 * 初期処理
	 * @param JBSbatCommonItem commonItem　バッチ共通パラメータ電文
	 * @throws Exception
	 */
	public void initial(JBSbatCommonItem commonItem) throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの初期処理を記述してください。▼▼▼▼▼▼*/
		/**▼▼▼▼▼▼ツールから生成した初期化のソースです 開始▼▼▼▼▼▼*/
		super.setCommonInfo(commonItem);
		/**▲▲▲▲▲▲ツールから生成した初期化のソースです 終了▲▲▲▲▲▲*/
		
		
		String strFreeParam = commonItem.getFreeItem();
		
		// パラメータを区切り文字で分割する
		String[] lines = strFreeParam.split(JKKStrConst.SEMI_COLON);
		
		// ファイル名(コンシューマ有効性チェック結果ファイル)
		String resultFile = lines[0];
		
		// ファイル名(コンシューマ有効性結果補正ファイル)
		String correctionFile = lines[1];
		
		// コンシューマ有効性チェック結果ファイル読み込み
		consResultList = readFile(resultFile);
		
		// コンシューマ有効性結果補正ファイルが存在するかどうかを確認します。
		if(isFileExist(correctionFile))
		{
			
			//ファイルが存在していたらフラグをtrueに
			consCorrectionExistFlg = true;
			
			// コンシューマ有効性結果補正ファイル
			consCorrectionList = readFile(correctionFile);
			
			// コンシューマ有効性結果補正ファイルのチェック処理
			consCorrectionChkErrResultFlg = isProcessItemCheck(correctionFile);
		}
		
		
	/**▲▲▲▲▲▲業務サービスの初期処理を記述してください。▲▲▲▲▲▲*/
	}

	/**
	 * 主処理
	 * @return JBSbatOutputItem　出力情報
	 * @throws Exception
	 */
	public JBSbatOutputItem execute(JBSbatServiceInterfaceMap inMap) throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの主処理を記述してください。▼▼▼▼▼▼*/
		// 出力共通電文を生成する。
		JBSbatOutputItem outputBean = new JBSbatOutputItem();
				
		//もし以下の条件のどちらかを満たしてたら、入力ファイルをそのまま出力する
		//consCorrectionExistFlgがfalse
		//consCorrectionChkErrResultFlgがfalse
		
		if(!consCorrectionExistFlg || !consCorrectionChkErrResultFlg)
		{
			// コンシューマ有効性チェック結果ファイル補正処理
			outputBean = createKkifm972(inMap,false);

		}
		else
		{
			// コンシューマ有効性チェック結果ファイル補正処理
			outputBean = createKkifm972(inMap,true);
		}
		
		
		return outputBean;
		/**▲▲▲▲▲▲業務サービスの主処理を記述してください。▲▲▲▲▲▲*/
	}
	
	
	/**
	 * コンシューマ有効性結果ファイルのチェック処理。<br>
	 * 
	 * @param resultFile ファイル名(コンシューマ有効性チェック結果ファイル)
	 * @param correctionFile ファイル名(コンシューマ有効性結果補正ファイル)
	 * @throws Exception 
	 */
	private boolean isProcessItemCheck(String correctionFileName) throws Exception
	{
		for(int i = 0; i < consCorrectionList.size(); i++)
		{
			String[] consData = consCorrectionList.get(i).split(JKKStrConst.KDDI_CONMA, -1);
			// 項目数チェック
			if(ITEM_SIZE != consData.length)
			{
				consCorrectionChkErrCode = JPCBatchMessageConstant.EKKB2330AI;
				consCorrectionChkMsgCkanMoji = new String[] {correctionFileName, String.valueOf(i + 1), consCorrectionList.get(i) };
				return false;
			}
			String seikyKeiNo = checkQuotation(consData[0]); // 請求契約番号
			String crecardNoAzkriId = checkQuotation(consData[1]); // クレジットカード番号預りＩＤ
			
			// 列表現 : 0 - 項目名 , 1 - 必須, 2 - 形式, 3 - 最小, 4 - 最大, 5 - データ
			String[][] recordDefinition = {
					{ "請求契約番号", IS_REQUIRED, ATTR_HLFWD_ALP_1, "10", "10", seikyKeiNo },
					{ "クレジットカード番号預りＩＤ", IS_REQUIRED, ATTR_HLFWD_ALP_1, "16", "16", crecardNoAzkriId },
			};
			
			// 項目チェック（必須・属性・桁数チェック）を行う。
			for(String[] arrayData : recordDefinition)
			{
				// 必須エラーの場合
				if(checkRequired(correctionFileName, arrayData, i))
				{
					return false;
				}
				// 属性エラーの場合
				if(checkAttribute(correctionFileName, arrayData, i))
				{
					return false;
				}
				// 桁数エラーの場合
				if(checkDigits(correctionFileName, arrayData, i))
				{
					return false;
				}
			}
			if(!consCorrectionChkErrCode.isEmpty())
			{
				return false;
			}

		}
		// 「クレジットカード番号預りID」存在チェック
		checkCredCardId();
		
		return true;
		
	}
	
	/**
	 * 「クレジットカード番号預りID」存在チェック
	 * 
	 * @param resultFile コンシューマ有効性チェック結果ファイル
	 * @param correctionFile コンシューマ有効性結果補正ファイル
	 * @throws Exception 
	 */
	private void checkCredCardId() throws Exception 
	{
		
		/** コンシューマ有効性チェック結果ファイルの預かりＩＤの格納用リスト */
		Set<String> consResultCustIdSet = new HashSet<String>();


		//コンシューマ有効性チェック結果ファイルの預かりＩＤの格納用リスト作成
		for(int i = 0; i < consResultList.size(); i++)
		{
			String[] consData = consResultList.get(i).split(JKKStrConst.KDDI_CONMA, -1);
			
			if(consData.length >= 3 && !consResultCustIdSet.contains(consData[2]))
			{
				consResultCustIdSet.add(consData[2]);
			}
		}
		
		for(int i = 0; i < consCorrectionList.size(); i++)
		{
			String[] corrData = consCorrectionList.get(i).split(JKKStrConst.KDDI_CONMA, -1);
			if(consResultCustIdSet.contains(corrData[1]))
			{
				// コンシューマ有効性結果補正ファイルの預かりＩＤを顧客ＩＤリストに格納する
				custIdSet.add(corrData[1]);
			}
			else
			{
				missingCredIdList.add(corrData[1]);
			}
		}
	}
	
	/**
	 * ダブルクォーテーションをチェックする。<br>
	 * 
	 * @param data 入力ファイルの行データ
	 * @throws JBSbatBusinessException 業務サービス内で発生した例外全般。
	 */
	private String checkQuotation(String data) throws JBSbatBusinessException
	{
		String colm = data;
		// 先頭 または 最後がダブルクォートの場合
		if (colm.startsWith(KAKOIMOJI))
		{
			colm = colm.substring(1);
		}
		if (colm.endsWith(KAKOIMOJI))
		{
			colm = colm.substring(0, colm.length() - 1);
		}
		return colm;
	}
	
	/**
	 * 必須エラーチェック。<br>
	 * 
	 * @param fileName ファイル名(有効性チェック結果データファイル)
	 * @param data 入力ファイルの行データ
	 * @param index ループの現在のインデックス
	 * @return true:エラーあり false:エラーなし
	 * @throws JBSbatBusinessException 業務サービス内で発生した例外全般。
	 */
	private boolean checkRequired(String fileName, String[] data, int index) throws JBSbatBusinessException
	{
		// 0 - 項目名
		// 1 - 必須
		// 5 - データ
		if (IS_REQUIRED.equals(data[1]))
		{
			if (JKKCommonUtil.isNull(data[5]))
			{
				// 必須エラーの場合
				consCorrectionChkErrCode = JPCBatchMessageConstant.EKKB2340AI;
				consCorrectionChkMsgCkanMoji = new String[] {fileName, String.valueOf(index + 1), data[0] };
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 属性エラーを確認します。<br>
	 * 
	 * @param fileName ファイル名(有効性チェック結果データファイル)
	 * @param data 入力ファイルの行データ
	 * @param index ループの現在のインデックス
	 * @return true:エラーあり false:エラーなし
	 * @throws JBSbatBusinessException 
	 */
	private boolean checkAttribute(String fileName, String[] data, int index) throws JBSbatBusinessException
	{
		// 0 - 項目名
		// 2 - 形式
		// 5 - データ
		if (!JKKCommonUtil.isNull(data[5]))
		{
			// 半角英数字1
			if (ATTR_HLFWD_ALP_1.equals(data[2]))
			{
				if (!JCCBatCommon.isHannkakuESuuji1(data[5]))
				{
					// 属性エラーの場合
					consCorrectionChkErrCode = JPCBatchMessageConstant.EKKB2350AI;
					consCorrectionChkMsgCkanMoji = new String[] {fileName, String.valueOf(index + 1), data[0] };
					return true;
				}
			
			}
			// 半角英数字2 
			else if (ATTR_HLFWD_ALP_2.equals(data[2]))
			{
				if (!JCCBatCommon.isHannkakuESuuji2(data[5]))
				{
					// 属性エラーの場合
					consCorrectionChkErrCode = JPCBatchMessageConstant.EKKB2350AI;
					consCorrectionChkMsgCkanMoji = new String[] {fileName, String.valueOf(index + 1), data[0] };
					return true;
				}
			
			}
			// 半角数字1 
			else if (ATTR_HLFWD_NUM_1.equals(data[2]))
			{
				if (!JCCBatCommon.isHannkakuSuuji1(data[5]))
				{
					// 属性エラーの場合
					consCorrectionChkErrCode = JPCBatchMessageConstant.EKKB2350AI;
					consCorrectionChkMsgCkanMoji = new String[] {fileName, String.valueOf(index + 1), data[0] };
					return true;
				}
			
			}
		}
		return false;
	}
	
	/**
	 * 桁エラーチェックを実行します。<br>
	 * 
	 * @param fileName ファイル名(有効性チェック結果データファイル)
	 * @param data 入力ファイルの行データ
	 * @param index ループの現在のインデックス
	 * @return true:エラーあり false:エラーなし
	 * @throws JBSbatBusinessException 業務サービス内で発生した例外全般。
	 */
	private boolean checkDigits(String fileName, String[] data, int index) throws JBSbatBusinessException
	{
		// 0 - 項目名
		// 3 - 最小
		// 4 - 最大
		// 5 - データ
		if (!JKKCommonUtil.isNull(data[5]))
		{
			// 桁数チェック
			if(!LengthCheck.isLength2Check(data[5], Integer.parseInt(data[3]), Integer.parseInt(data[4])))
			{
				// 桁数エラーの場合
				consCorrectionChkErrCode = JPCBatchMessageConstant.EKKB2360AI;
				consCorrectionChkMsgCkanMoji = new String[] {fileName, String.valueOf(index + 1), data[0] };
				return true;
			}
		}
		return false;
	}

	/**
	 * ファイル読み込み処理を行います。<br>
	 * <p>
	 * <b>処理フロー</b><br>
	 * <pre>
	 * 1.引数で読込ファイルディレクトリ(フルパス)を設定します。<br>
	 *
	 * 2.引数を元にファイル読込を行い、行をListへ格納します。<br>
	 * 
	 * </pre>
	 * <p>
	 * @param strFileDir    出力ディレクトリ(フルパス)。
	 * @return resultList   返却用List
	 * @throws Exception    業務サービス内で発生した例外全般。
	 */
	private static ArrayList<String> readFile(String strFileDir) throws Exception
	{
		ArrayList<String> resultList = new ArrayList<String>();
		File file = new File(strFileDir);
		if(!file.exists()){
			return resultList;
		}
		// 外部出力ファイルパス
		JBSbatInputFileUtil inFile = new JBSbatInputFileUtil(strFileDir);
		inFile.setEncode(JKKStrConst.ENCODE_SJIS); // 文字コード
		inFile.setLine(JKKStrConst.LINE_SEPARATOR); // 改行コード
		inFile.createReader();
		try
		{
			while (true) 
			{
				String line = inFile.readLine();
				if (line == null)
				{
					inFile.close();
					break;
				}
				resultList.add(line);
			}
			return resultList;
		} 
		catch (IOException e)
		{
			throw e;
		} 
		finally
		{
			inFile.close();
		}
	}
	
	
	/**
	 * ファイルが存在するかどうかを確認する。<br>
	 * <p>
	 * <b>処理フロー</b><br>
	 * <pre>
	 * 
	 * </pre>
	 * <p>
	 * @param strFileDir    出力ディレクトリ(フルパス)。
	 */
	private boolean isFileExist(String strFileDir) 
	{
		File file = new File(strFileDir);
		if(!file.exists()){
			return false;
		}
		return true;
	}
	
	/**
	 * 
	 *  変更されたコンシューマ有効性結果補正ファイルを作成
	 *  
	 * @return outputBean JBSbatOutputItem
	 * @throws Exception メソッド内で発生した例外全般。
	 */
	private JBSbatOutputItem createKkifm972(JBSbatServiceInterfaceMap inMap, boolean hoseFlg) throws Exception
	{
		// 出力共通電文を生成する。
		JBSbatOutputItem outputBean = new JBSbatOutputItem();
		

		//入出力インターフェースオブジェクトを生成
		JBSbatServiceInterfaceMap outmap = new JBSbatServiceInterfaceMap();
		
		//項目を設定
		outmap.setString(JBSbatKKIFM972.REC_ID, JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.REC_ID)));						// レコードＩＤ
		outmap.setString(JBSbatKKIFM972.SITE_ID,JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.SITE_ID)));						// サイトＩＤ
		outmap.setString(JBSbatKKIFM972.CUST_ID,JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.CUST_ID)));						// 顧客ＩＤ
		outmap.setString(JBSbatKKIFM972.CUST_CARD_ID,JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.CUST_CARD_ID)));					// 顧客カードＩＤ
		
		//顧客ＩＤ
		String custId = JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.CUST_ID)); 
		
		//有効性判定結果
		String ykJdgRrslt = JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.YK_JDGRSLT)); 
		
		//補正フラグがtrueかつ、顧客ＩＤの格納用リストに預かりＩＤが存在する
		if (hoseFlg && !JKKStringUtil.isNullBlank(custId) && custIdSet.contains(custId)) 
		{
			if(!JKKStringUtil.isNullBlank(ykJdgRrslt) 
					&& (YK_CFM_RSLT_OK.equals(ykJdgRrslt) || YK_CFM_RSLT_UNSUPPORTED.equals(ykJdgRrslt)))
			{
				ykJdgRrslt = YK_NG_UPLOAD_BUN;
			}
		}
		
		outmap.setString(JBSbatKKIFM972.YK_JDGRSLT, ykJdgRrslt);					// 有効性判定結果
		outmap.setString(JBSbatKKIFM972.CARD_NO_UPD_SAIN, JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.CARD_NO_UPD_SAIN)));				// カード番号更新サイン
		outmap.setString(JBSbatKKIFM972.YK_KIGEN_UPD_SAIN, JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.YK_KIGEN_UPD_SAIN)));			// 有効期限更新サイン
		outmap.setString(JBSbatKKIFM972.MASK_CARD_NO, JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.MASK_CARD_NO)));					// マスクされたカード番号
		outmap.setString(JBSbatKKIFM972.CARD_YK_KIGEN, JBSbatStringUtil.Rtrim(inMap.getString(JBSbatKKIFM972.CARD_YK_KIGEN)));				// カード有効期限
		
		//出力フラグを設定
		outmap.setOutFlg(true);
		//出力共通電文に入出力インターフェースを設定する。
		outputBean.addOutMapList(outmap);
		
		//出力共通電文を返却
		return outputBean;

	}
	
	/**
	 * 業務サービス終了処理
	 * @throws Exception
	 */
	public void terminal() throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの終了処理を記述してください。▼▼▼▼▼▼*/
		/**▼▼▼▼▼▼ツールから生成した終了処理のソースです 開始▼▼▼▼▼▼*/
		/**▲▲▲▲▲▲ツールから生成した終了処理のソースです 終了▲▲▲▲▲▲*/
		
		
		//もし以下の条件を満たしてたら、エラーを出力する
		//consCorrectionChkErrResultFlgがfalse
		if(!consCorrectionChkErrResultFlg)
		{
			super.logPrint.printBusinessErrorLog(consCorrectionChkErrCode, consCorrectionChkMsgCkanMoji);
			super.logPrint.printBusinessErrorLog(JPCBatchMessageConstant.EKKB2380JW);
			super.commonItem.addErrorCount(1);
			
			return;
		}
		
		//もし以下の条件を満たしてたら、エラーを出力する
		//missingCredIdListが空でない
		if(!missingCredIdList.isEmpty())
		{
			
			// エラーレコードの出力情報
			for(String id : missingCredIdList)
			{
				errCd = JPCBatchMessageConstant.EKKB2370AI;
				msgCkanMoji = new String[] {id};
				logPrint.printBusinessErrorLog(errCd, msgCkanMoji);
			}
			
			super.logPrint.printBusinessErrorLog(JPCBatchMessageConstant.EKKB2390JW);
			
			return;
		} 
		
		
	/**▲▲▲▲▲▲業務サービスの終了処理を記述してください。▲▲▲▲▲▲*/
	}
	/**▼▼▼▼▼▼ツールから生成したメソッドです 開始▼▼▼▼▼▼*/
	/**▲▲▲▲▲▲ツールから生成したメソッドです 終了▲▲▲▲▲▲*/
}
