/*********************************************************************
 *  All Rights reserved,Copyright (c) K-Opticom
 **********************************************************************
 *＜プログラム内容＞
 *	システム名			：eo顧客基幹システム
 *	モジュール名		：JBSbatCHKsdTrgtsUcwkKshkmCp
 *	ソースファイル名	：JBSbatCHKsdTrgtsUcwkKshkmCp.java
 *	作成者				：富士通　
 *	作成日				：2023年10月25日
 *＜機能概要＞
 *　貸倒れ対象者内訳消込（ＣＰ）部品です。
 *＜修正履歴＞
 *	バージョン	修正日		修正者		修正内容
 *	v68.00.00   2023/10/25  FJ)森脇		【ANK-4475-00-00】インボイス対応 STEP2
 *********************************************************************/
package eo.business.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import eo.business.common.JACbatDebugLogUtil;
import eo.business.common.JBSbatBusinessService;
import eo.business.common.JBSbatMatchServiceInterface;
import eo.business.util.file.JBSbatCHIFM441;
import eo.business.util.file.JBSbatCHIFM444;
import eo.common.constant.JACStrConst;
import eo.framework.item.JBSbatCommonItem;
import eo.framework.item.JBSbatOutputItem;
import eo.framework.item.JBSbatServiceInterfaceMap;

/**
 * (クラスの機能概要)
 * <p>
 *<BR>
 * 
 * @author 富士通
 */
public class JBSbatCHKsdTrgtsUcwkKshkmCp extends JBSbatBusinessService implements JBSbatMatchServiceInterface
{
	/** ▼▼▼▼▼▼ツールから生成した宣言です 開始▼▼▼▼▼▼ */
	/** キーマッチ処理フラグ */
	private boolean matchProcFlg;

	/** マスタファイル処理フラグ */
	private boolean mastProcFlg;

	/** トランファイル処理フラグ */
	private boolean tranProcFlg;
	/** ▲▲▲▲▲▲ツールから生成した宣言です 終了▲▲▲▲▲▲ */

	/** free項目 */
	private String[] freeItems = null;

	/** 入力Ｍ読み込み終了回数 */
	private int intMstCntEnd = 0; 
	
	/** 入力Ｔ読み込み終了回数 */
	private int intTrnCntEnd = 0; 
	
	/** マスタレコードキー保持用 **/
	private String matchingKeyMastTmp = null;

	/** トランレコードキー保持用 **/
	private String matchingKeyTranTmp = null;

	/** マスタレコード保持キー **/
	private String mastKeyTmp = null;

	/** マスタレコード保持キー **/
	private String tranKeyTmp = null;

	/** マスタレコード保持用 **/
	private List<JBSbatServiceInterfaceMap> mastMapList = new ArrayList<JBSbatServiceInterfaceMap>();

	/** トランレコード保持用 **/
	private List<JBSbatServiceInterfaceMap> tranMapList = new ArrayList<JBSbatServiceInterfaceMap>();

	/** 最終行読込フラグ（マスタ） **/
	boolean readEndRecordMast = false;

	/** 最終行読込フラグ（トラン） **/
	boolean readEndRecordTran = false;

	/**
	 * 初期処理
	 * 
	 * @param JBSbatCommonItem commonItem バッチ共通パラメータ電文
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	public void initial(JBSbatCommonItem commonItem) throws Exception
	{
		/** ▼▼▼▼▼▼業務サービスの初期処理を記述してください。▼▼▼▼▼▼ */
		/** ▼▼▼▼▼▼ツールから生成した初期化のソースです 開始▼▼▼▼▼▼ */
		// 共通パラメータを設定します
		super.setCommonInfo(commonItem);
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][initial]");
		/** ▲▲▲▲▲▲ツールから生成した初期化のソースです 終了▲▲▲▲▲▲ */

		// free項目を取得
		String freeItem = commonItem.getFreeItem();
		freeItems = freeItem.split(JACStrConst.FREE_DIV);
		
		// 入力Ｍファイル行数取得
		intMstCntEnd = Integer.parseInt(freeItems[0]);
		// 入力Ｔファイル行数取得
		intTrnCntEnd = Integer.parseInt(freeItems[1]);

		super.logPrint.printDebugLog("入力Ｍファイル行数：" + intMstCntEnd);
		super.logPrint.printDebugLog("入力Ｔファイル行数：" + intTrnCntEnd);

		/** ▲▲▲▲▲▲業務サービスの初期処理を記述してください。▲▲▲▲▲▲ */
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][initial][opeDate=" + super.opeDate + "]");
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][initial][freeItem=" + super.freeItem + "]");
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][initial]");
	}

	/**
	 * 主処理
	 * 
	 * @param mastMap 入力電文
	 * @param tranMap 入力電文
	 * @param outputInItem 入力情報
	 * @return JBSbatOutputItem 出力情報
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	public JBSbatOutputItem execute(JBSbatServiceInterfaceMap mastMap, JBSbatServiceInterfaceMap tranMap, JBSbatOutputItem outputInItem) throws Exception
	{
		/** ▼▼▼▼▼▼業務サービスの主処理を記述してください。▼▼▼▼▼▼ */
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][execute]");
		assert mastMap != null ? JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][execute][mastMap=" + mastMap.getMap().toString() + "]") : true;
		assert tranMap != null ? JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][execute][tranMap=" + tranMap.getMap().toString() + "]") : true;

		// 読込単位
		String mastKey = new String();
		String tranKey = new String();

		// マッチングキー・リスト作成

		if (mastMap != null)
		{
			// 入力Ｍが存在する場合

			// マスタレコード読込
			mastKey = getMastKey(mastMap);

			if (mastKeyTmp == null || mastKey.compareTo(mastKeyTmp) <= 0)
			{
				// 初回、またはキーが変わるまで読込
				this.setMastProcFlg(true);

				readRecordMast(mastMap);
				
				if (super.commonItem.getInputCount() < intMstCntEnd)
				{
					// 最終行でない場合は次レコード
					return outputInItem;
				}
			}
			else
			{
				// 消込処理へ
			}
		}
		if (tranMap != null)
		{
			// 入力Ｔが存在する場合

			// トランレコード読込
			tranKey = getMatchingKey(tranMap);

			if (tranKeyTmp == null || tranKey.compareTo(tranKeyTmp) <= 0)
			{
				// 初回、またはキーが変わるまで読込
				this.setTranProcFlg(true);

				readRecordTran(tranMap);

				if (super.commonItem.getInputCount2() < intTrnCntEnd)
				{
					// 最終行でない場合は次レコード
					return outputInItem;
				}
			}
			else
			{
				// 消込処理へ
			}
		}

		// 消込処理

		this.setMastProcFlg(false);
		this.setTranProcFlg(false);

		if (!mastMapList.isEmpty() && tranMapList.isEmpty())
		{
			assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][execute][入力Ｍのみ存在する]");
			// 入力Ｍのみ存在する場合
			
			// マスタ出力
			outPutMapMast(outputInItem);
		}
		else if (mastMapList.isEmpty() && !tranMapList.isEmpty())
		{
			assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][execute][入力Ｔのみ存在する]");
			// 入力Ｔのみ存在する場合

			// トラン出力
			outPutMapTran(outputInItem);
		}
		else
		{
			// 入力Ｍ、入力Ｔともに存在する

			if (matchingKeyMastTmp.compareTo(matchingKeyTranTmp) == 0)
			{
				assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][execute][入力Ｍ、入力Ｔともに存在する][入力Ｍ＝入力Ｔ]");
				// 入力Ｍ = 入力Ｔ

				BigDecimal mastAmnt = BigDecimal.ZERO;
				BigDecimal tranAmnt = BigDecimal.ZERO;

				for (int i = 0; i < mastMapList.size(); i++)
				{
					// 減額残
					mastAmnt = mastMapList.get(0).getBigDecimal(JBSbatCHIFM444.SAIKEN_AMNT);

					if (mastAmnt.compareTo(BigDecimal.ZERO) > 0)
					{
						// 減額残がマイナスでない場合対象外
						continue;
					}

					for (int j = 0; j < tranMapList.size(); j++)
					{
						// 引代残
						tranAmnt = tranMapList.get(j).getBigDecimal(JBSbatCHIFM444.SAIKEN_AMNT);

						// マッチングキー（マスタ）を作成
						String matMastKey = getMatchingKeyMast(mastMapList.get(i));

						// マッチングキー（トラン）を作成
						String matTranKey = getMatchingKeyTran(tranMapList.get(j));

						if (matMastKey.compareTo(matTranKey) == 0)
						{
							if (tranAmnt.abs().compareTo(mastAmnt.abs()) >= 0)
							{
								// 引代残が減額残より大きい場合

								// 引代残に 引代残 - 減額残 を設定
								tranAmnt = tranAmnt.add(mastAmnt);
								tranMapList.get(j).setBigDecimal(JBSbatCHIFM444.SAIKEN_AMNT,tranAmnt);

								// 減額残に 0 を設定
								mastAmnt = BigDecimal.ZERO;
								mastMapList.get(0).setBigDecimal(JBSbatCHIFM444.SAIKEN_AMNT,mastAmnt);
							}
							else
							{
								// 減額残が引代残より大きい場合

								// 減額残に 減額残 - 引き代金額 を設定
								mastAmnt = mastAmnt.add(tranAmnt);
								mastMapList.get(0).setBigDecimal(JBSbatCHIFM444.SAIKEN_AMNT,mastAmnt);

								// 引代残に 0 を設定
								tranAmnt = BigDecimal.ZERO;
								tranMapList.get(j).setBigDecimal(JBSbatCHIFM444.SAIKEN_AMNT,tranAmnt);
							}
						}
					}
				}
				
				// マスタ出力
				outPutMapMast(outputInItem);
			}
			else if (matchingKeyMastTmp.compareTo(matchingKeyTranTmp) < 0)
			{
				assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][execute][入力Ｍ、入力Ｔともに存在する][入力Ｍ＜入力Ｔ]");
				// 入力Ｍ < 入力Ｔ

				// マスタ出力
				outPutMapMast(outputInItem);
			}
			else
			{
				assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][execute][入力Ｍ、入力Ｔともに存在する][入力Ｍ＞入力Ｔ]");
				// 入力Ｍ > 入力Ｔ

				// トラン出力
				outPutMapTran(outputInItem);
			}
		}

		// 次レコード読込

		if (isMastProcFlg())
		{
			// マスタレコード
			readRecordMast(mastMap);
		}
		if (isTranProcFlg())
		{
			// トランレコード
			readRecordTran(tranMap);
		}
		if (super.commonItem.getInputCount() < intMstCntEnd
				|| super.commonItem.getInputCount2() < intTrnCntEnd)
		{
			// 最終行の場合は出力処理へ
			return outputInItem;
		}

		// 最終行出力処理

		if (super.commonItem.getInputCount() >= intMstCntEnd)
		{
			readRecordMast(mastMap);

			if (!mastMapList.isEmpty())
			{
				// マスタ出力
				outPutMapMast(outputInItem);
			}
		}
		if (super.commonItem.getInputCount2() >= intTrnCntEnd)
		{
			readRecordTran(tranMap);

			if (!tranMapList.isEmpty())
			{
				// トラン出力
				outPutMapTran(outputInItem);
			}
		}

		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][execute]");
		return outputInItem;
		/** ▲▲▲▲▲▲業務サービスの主処理を記述してください。▲▲▲▲▲▲ */
	}

	/**
	 * 業務サービス終了処理
	 * 
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	public void terminal() throws Exception
	{
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][terminal]");
		/** ▼▼▼▼▼▼業務サービスの終了処理を記述してください。▼▼▼▼▼▼ */
		/** ▼▼▼▼▼▼ツールから生成した終了処理のソースです 開始▼▼▼▼▼▼ */
		/** ▲▲▲▲▲▲ツールから生成した終了処理のソースです 終了▲▲▲▲▲▲ */

		/** ▲▲▲▲▲▲業務サービスの終了処理を記述してください。▲▲▲▲▲▲ */
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][terminal]");
	}

	/** ▼▼▼▼▼▼ツールから生成したメソッドです 開始▼▼▼▼▼▼ */
	/**
	 * @return mastProcFlg を戻します。
	 */
	public boolean isMastProcFlg()
	{
		return mastProcFlg;
	}

	/**
	 * @return matchProcFlg を戻します。
	 */
	public boolean isMatchProcFlg()
	{
		return matchProcFlg;
	}

	/**
	 * @return tranProcFlg を戻します。
	 */
	public boolean isTranProcFlg()
	{
		return tranProcFlg;
	}

	/**
	 * @param mast_ProcFlg 設定する mastProcFlg。
	 */
	public void setMastProcFlg(boolean mast_ProcFlg)
	{
		this.mastProcFlg = mast_ProcFlg;
	}

	/**
	 * @param match_ProcFlg 設定する matchProcFlg。
	 */
	public void setMatchProcFlg(boolean match_ProcFlg)
	{
		this.matchProcFlg = match_ProcFlg;
	}

	/**
	 * @param tran_ProcFlg 設定する tranProcFlg。
	 */
	public void setTranProcFlg(boolean tran_ProcFlg)
	{
		this.tranProcFlg = tran_ProcFlg;
	}

	/** ▲▲▲▲▲▲ツールから生成したメソッドです 終了▲▲▲▲▲▲ */

	/**
	 * 引数で渡された情報をもとにマッチング用のキーを作成し、返却します。
	 * 
	 * @param trgMap 対象情報
	 * @return String マッチングキー
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private String getMastKey(JBSbatServiceInterfaceMap inMap) throws Exception
	{
		StringBuffer buf = new StringBuffer();

		// 請求契約番号
		buf.append(inMap.getString(JBSbatCHIFM444.SEIKY_KEI_NO));

		// 債権番号
		buf.append(inMap.getString(JBSbatCHIFM444.SAIKEN_NO));

		// 処理順
		String trnJun =String.format("%03d", new Integer(inMap.getInt(JBSbatCHIFM444.TRN_JUN)));
		buf.append(trnJun);

		// 不課税識別
		buf.append(inMap.getString(JBSbatCHIFM444.FUKAZEI_TAX_RT_SKBT));

		// 料金項目コード
		buf.append(inMap.getString(JBSbatCHIFM444.PRC_KMK_CD));

		return buf.toString();
	}

	/**
	 * 引数で渡された情報をもとにマッチング用のキーを作成し、返却します。
	 * 
	 * @param trgMap 対象情報
	 * @return String マッチングキー
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private String getMatchingKey(JBSbatServiceInterfaceMap inMap) throws Exception
	{
		StringBuffer buf = new StringBuffer();

		// 請求契約番号
		buf.append(inMap.getString(JBSbatCHIFM444.SEIKY_KEI_NO));

		// 債権番号
		buf.append(inMap.getString(JBSbatCHIFM444.SAIKEN_NO));

		// 処理順
		String trnJun =String.format("%03d", new Integer(inMap.getInt(JBSbatCHIFM444.TRN_JUN)));
		buf.append(trnJun);

		// 不課税識別
		buf.append(inMap.getString(JBSbatCHIFM444.FUKAZEI_TAX_RT_SKBT));

		return buf.toString();
	}

	/**
	 * 引数で渡された情報をもとにマッチング用のキーを作成し、返却します。
	 * 
	 * @param trgMap 対象情報
	 * @return String マッチングキー
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private String getMatchingKeyMast(JBSbatServiceInterfaceMap inMap) throws Exception
	{
		StringBuffer buf = new StringBuffer();

		// 請求契約番号
		buf.append(inMap.getString(JBSbatCHIFM444.SEIKY_KEI_NO));

		// 債権番号
		buf.append(inMap.getString(JBSbatCHIFM444.SAIKEN_NO));

		// 処理順
		String trnJun =String.format("%03d", new Integer(inMap.getInt(JBSbatCHIFM444.TRN_JUN)));
		buf.append(trnJun);

		// 不課税識別
		buf.append(inMap.getString(JBSbatCHIFM444.FUKAZEI_TAX_RT_SKBT));

		// 集計料金項目コード
		buf.append(inMap.getString(JBSbatCHIFM444.SHUK_PRC_KMK_CD));

		return buf.toString();
	}

	/**
	 * 引数で渡された情報をもとにマッチング用のキーを作成し、返却します。
	 * 
	 * @param trgMap 対象情報
	 * @return String マッチングキー
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private String getMatchingKeyTran(JBSbatServiceInterfaceMap inMap) throws Exception
	{
		StringBuffer buf = new StringBuffer();

		// 請求契約番号
		buf.append(inMap.getString(JBSbatCHIFM441.SEIKY_KEI_NO));

		// 債権番号
		buf.append(inMap.getString(JBSbatCHIFM441.SAIKEN_NO));

		// 処理順
		String trnJun =String.format("%03d", new Integer(inMap.getInt(JBSbatCHIFM444.TRN_JUN)));
		buf.append(trnJun);

		// 不課税識別
		buf.append(inMap.getString(JBSbatCHIFM441.FUKAZEI_TAX_RT_SKBT));

		// 料金項目コード
		buf.append(inMap.getString(JBSbatCHIFM441.PRC_KMK_CD));

		return buf.toString();
	}

	/**
	 * マスタレコードを読込み、マッチング用の情報を作成します。
	 * 
	 * @param trgMap 対象情報
	 * @return String マッチングキー
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private void readRecordMast(JBSbatServiceInterfaceMap mastMap) throws Exception
	{
		if (mastMap != null)
		{
			if (!readEndRecordMast)
			{
				// マスタレコード読込
				mastMapList.add(mastMap);

				mastKeyTmp = getMastKey(mastMap);
				matchingKeyMastTmp = getMatchingKey(mastMap);
			}
			if (super.commonItem.getInputCount() >= intMstCntEnd)
			{
				// 最終行読込済
				readEndRecordMast = true;
			}
		}
	}

	/**
	 * トランレコードを読込み、マッチング用の情報を作成します。
	 * 
	 * @param trgMap 対象情報
	 * @return String マッチングキー
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private void readRecordTran(JBSbatServiceInterfaceMap tranMap) throws Exception
	{
		if (tranMap != null)
		{
			if (!readEndRecordTran)
			{
				// トランレコード読込
				tranMapList.add(tranMap);

				tranKeyTmp = getMatchingKey(tranMap);
				matchingKeyTranTmp = getMatchingKey(tranMap);
			}
			if (super.commonItem.getInputCount2() >= intTrnCntEnd)
			{
				// 最終行読込済
				readEndRecordTran = true;
			}
		}
	}

	/**
	 * データ出力（マスタ）
	 * 
	 * @param inMapList 入力電文
	 * @param outputInItem 入力情報
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private void outPutMapMast(JBSbatOutputItem outputInItem) throws Exception
	{
		this.setMastProcFlg(true);

		// 出力情報生成
		makeOutPutMap(mastMapList.get(0), outputInItem);
		mastMapList.clear();
	}

	/**
	 * データ出力（トラン）
	 * 
	 * @param inMapList 入力電文
	 * @param outputInItem 入力情報
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private void outPutMapTran(JBSbatOutputItem outputInItem) throws Exception
	{
		this.setTranProcFlg(true);

		// 出力情報生成
		makeOutPutMapList(tranMapList, outputInItem);
		tranMapList.clear();
	}

	/**
	 * 出力データ編集（リスト）
	 * 
	 * @param inMapList 入力電文
	 * @param outputInItem 入力情報
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private void makeOutPutMapList(List<JBSbatServiceInterfaceMap> inMapList, JBSbatOutputItem outputInItem) throws Exception
	{
		for (int i = 0; i < inMapList.size(); i++)
		{
			makeOutPutMap(inMapList.get(i),outputInItem);
		}
	}

	/**
	 * 出力データ編集
	 * 
	 * @param inMap 入力電文
	 * @param outputInItem 入力情報
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private void makeOutPutMap(JBSbatServiceInterfaceMap inMap, JBSbatOutputItem outputInItem) throws Exception
	{
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][makeOutPutMap]");

		JBSbatServiceInterfaceMap outputMap = new JBSbatServiceInterfaceMap();

		// 入力電文コピー
		outputMap.setMap(inMap.getMap());

		if (outputMap.getBigDecimal(JBSbatCHIFM441.SAIKEN_AMNT).compareTo(BigDecimal.ZERO) == 0)
		{
			// 金額が 0 の場合は出力対象外
			return;
		}

		// 出力フラグを設定
		outputMap.setOutFlg(true);

		// 出力共通電文に設定
		outputInItem.addOutMapList(outputMap);

		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][makeOutPutMap]");
	}

}
