/*********************************************************************
*  All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名			：eo顧客基幹システム
*	モジュール名		：JBSbatACEmHjnTsnInfShuk
*	ソースファイル名	：JBSbatACEmHjnTsnInfShuk.java
*	作成者				：富士通　
*	作成日				：2011年12月14日
*＜機能概要＞
*　ＥＭ法人通信情報集計部品です。
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v1.00.00	2011/12/14   富士通		新規作成
*	v3.00		2012/09/04   FJ）岡田	【ST1-2012-0000397】処理を全面見直し
*	v4.00.00	2012/11/28   FJ)早崎	【ANK-0141-00-00】対応
*	v5.00.00	2013/07/09   FJ)大戸	【TG1-2013-0000662】マスタ参照基準日対応
*********************************************************************/
package eo.business.service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import eo.business.common.JACbatDebugLogUtil;
import eo.business.common.JACbatSchdlUtil;
import eo.business.common.JBSbatBusinessService;
import eo.business.util.file.JBSbatACIFM169;
import eo.business.util.table.JBSbatAC_M_JURYOPRC;
import eo.common.constant.JACStrConst;
import eo.common.constant.JPCBatchMessageConstant;
import eo.framework.item.JBSbatCommonItem;
import eo.framework.item.JBSbatServiceInterfaceMap;
import eo.framework.item.JBSbatOutputItem;
import eo.framework.item.JBSbatCommonDBInterface;
import eo.framework.application.JBSbatBusinessException;
import eo.framework.db.JBSbatSQLAccess;

/**
* (クラスの機能概要) <p>
*<BR>
* @author 富士通
*/
public class JBSbatACEmHjnTsnInfShuk extends JBSbatBusinessService
{
	/**▼▼▼▼▼▼ツールから生成した宣言です 開始▼▼▼▼▼▼*/
	/** テーブル(従量料金)*/
	private static final String D_TBL_NAME_AC_M_JURYOPRC = "AC_M_JURYOPRC";

	/** SQL定義キー(AC_SELECT_002)*/
	private static final String AC_M_JURYOPRC_AC_SELECT_002 = "AC_SELECT_002";

	/** テーブルアクセスクラス(従量料金)*/
	private JBSbatSQLAccess db_AC_M_JURYOPRC = null;
	/**▲▲▲▲▲▲ツールから生成した宣言です 終了▲▲▲▲▲▲*/

//20130709 追加　FJ)OHTO　START
	/** 請求年月 */
	private String wk_SkyuYM 	= null;

	/** 請求年月初日 */
	private String wk_Str 	= null;

	/** 請求年月末日 */
	private String wk_End 	= null;
//20130709 追加　FJ)OHTO　END
	

	/** 締め日*/
	private static final String CONST_SIME_DAY = "99";
	
	/** 従量マスタ取得データ格納マップ*/
	private HashMap<ArrayList<String>, JBSbatCommonDBInterface> juryoPrcMap = null;
	
	/** １レコード前のキーの値を格納するリスト */
	private ArrayList<String> beforeKey = null;

	/**
	 * 初期処理
	 * @param JBSbatCommonItem commonItem　バッチ共通パラメータ電文
	 * @throws Exception
	 */
	public void initial(JBSbatCommonItem commonItem) throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの初期処理を記述してください。▼▼▼▼▼▼*/
		/**▼▼▼▼▼▼ツールから生成した初期化のソースです 開始▼▼▼▼▼▼*/
		// 共通パラメータを設定します
		super.setCommonInfo(commonItem);

		// DBアクセスクラスを生成します
		db_AC_M_JURYOPRC = new JBSbatSQLAccess(commonItem, D_TBL_NAME_AC_M_JURYOPRC);
		/**▲▲▲▲▲▲ツールから生成した初期化のソースです 終了▲▲▲▲▲▲*/
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][initial]");
//20130709 追加　FJ)OHTO　START
		// 請求年月取得
		JACbatSchdlUtil schdUtil = new JACbatSchdlUtil(commonItem);
		try
		{
			// 料金スケジュール定義アクセス部品を使用する。
			this.wk_SkyuYM = schdUtil.getBillDate(super.opeDate, JACStrConst.EVENT_CD_RYOKIN_KEISAN_YMD);
			
			// 月初日、締め日　←　JACbatSchdlUtil.getUseStrEnd(請求年月, イベントコード("01"（利用開始日））, イベントコード（"02"（利用終了日））)
			String[] rtn = schdUtil.getUseStrEnd(this.wk_SkyuYM, JACStrConst.EVENT_CD_USE_STAYMD, JACStrConst.EVENT_CD_USE_ENDYMD);
			this.wk_Str = rtn[0];
			this.wk_End = rtn[1];
		}
		finally
		{
			// クローズ
			schdUtil.close();
		}
//20130709 追加　FJ)OHTO　END
		
		// 従量マスタを参照し取得データをメモリに格納します
		juryoPrcMap = selectJuryoPrc();
		
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][initial]");
	/**▲▲▲▲▲▲業務サービスの初期処理を記述してください。▲▲▲▲▲▲*/
	}

	/**
	 * 主処理
	 * @param inMap　入力電文
	 * @param outputInItem 入力情報
	 * @return JBSbatOutputItem　出力情報
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public JBSbatOutputItem execute(JBSbatServiceInterfaceMap inMap, JBSbatOutputItem outputInItem) throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの主処理を記述してください。▼▼▼▼▼▼*/
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][execute]");
		
		// ブレイク用のキーリスト
		ArrayList<String> crrentKey = null;
		
		// 最終レコード判定
		if (inMap == null)
		{
			// ダミーレコードを消去
			outputInItem.clearOutMapList();
			
			// 格納領域より退避したレコードを全件取得
			ArrayList tempMapList =  outputInItem.getTmpList();
			if(tempMapList == null)
			{
				// レコードの格納がない
				return outputInItem;
			}
			
			// キーブレイク時のパケット計算等を行う
			JBSbatServiceInterfaceMap editOutPutInfo = breakLogic(tempMapList);
			// 出力情報を生成
			outputInItem.addOutMapList(editOutPutInfo);
			// 格納領域をクリアー
			outputInItem.clearTmpList();
			
			// 主処理を終了する
			assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][execute] 最終レコード");
			// 次のレコードの処理へ
			return outputInItem;
		}
		else
		{
			// ブレイク用のキーリストを生成する
			crrentKey = createBreakKey(inMap);
		}
		
		// １件目レコード判定（前回格納キーがNULLである場合）
		if (beforeKey == null)
		{
			// ブレイク用のキーを生成する
			beforeKey = new ArrayList(2);
			beforeKey.addAll(crrentKey);
			
			// ダミーレコードを設定しておく
			outputInItem.addOutMapList(new JBSbatServiceInterfaceMap());
			
			// 入力情報を一時格納領域に退避
			outputInItem.addTmpList(inMap);
			assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][execute] レコード1件目");
			// 次のレコードの処理へ
			return outputInItem;
			
		}
		
		// ２件目以降 キーが等しい場合
		if (beforeKey.equals(crrentKey))
		{
			// 入力情報を一時格納領域に退避
			outputInItem.addTmpList(inMap);
			assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][execute] 集計中・・・");
			// 次のレコードの処理へ
			return outputInItem;
		}
		else
		{
			// 格納領域より退避したレコードを全件取得
			ArrayList tempMapList =  outputInItem.getTmpList();
			// 取得した入力電文リストよりパケット計算および出力情報の生成を行う
			JBSbatServiceInterfaceMap editOutPutInfo = breakLogic(tempMapList);
			// 出力電文へレコードを設定する
			outputInItem.addOutMapList(editOutPutInfo);
			
			// 格納領域をクリアー
			outputInItem.clearTmpList();
			// 入力情報を一時格納領域に退避
			outputInItem.addTmpList(inMap);
			// キー格納領域をクリアー
			beforeKey.clear();
			// キー格納領域に現在のキーを設定
			beforeKey.addAll(crrentKey);
			
			// 主処理を終了する
			assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][execute] 集計完");
			// 次のレコードの処理へ
			return outputInItem;
		}
		
	/**▲▲▲▲▲▲業務サービスの主処理を記述してください。▲▲▲▲▲▲*/
	}

	/**
	 * 業務サービス終了処理
	 * @throws Exception
	 */
	public void terminal() throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの終了処理を記述してください。▼▼▼▼▼▼*/
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][terminal]");
		/**▼▼▼▼▼▼ツールから生成した終了処理のソースです 開始▼▼▼▼▼▼*/
		// DBアクセスクラスをクローズします
		db_AC_M_JURYOPRC.close();
		/**▲▲▲▲▲▲ツールから生成した終了処理のソースです 終了▲▲▲▲▲▲*/
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][terminal]");
	/**▲▲▲▲▲▲業務サービスの終了処理を記述してください。▲▲▲▲▲▲*/
	}

	/**▼▼▼▼▼▼ツールから生成したメソッドです 開始▼▼▼▼▼▼*/
	/**
	 * SQLKEY(AC_SELECT_002)でDBアクセスを行います。<br>
	 * <p>
	 * <b>処理フロー</b><br>
	 * <pre>
	 * 1.引数でバイント変数を設定します。<br>
	 *
	 * 2.DBアクセスを実行します。<br>
	 * 
	 * 3.メソッドの呼び出し方です。<br>
	 *		引数:
	 *		param:順にバイント変数の値をparam配列に入れます。バイント変数は以下に説明します。
	 *		 	システムコード
	 *		 	課税非課税コード
	 *		 	相対区分
	 *		 	従量料金適用開始年月日
	 *		 	従量料金適用終了年月日
	 * </pre>
	 * <p>
	 * @param param バイント変数の値配列。
	 * @throws Exception 業務サービス内で発生した例外全般。
	 */
	private void executeAC_M_JURYOPRC_AC_SELECT_002(Object[] param) throws Exception
	{
		// バイント変数のリストを生成します
		JBSbatCommonDBInterface paramList = new JBSbatCommonDBInterface();
		paramList.setValue(param[0].toString());
		paramList.setValue(param[1].toString());
		paramList.setValue(param[2].toString());
		paramList.setValue(param[3].toString());
		paramList.setValue(param[4].toString());

		// DBアクセスを実行します
		db_AC_M_JURYOPRC.selectBySqlDefine(paramList, AC_M_JURYOPRC_AC_SELECT_002);
	}
	/**▲▲▲▲▲▲ツールから生成したメソッドです 終了▲▲▲▲▲▲*/

	/**
	 * キーブレイク時のパケット計算およびファイル編集のロジックを提供します。
	 * 
	 * @param tempMapList 退避領域より取得した入力電文のリスト（NULL不許可）
	 * @return 出力情報
	 * @throws Exception
	 */
	private JBSbatServiceInterfaceMap breakLogic(ArrayList tempMapList) throws Exception
	{
		// キーブレイク時の料金集計処理開始
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][breakLogic]");
		// 料金（バイト数）を集計する
		BigDecimal sumByte = calcPrc(tempMapList);
		// 先頭の入力レコードを１件取得する
		JBSbatServiceInterfaceMap getInMap = (JBSbatServiceInterfaceMap)tempMapList.get(0);
		// 従量マスタ検索用のキーを生成する
		ArrayList<String> mapKeyList = createMapKey(getInMap);
		// 従量マスタより該当レコードを取得する
		JBSbatCommonDBInterface dbMap = juryoPrcMap.get(mapKeyList);
		if (dbMap == null)
		{
			// 従量のマスタに料金コースコード、料金サービスコードに対応するレコード未存在
			String[] msgParam = new String[]{JBSbatAC_M_JURYOPRC.TABLE_NAME, mapKeyList.toString()};
			assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][従量マスタのＤＢ未存在エラー]");
			// ログ出力（【最重要】ＤＢ未存在エラー）強制的に処理を終了する
			throw new JBSbatBusinessException(JPCBatchMessageConstant.EACB0250CE, msgParam);
		}
		// 料金（バイト数）よりパケット数を算出する
		BigDecimal calcPacet = calcPacet(sumByte, dbMap);
		// キーブレイク時の料金集計処理終了
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][breakLogic]");
		// 出力情報を生成
		return editEmHojinPrcInfo(getInMap, calcPacet, dbMap);
	}
	
	
	/**
	 * 従量のマスタより対象レコードを取得し、料金コースコード、料金サービスコード
	 * ごとのマップを生成します。
	 * 
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private HashMap<ArrayList<String>, JBSbatCommonDBInterface> selectJuryoPrc() throws Exception
	{
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][selectJuryoPrc]");
		
		// 取得結果格納用マップを初期化
		HashMap<ArrayList<String>, JBSbatCommonDBInterface> pctCntMap = null;
		pctCntMap = new HashMap<ArrayList<String>, JBSbatCommonDBInterface>(101);
		
		// 従量マスタ検索用パラメータ生成
		JBSbatCommonDBInterface paramList = new JBSbatCommonDBInterface();
		paramList.setValue(JACStrConst.SYS_CD_AC);					// システムコード
		paramList.setValue(JACStrConst.KAZEI_HIKAZEI_CD_KAZEI);		// 課税非課税コード（課税）
		paramList.setValue(JACStrConst.AITAI_NO_SP);				// 相対番号

//20130709 追加　FJ)OHTO　START
		paramList.setValue(this.wk_End);							// 請求年月末日
		paramList.setValue(this.wk_End);							// 請求年月末日

//		paramList.setValue(super.opeDate);							// バッチ運用日
//		paramList.setValue(super.opeDate);							// バッチ運用日
//20130709 追加　FJ)OHTO　ENDT
		

		// 検索実行パラメータ
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][selectJuryoPrc][paramList=" + paramList.getList().toString() + "]");		
		
		// SQL実行
		executeAC_M_JURYOPRC_AC_SELECT_002(paramList.getList().toArray());
		JBSbatCommonDBInterface dbMap =  db_AC_M_JURYOPRC.selectNext();

		while(dbMap != null)
		{
			// マップ格納キーを設定する
			ArrayList<String> juryoPrcKey = createDbMapKey(dbMap);
			// キー項目ごとにスキーマ取得情報を格納する
			pctCntMap.put(juryoPrcKey, dbMap);
			// 次のレコードを読み込む
			dbMap =  db_AC_M_JURYOPRC.selectNext();
		}
		
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][selectJuryoPrc] 従量マスタマップ格納件数：" + pctCntMap.size());
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][selectJuryoPrc]");
		
		// マスタマップの返却
		return pctCntMap;
	}
	
	
	/**
	 * 従量のマスタ取得レコードより、マップ検索用のキーリストを生成します。
	 * 
	 * @param dbMap 従量のマスタ取得結果
	 * @return マップ検索用のキーリスト
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private ArrayList<String> createDbMapKey(JBSbatCommonDBInterface dbMap) throws Exception
	{
		ArrayList<String> keyList = new ArrayList<String>(2);
		keyList.add(dbMap.getString(JBSbatAC_M_JURYOPRC.PCRS_CD)); 		// 料金コースコード
		keyList.add(dbMap.getString(JBSbatAC_M_JURYOPRC.PRC_SVC_CD)); 	// 料金サービスコード
		return keyList;
	}
	
	/**
	 * 入力電文より従量のマスタマップからデータを取得するためのキーを生成します。
	 * 
	 * @param inMap 入力電文
	 * @return マップ検索用のキーリスト
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private ArrayList<String> createMapKey(JBSbatServiceInterfaceMap inMap) throws Exception
	{
		ArrayList<String> keyList = new ArrayList<String>(2);
		keyList.add(inMap.getString(JBSbatACIFM169.PCRS_CD)); 		// 料金コースコード
		keyList.add(inMap.getString(JBSbatACIFM169.PRC_SVC_CD)); 	// 料金サービスコード
		return keyList;
	}
	
	/**
	 * キーブレイク用のキーリストを生成します。
	 * 
	 * @param dbMap 従量のマスタ取得結果
	 * @return マップ検索用のキーリスト
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private ArrayList<String> createBreakKey(JBSbatServiceInterfaceMap inMap) throws Exception
	{
		ArrayList<String> keyList = new ArrayList<String>(4);
		keyList.add(inMap.getString(JBSbatACIFM169.SVC_NO)); 		// サービス番号（サービス契約番号が格納されている）
		keyList.add(inMap.getString(JBSbatACIFM169.SEIKY_YM)); 		// 請求年月
		keyList.add(inMap.getString(JBSbatACIFM169.PCRS_CD)); 		// 料金コースコード
		keyList.add(inMap.getString(JBSbatACIFM169.PRC_SVC_CD)); 	// 料金サービスコード
		return keyList;
	}
	
	/**
	 * 入力電文を格納したリストよりパケット数を計算します。
	 * ※ NULLを引数に渡すことはできません
	 * 
	 * @param inMpaList 入力電文格納リスト
	 * @return 料金（計算後）
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	@SuppressWarnings("unchecked")
	private BigDecimal calcPrc(ArrayList inMpaList) throws Exception
	{
		// 集計後の料金
		BigDecimal sumBigPrc = new BigDecimal(0);
		
		Iterator itr = inMpaList.iterator();
		while(itr.hasNext())
		{
			// 入力電文を取得
			JBSbatServiceInterfaceMap inMap = (JBSbatServiceInterfaceMap)itr.next();
			// 料金（バイト数）を取得
			BigDecimal bigPrc = inMap.getBigDecimal(JBSbatACIFM169.PRC);
			// 料金を加算
			sumBigPrc = sumBigPrc.add(bigPrc);
		}
		
		return sumBigPrc;
	}
	
	/**
	 * パケット料金計算
	 * 集計後利用バイト数および従量のデータ（単位料金,課金単位）より
	 * パケット料金の計算を行います。
	 * 
	 * @param useByteCnt 料金（バイト数）
	 * @param dbMap 従量マスタ取得データ
	 * @return パケット料金
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private BigDecimal calcPacet(BigDecimal useByteCnt, JBSbatCommonDBInterface dbMap) throws Exception
	{
		// 従量のデータよりパケット計算用の項目を取得します
		BigDecimal taniPrc 	= dbMap.getBigDecimal(JBSbatAC_M_JURYOPRC.TANI_PRC);	// 単位料金
		BigDecimal chrgTani = dbMap.getBigDecimal(JBSbatAC_M_JURYOPRC.CHRG_TANI);	// 課金単位
		// 利用バイト数 ÷ 課金単位 × 課金料金(小数点以下切り上げ)
		return useByteCnt.divide(chrgTani.multiply(taniPrc), 0, RoundingMode.UP);
	}
	

	/**
	 * EM法人利用料金情報を作成します。
	 * 
	 * @param inMap 入力情報
	 * @param sumPrc 集計後パケット数
	 * @param dbMap 従量スキーマ取得データ
	 * @return 出力電文
	 * @throws Exception 業務サービス内で発生した例外全般
	 */
	private JBSbatServiceInterfaceMap editEmHojinPrcInfo(JBSbatServiceInterfaceMap inMap, BigDecimal sumPrc, JBSbatCommonDBInterface dbMap) throws Exception
	{
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][editEmHojinPrcInfo]");
		
		// EM法人利用料金情報マップ
		JBSbatServiceInterfaceMap outMap 		= new JBSbatServiceInterfaceMap();
		
		//  1.請求先番号
		outMap.set(JBSbatACIFM169.SEIKY_KEI_NO, 		inMap.getString(JBSbatACIFM169.SEIKY_KEI_NO));
		//  2.請求年月
		outMap.set(JBSbatACIFM169.SEIKY_YM, 			inMap.getString(JBSbatACIFM169.SEIKY_YM));
		//  6.サービス番号
		outMap.set(JBSbatACIFM169.SVC_NO, 				inMap.getString(JBSbatACIFM169.SVC_NO));
		// 10.料金コースコード
		outMap.set(JBSbatACIFM169.PCRS_CD, 				inMap.getString(JBSbatACIFM169.PCRS_CD));
		// 11.料金サービスコード
		outMap.set(JBSbatACIFM169.PRC_SVC_CD, 			inMap.getString(JBSbatACIFM169.PRC_SVC_CD));
		// 12.料金項目コード
		outMap.set(JBSbatACIFM169.PRC_KMK_CD, 			dbMap.getString(JBSbatAC_M_JURYOPRC.PRC_KMK_CD));
		// 14.宅内機器型式コード
		outMap.set(JBSbatACIFM169.TAKNKIKI_MODEL_CD, 	inMap.getString(JBSbatACIFM169.TAKNKIKI_MODEL_CD));
		// 15.料金
		outMap.set(JBSbatACIFM169.PRC, 					sumPrc);
		// 18.サービス開始日
		outMap.set(JBSbatACIFM169.SVC_STAYMD, 			inMap.getString(JBSbatACIFM169.SVC_STAYMD));
		// 19.初回課金開始日
		outMap.set(JBSbatACIFM169.FIRST_CHRG_STAYMD, 	inMap.getString(JBSbatACIFM169.FIRST_CHRG_STAYMD));
		// 20.サービス解約日
		outMap.set(JBSbatACIFM169.SVC_DSL_YMD, 			inMap.getString(JBSbatACIFM169.SVC_DSL_YMD));
		// 26.締め日
		outMap.set(JBSbatACIFM169.SIME_DAY, 			CONST_SIME_DAY);
		
		// 出力フラグ設定
		outMap.setOutFlg(true);
		
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][editEmHojinPrcInfo]");
		return outMap;
	}
}
