/*********************************************************************
*  All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名			：eo顧客基幹システム
*	モジュール名		：JBSbatACKaikSchemaCalcAdd
*	ソースファイル名	：JBSbatACKaikSchemaCalcAdd.java
*	作成者				：富士通　
*	作成日				：2012年05月19日
*＜機能概要＞
*　会計ＤＢ計算式分登録部品です。
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v3.00		2012/05/22   山下		新規作成
*	v4.00		2012/03/06   広野		新規作成
*	v4.01		2013/04/05   FJ)小柴	【IKK-2013-0000783】文字化け対策のため、エンコード形式の変更
*********************************************************************/
package eo.business.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import eo.business.common.JACBatCommon;
import eo.business.common.JACbatDebugLogUtil;
import eo.business.common.JBSbatBusinessService;
import eo.business.common.JCCBatCommon;
import eo.business.util.file.JBSbatACIFM147;
import eo.business.util.table.JBSbatCH_M_KAIK_ZDHYO_SHUK;
import eo.business.util.table.JBSbatCH_M_PRC_SCHDL_TEIGI;
import eo.common.constant.JACStrConst;
import eo.common.constant.JPCBatchMessageConstant;
import eo.framework.application.JBSbatBusinessException;
import eo.framework.db.JBSbatSQLAccess;
import eo.framework.file.JBSbatDefFileUtil;
import eo.framework.file.JBSbatOutputFileUtil;
import eo.framework.item.JBSbatCommonDBInterface;
import eo.framework.item.JBSbatCommonItem;
import eo.framework.item.JBSbatOutputItem;
import eo.framework.item.JBSbatServiceInterfaceMap;
import eo.framework.util.JBSbatAplConst;
import eo.framework.util.JBSbatBusinessFileUtil;

/**
* (クラスの機能概要) <p>
*<BR>
* @author 富士通
*/
public class JBSbatACKaikSchemaCalcAdd extends JBSbatBusinessService
{
	/**▼▼▼▼▼▼ツールから生成した宣言です 開始▼▼▼▼▼▼*/
	private static final String D_TBL_NAME_CH_M_PRC_SCHDL_TEIGI = "CH_M_PRC_SCHDL_TEIGI";

	/** テーブル(会計残高表集計)*/
	private static final String D_TBL_NAME_CH_M_KAIK_ZDHYO_SHUK = "CH_M_KAIK_ZDHYO_SHUK";

	/** テーブル(会計)*/
	private static final String D_TBL_NAME_CH_T_KAIK = "CH_T_KAIK";

	/** SQL定義キー(AC_SELECT_008)*/
	private static final String CH_M_PRC_SCHDL_TEIGI_AC_SELECT_008 = "AC_SELECT_008";

	/** SQL定義キー(AC_SELECT_003)*/
	private static final String CH_M_KAIK_ZDHYO_SHUK_AC_SELECT_003 = "AC_SELECT_003";

	/** テーブルアクセスクラス(料金スケジュール定義)*/
	private JBSbatSQLAccess db_CH_M_PRC_SCHDL_TEIGI = null;

	/** テーブルアクセスクラス(会計残高表集計)*/
	private JBSbatSQLAccess db_CH_M_KAIK_ZDHYO_SHUK = null;

	/** テーブルアクセスクラス(会計)*/
	private JBSbatSQLAccess db_CH_T_KAIK = null;
	/**▲▲▲▲▲▲ツールから生成した宣言です 終了▲▲▲▲▲▲*/
	
	/** 会計計上月:（会計処理日） */
	private String kaikYm = null;
	
	/** 当月分対象データリスト */
	private List<String[]> togtuZdhyoShukList = null;
	
	/** 算術演算子:（加算） */
	private static final String PLUS = "+";
	
	/** 算術演算子:（減算） */
	private static final String MINUS = "-";

	/** 会計情報出力ファイル */
	private JBSbatBusinessFileUtil acifm147 = null;

	/** 出力件数カウント用 */
	private int outputCounter147 = 0;
	private Map<String,String> meisai=new HashMap<String,String>() ;
	private String preSeikyKeiNo  = null;
	private String preSeikyNo  = null;

	/**
	 * 初期処理
	 * @param JBSbatCommonItem commonItem　バッチ共通パラメータ電文
	 * @throws Exception
	 */
	public void initial(JBSbatCommonItem commonItem) throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの初期処理を記述してください。▼▼▼▼▼▼*/
		/**▼▼▼▼▼▼ツールから生成した初期化のソースです 開始▼▼▼▼▼▼*/
		// 共通パラメータを設定します
		super.setCommonInfo(commonItem);
		// ファイル名を取得
		String[] freeFiles = commonItem.getFreeItem().split(JACStrConst.FREE_DIV);
		this.acifm147 = createFile(freeFiles[1], freeFiles[0]); 
		// commonItem.getOutPutFile().print(map, util) ;

		// DBアクセスクラスを生成します
		db_CH_M_PRC_SCHDL_TEIGI = new JBSbatSQLAccess(commonItem, D_TBL_NAME_CH_M_PRC_SCHDL_TEIGI);
		db_CH_M_KAIK_ZDHYO_SHUK = new JBSbatSQLAccess(commonItem, D_TBL_NAME_CH_M_KAIK_ZDHYO_SHUK);
		db_CH_T_KAIK = new JBSbatSQLAccess(commonItem, D_TBL_NAME_CH_T_KAIK);
		/**▲▲▲▲▲▲ツールから生成した初期化のソースです 終了▲▲▲▲▲▲*/
		
		assert 	JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][initial]");
		assert 	JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][initial][opeDate=" + super.opeDate + "]");
		assert 	JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][initial][freeItem=" + super.freeItem + "]");
		
		// 会計計上月を取得
		this.kaikYm = this.getSeikyYM();
		
		// 当月分対象データリストの作成
		this.togtuZdhyoShukList = new ArrayList<String[]>();
		this.getTogtuZdhyoShukList();
		
		assert 	JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][initial]");
	/**▲▲▲▲▲▲業務サービスの初期処理を記述してください。▲▲▲▲▲▲*/
	}

	/**
	 * 主処理
	 * @param inMap　入力電文
	 * @return JBSbatOutputItem　出力情報
	 * @throws Exception
	 */
	public JBSbatOutputItem execute(JBSbatServiceInterfaceMap inMap, JBSbatOutputItem outputInItem) throws Exception
	{
		/**▼▼▼▼▼▼業務サービスの主処理を記述してください。▼▼▼▼▼▼*/
		assert 	JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][execute]");
		assert 	inMap != null ? JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][execute][inMap=" + inMap.getMap().toString() + "]") : true;
		
		if(null==inMap)
		{
			// 請求番号単位で残高集計表明細の金額コレクションを合算出力する
			output_sum(this.preSeikyKeiNo, this.preSeikyNo);
			return outputInItem;
		}

		// 退避情報なしの場合
		if(!outputInItem.isOutMapList())
		{
			// ダミーを設定
			outputInItem.addOutMapList(new JBSbatServiceInterfaceMap());
		}

		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][execute][当月分開始]");

		if(null != this.preSeikyKeiNo || null != this.preSeikyNo)
		{
			// 請求契約番号ならびに請求番号がともに異なるレコードであった場合、請求先である契約者がリス世読み込み処理中でブレイクしたらフラグを立てる。this.isBreak = true
			if( !this.preSeikyKeiNo.equals(inMap.getString(JBSbatACIFM147.SEIKY_KEI_NO)) 
			 && !this.preSeikyNo.equals(inMap.getString(JBSbatACIFM147.SEIKY_NO)))
			{
				{
					// 請求番号単位で残高集計表明細の金額コレクションを合算出力する
					output_sum(this.preSeikyKeiNo, this.preSeikyNo);
					this.meisai.clear() ;
				}
			}
		}
		
		// 残高集計CDが NULLの場合、集計対象とはしない
		if(!"".equals(inMap.getString(JBSbatACIFM147.ZDK_SHUK_CD)))
		{
			this.meisai.put(
				inMap.getString(JBSbatACIFM147.ZDK_SHUK_CD).trim(), 
				inMap.getString(JBSbatACIFM147.AMNT)
			) ;
		}

		this.preSeikyKeiNo = inMap.getString(JBSbatACIFM147.SEIKY_KEI_NO);
		this.preSeikyNo = inMap.getString(JBSbatACIFM147.SEIKY_NO);

		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][execute][当月分終了]");		
		assert 	JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][execute]");

		// 空レコードを返却
		return outputInItem;

		/**▲▲▲▲▲▲業務サービスの主処理を記述してください。▲▲▲▲▲▲*/
	}

	/**
	 * 業務サービス終了処理
	 * @throws Exception
	 */
	public void terminal() throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの終了処理を記述してください。▼▼▼▼▼▼*/
		assert 	JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][terminal]");
		// 会計DB削除
		/**▼▼▼▼▼▼ツールから生成した終了処理のソースです 開始▼▼▼▼▼▼*/
		// 出力件数をログに出力
		super.logPrint.printBusinessErrorLog(JPCBatchMessageConstant.EACB0860AI, new String[]{"acifm147104", String.valueOf(outputCounter147)});
		// ファイルのクローズ
		JCCBatCommon.closeBusinessFileUtil(this.acifm147);
		// DBアクセスクラスをクローズします
		db_CH_M_KAIK_ZDHYO_SHUK.close();
		db_CH_T_KAIK.close();
		/**▲▲▲▲▲▲ツールから生成した終了処理のソースです 終了▲▲▲▲▲▲*/
		assert 	JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][terminal]");
	/**▲▲▲▲▲▲業務サービスの終了処理を記述してください。▲▲▲▲▲▲*/
	}

	/**▼▼▼▼▼▼ツールから生成したメソッドです 開始▼▼▼▼▼▼*/

	/**
	 * SQLKEY(AC_SELECT_003)でDBアクセスを行います。<br>
	 * <p>
	 * <b>処理フロー</b><br>
	 * <pre>
	 * 1.引数でバイント変数を設定します。<br>
	 *
	 * 2.DBアクセスを実行します。<br>
	 * 
	 * 3.メソッドの呼び出し方です。<br>
	 *		引数:
	 *		param:順にバイント変数の値をparam配列に入れます。バイント変数は以下に説明します。
	 *		 	会計残高表集計適用開始年月日
	 *		 	会計残高表集計適用終了年月日
	 *		 	予約適用年月日
	 * </pre>
	 * <p>
	 * @param param バイント変数の値配列。
	 * @throws Exception 業務サービス内で発生した例外全般。
	 */
	private void executeCH_M_KAIK_ZDHYO_SHUK_AC_SELECT_003(Object[] param) throws Exception
	{
		// バイント変数のリストを生成します
		JBSbatCommonDBInterface paramList = new JBSbatCommonDBInterface();
		paramList.setValue(param[0].toString());
		paramList.setValue(param[1].toString());
		paramList.setValue(param[2].toString());

		// DBアクセスを実行します
		db_CH_M_KAIK_ZDHYO_SHUK.selectBySqlDefine(paramList, CH_M_KAIK_ZDHYO_SHUK_AC_SELECT_003);
	}

	/**▲▲▲▲▲▲ツールから生成したメソッドです 終了▲▲▲▲▲▲*/

	/**
	 * 当月分対象データリストを取得します。
	 * 
	 * @throws Exception 　業務サービス内で発生した例外全般
	 */
	private void getTogtuZdhyoShukList() throws Exception
	{
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][getTogtuZdhyoShukList]");
		
		JBSbatCommonDBInterface paramList = new JBSbatCommonDBInterface();
		
		paramList.setValue(super.opeDate);			// 会計残高表集計適用開始年月日
		paramList.setValue(super.opeDate);			// 会計残高表集計適用終了年月日
		paramList.setValue(super.opeDate);			// 予約適用年月日
		
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][getTogtuZdhyoShukList][paramList=" + paramList.getList().toString() + "]");

		// SQL実行
		executeCH_M_KAIK_ZDHYO_SHUK_AC_SELECT_003(paramList.getList().toArray());
		
		// 結果取得
		JBSbatCommonDBInterface dbMap = db_CH_M_KAIK_ZDHYO_SHUK.selectNext();
		
		// 当月分対象データリストの作成
		while (dbMap != null)
		{
			// 当月分対象データをリストに格納
			this.togtuZdhyoShukList.add(new String[]{dbMap.getString(JBSbatCH_M_KAIK_ZDHYO_SHUK.ZDK_SHUK_CD).trim(), dbMap.getString(JBSbatCH_M_KAIK_ZDHYO_SHUK.SNST_SHIKI)});
			assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][getTogtuZdhyoShukList][dbMap=" + dbMap.getMap().toString() + "]");
			
			dbMap = db_CH_M_KAIK_ZDHYO_SHUK.selectNext();
		}
		
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][getTogtuZdhyoShukList]");
	}

	/**
	 * 当月分対象データと算術演算式から、金額を算出する。
	 * 
	 * @param inMap 		入力電文
	 * @param snstShiki 	算出式
	 * @return 
	 * @throws Exception 　業務サービス内で発生した例外全般
	 */
	private void output_sum(String seikyKeiNo, String seikyNo) throws Exception
	{
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][doSnstTogtuAmnt]");
		BigDecimal ans ;
		String amnt=null;
		String ope=null;
		// 算出式を取り出す
		for (String[] snstShiki : this.togtuZdhyoShukList){
			// 演算結果格納用
			ans = null;
			// 算出式を「取得元残高集計コード」と、演算子に分解
			String []snstShikiList = snstShiki[1].split(" ", -1);
			for(String snstShikiObj : snstShikiList)
			{
				// 演算子設定用
				assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][doSnstTogtuAmnt][snstShiki=" + snstShikiObj + "]");

				amnt = ((null==this.meisai.get(snstShikiObj)||"".equals(this.meisai.get(snstShikiObj)))?"0":this.meisai.get(snstShikiObj)) ;

				if(ans == null)
				{
					// 初回の場合
					ans = new BigDecimal(amnt);
					continue;
				}
				
				// 分解した算出式を計算用に変数へ設定し、計算する
				if(snstShikiObj.equals(PLUS))
				{
					// 算出式が「演算子：＋」の場合
					ope = PLUS;
				}
				else if(snstShikiObj.equals(MINUS))
				{
					// 算出式が「演算子：−」の場合
					ope = MINUS;
				}
				else
				{
					// 算出式が取得元残高集計コードの場合
					if(ope.equals(PLUS))
					{
						// 金額を取得して加算
						ans = ans.add(new BigDecimal(amnt));
					}
					else
					{
						// 金額を取得して減算
						ans = ans.subtract(new BigDecimal(amnt));
					}
				}
			}
			String answer=(null==ans)?"0":ans.toString() ;
			// 集計結果を明細に格納する
			this.meisai.put(snstShiki[0],answer) ;
			// ファイルに出力（集計結果が 0円だったらファイルに出力せず、会計スキーマの登録対象外になる）
			if(!"0".equals(answer)){
				JCCBatCommon.printBusinessFileUtil(
						this.acifm147, 
						this.kaikYm+","+
						// 請求契約番号
						seikyKeiNo+","+
						// 請求番号
						seikyNo+","+
						// 残高集計コード
						snstShiki[0]+","+
						// 料金月
						this.kaikYm+","+
						// 件数
						""+","+
						// 金額
						answer+","+
						// 会計処理年月日
						super.opeDate
					); // 第二引数でカンマ編集された文字列をセットする
				++this.outputCounter147; //出力件数をログに出力するため、カウントする
			}
			assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][doSnstTogtuAmnt][Ans=" + ans.toString() + "]");
		}
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][doSnstTogtuAmnt]");
	}

	/**
	 * ファイルオブジェクトを生成します。
	 * 
	 * @param filePath
	 *          ファイルパス
	 * @param fileDef
	 *          出力対象のDEFファイル名
	 * @return JBSbatBusinessFileUtil ファイル出力制御オブジェクト
	 * @throws Exception
	 *           業務サービス内で発生した例外全般
	 */
	private JBSbatBusinessFileUtil createFile(String filePath, String fileDef) throws Exception {
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][createFile]");
		JBSbatBusinessFileUtil fileUtil = 
			JCCBatCommon.createBusinessFileUtil(
				filePath, 
				JACStrConst.ENCODE_MS932, 
				JACBatCommon.chgKaigyo(JACStrConst.LINE_CRLF), 
				new JBSbatDefFileUtil(JBSbatAplConst.getAplConstValue("OTD") + fileDef, 
				new JBSbatOutputFileUtil(filePath)).getDelimiter()
			);
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][createFile]");
		return fileUtil;
	}

	/**
	 * SQLKEY(AC_SELECT_008)でDBアクセスを行います。<br>
	 * <p>
	 * <b>処理フロー</b><br>
	 * <pre>
	 * 1.引数でバイント変数を設定します。<br>
	 *
	 * 2.DBアクセスを実行します。<br>
	 * 
	 * 3.メソッドの呼び出し方です。<br>
	 *		引数:
	 *		param:順にバイント変数の値をparam配列に入れます。バイント変数は以下に説明します。
	 *		 	バッチ運用日
	 *		 	イベントコード
	 * </pre>
	 * <p>
	 * @param param バイント変数の値配列。
	 * @throws Exception 業務サービス内で発生した例外全般。
	 */
	private void executeCH_M_PRC_SCHDL_TEIGI_AC_SELECT_008(Object[] param) throws Exception
	{
		// バイント変数のリストを生成します
		JBSbatCommonDBInterface paramList = new JBSbatCommonDBInterface();
		paramList.setValue(param[0].toString());
		paramList.setValue(param[1].toString());

		// DBアクセスを実行します
		db_CH_M_PRC_SCHDL_TEIGI.selectBySqlDefine(paramList, CH_M_PRC_SCHDL_TEIGI_AC_SELECT_008);
	}

	/**
	 * 請求年月を取得します。
	 * 
	 * @throws Exception 　業務サービス内で発生した例外全般
	 */
	private String getSeikyYM() throws Exception
	{
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[S][getSeikyYM]");
		JBSbatCommonDBInterface paramList = new JBSbatCommonDBInterface();
		
		paramList.setValue(JACStrConst.EVENT_CD_KAIK_SHORI_YMD);			// イベントコード
		paramList.setValue(super.opeDate);			// バッチ運用日
		
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[L][getSeikyYM][paramList=" + paramList.getList().toString() + "]");
		executeCH_M_PRC_SCHDL_TEIGI_AC_SELECT_008(paramList.getList().toArray());

		JBSbatCommonDBInterface commonDBInterface = db_CH_M_PRC_SCHDL_TEIGI.selectNext();
		String seikyYm = commonDBInterface.getString(JBSbatCH_M_PRC_SCHDL_TEIGI.SEIKY_YM);
		// レコードの存在チェック
		if (null == seikyYm )
		{
			// 業務例外
			throw new JBSbatBusinessException(JPCBatchMessageConstant.EACB0440CE, new String[] { JBSbatCH_M_PRC_SCHDL_TEIGI.TABLE_NAME });
		}
		assert JACbatDebugLogUtil.printDebugLog(super.logPrint, "[E][getSeikyYM]");

		return seikyYm;
	}
}
