/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JCHPrcChoseiHenkoUtil
*   ソースファイル名：JCHPrcChoseiHenkoUtil.java
*   作成者          ：富士通
*   日付            ：2013年02月13日
*＜機能概要＞
*   料金調整、料金変更画面で使用する共通部品です。
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v1.00       2013/02/13   FJ          新規作成
*   v5.00.01	2013/07/30  FJ) 垣内   【LT-2013-0000595】前受け充当金対応
*   v5.00.02    2013/09/06  FJ) 林     【OM-2013-0001718/1769/1773】
*                                       会社別合計チェック変更・相殺額２重計上不備修正・調整前データ生成不備修正・債権内訳集計結果反映不備修正
*	v5.00.03    2013/09/12  FJ) 林     【OM-2013-0001890】前受け充当金対応 絶対値取得処理追加
*	v24.00.00   20160/03/02  FJ）宇野  【OM-2016-0000569】性能障害対応
*	v32.00.00   2017/05/26   FJ) 河邊  【OM-2017-0000488】オープンカーソルエラー
*
**********************************************************************/
package eo.ejb.common;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.fujitsu.futurity.model.base.CAANConnectionMgr;
import com.fujitsu.futurity.model.base.CAANJDBCUtil;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.base.CAANRuntimeException;
import com.fujitsu.futurity.model.ejb.common.JSYejbConnection;
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 eo.common.constant.JACStrConst;
import eo.common.util.JCRUtilCommon;
import eo.ejb.cbm.entity.CH0051ETMsg;
import eo.ejb.cbm.entity.CH0401ETMsg;
import eo.ejb.common.db.JCHejbCH0101SecProc;

/**
 * 料金調整、料金変更画面で使用する共通部品です。
 * @author FJ
 *
 */
public class JCHPrcChoseiHenkoUtil
{
	/**
	 * <p>
	 * フロアリミットチェック実行処理。
	 * </p>
	 * @param inMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @param cardNo クレジットカード番号
	 * @return 超過しない場合:"0"、超過する場合:"1"
	 */
	protected static String execFlrlmtChk(CAANMsg inCBSMsg, AgentDispatchContext inContext, String cardNo)
	{
		// コネクション
		Connection con1 = null;

		// プリペアステートメント
		PreparedStatement pstmt = null;

		// リザルトセット
		ResultSet rsltQuery = null;

		// パラメータ設定リスト
		List<Object> replaceListCnt = new ArrayList<Object>();

		/******************** 
		 * SQL文の作成
		 ********************/
		try
		{
			// 運用日付
			String opeDate = (String)JPCModelCommon.getOpeDate(inCBSMsg, inContext, null);

			// フロアリミット額を取得
			String strFlrLmtGk = JCHModelCommon.getWorkParam(JACStrConst.FLOOR_LIMIT_KINGAKU);

			//コネクション取得
			con1 = JSYejbConnection.getConnection(CH0051ETMsg.getTableName());

			// SQL文
			StringBuffer sql_Buff = getFlrlmtChkSql();

			replaceListCnt.add(inCBSMsg.getObject(JCHModelCommon.KEY_SEIKY_YM));
			replaceListCnt.add(JACStrConst.SEIKY_CREDIT);
			replaceListCnt.add(cardNo);
			replaceListCnt.add(inCBSMsg.getObject(JCHModelCommon.KEY_SEIKY_YM));
			replaceListCnt.add(JACStrConst.SYS_CD_CH);
			replaceListCnt.add(JCHModelCommon.getWorkParam(JACStrConst.WKPARA_CH_WKS_SEIKY_TANI_GK));
			replaceListCnt.add(JACStrConst.CHSHT_CHG_CD_1);
			replaceListCnt.add(opeDate);
			replaceListCnt.add(opeDate);

			//prepareStatementにSQL文をセット
			pstmt = con1.prepareStatement(sql_Buff.toString());

			//ログ出力(SQL文の出力)
			JSYejbLog.outlog(inContext, JSYejbLog.DBACCESS, JCHejbCH0101SecProc.class, sql_Buff);

			// PreparedStatementの指定されたパラメータカラムに 指定された値を設定
			for (int idx = 0; idx < replaceListCnt.size(); idx++ )
			{
				CAANJDBCUtil.setParam(pstmt, idx+1, replaceListCnt.get(idx));
			}

			// ResultSetの取得
			rsltQuery = pstmt.executeQuery();

			// 戻り値の判定
			String strAmnt = "";
			if (rsltQuery.next())
			{
				strAmnt = rsltQuery.getString("AMNT");
			}

			if (!JCRUtilCommon.isNull(strAmnt))
			{
				BigDecimal bdAmnt = new BigDecimal(strAmnt);

				if (!JCRUtilCommon.isNull(strFlrLmtGk))
				{
					BigDecimal bdFlrLmtGk = new BigDecimal(strFlrLmtGk);
					
					if (bdAmnt.compareTo(bdFlrLmtGk) > 0)
					{
						return JACStrConst.FLOOR_LIMIT_CHOKA_FLG_CHOKA;
					}
				}

			}

			return JACStrConst.FLOOR_LIMIT_CHOKA_FLG_IKA;
		}
		catch (SQLException e)
		{
			throw new CAANRuntimeException(e);
		}
		catch (Exception e)
		{
			throw new CAANRuntimeException(e);
		}
		finally
		{
			// 資源の解放
			try
			{
				if (null != rsltQuery) 
				{
					rsltQuery.close();
				}
				if (null != pstmt) 
				{
					pstmt.close();
				}
				if (null != con1) 
				{
					CAANConnectionMgr.getInstance().close(con1);
				}
			}
			catch(SQLException e)
			{
				inCBSMsg.set(CH0051ETMsg.STATUS, StatusCodes.FIND_DB_ERR);
				throw new CAANRuntimeException(e);
			}
		}
	}

	/**
	 * <p>
	 * 指定された請求年月、イベントコードに紐づく利用開始年月日、利用終了年月日を取得し、<br>
	 * String配列でリターンする。
	 * </p>
	 * @param inMsg 処理対象のメッセージキャリア
	 * @param funcCd "1":利用開始年月日のみ取得、"2":利用終了年月日のみ取得、"3":両方取得
	 * @param seikyYm 請求年月
	 * @return 配列の1番目の要素に利用開始年月日、2番目の要素に利用終了年月日を格納。
	 */
	protected static String[] getUseYmd(CAANMsg inMsg, String funcCd, String seikyYm){

		// コネクション
		Connection con1 = null;
		
		// プリペアステートメント
		PreparedStatement pstmt1 = null;
		PreparedStatement pstmt2 = null;

		// リザルトセット
		ResultSet rsltQuery = null;

		// 結果値を返す配列
		String[] ymdArray = new String[2];

		try{
			//コネクション取得
			con1 = JSYejbConnection.getConnection(CH0051ETMsg.getTableName());

			StringBuffer sql_Buff = null;

			// 機能コードが"1"または"3"の場合、利用開始年月日を取得する
			if ("1".equals(funcCd) || "3".equals(funcCd))
			{
				// SQL文_基本部1
				sql_Buff = getUseStaYmdSql();

				// prepareStatementにSQL文をセット
				pstmt1 = con1.prepareStatement(sql_Buff.toString());
	
				// PreparedStatementの指定されたパラメータカラムに 指定された値を設定
				int idx = 1;
				CAANJDBCUtil.setParam(pstmt1, idx++, seikyYm);
				CAANJDBCUtil.setParam(pstmt1, idx++, JACStrConst.EVENT_CD_USE_STA_DAY);
	
				// ResultSetの取得
				rsltQuery = pstmt1.executeQuery();
	
				// 結果が取得できた場合、日付をリターンする
				if (rsltQuery.next())
				{
					ymdArray[0] = rsltQuery.getString("USE_STAYMD");
				}
			}

			// 機能コードが"2"または"3"の場合、利用開始年月日を取得する
			if ("2".equals(funcCd) || "3".equals(funcCd))
			{
				// SQL文_基本部1
				sql_Buff = getUseEndYmdSql();

				// prepareStatementにSQL文をセット
				pstmt2 = con1.prepareStatement(sql_Buff.toString());
	
				// PreparedStatementの指定されたパラメータカラムに 指定された値を設定
				int idx = 1;
				CAANJDBCUtil.setParam(pstmt2, idx++, seikyYm);
				CAANJDBCUtil.setParam(pstmt2, idx++, JACStrConst.EVENT_CD_USE_END_DAY);
	
// OM-2017-0000488 2017/05/26 ADD START
				if(rsltQuery != null){
					rsltQuery.close();
				}
// OM-2017-0000488 2017/05/26 ADD END
				// ResultSetの取得
				rsltQuery = pstmt2.executeQuery();
	
				// 結果が取得できた場合、日付をリターンする
				if (rsltQuery.next())
				{
					ymdArray[1] = rsltQuery.getString("USE_ENDYMD");
				}
			}

			return ymdArray;

		} catch(SQLException e) {
			inMsg.set("status", StatusCodes.FIND_DB_ERR);
			throw new CAANRuntimeException(e);
		} finally {
			// 資源の解放
			try{
				if(rsltQuery != null){
					rsltQuery.close();
				}
				if(pstmt1 != null){
					pstmt1.close();
				}
				if(pstmt2 != null){
					pstmt2.close();
				}
				if(con1 != null){
					CAANConnectionMgr.getInstance().close(con1);
				}
			}catch(SQLException e){
				inMsg.set("status", StatusCodes.FIND_DB_ERR);
				throw new CAANRuntimeException(e);
			}
		}
	}

	/**
	 * <p>
	 * 金額マイナスチェック。
	 * </p>
	 * @param inMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @param inList 処理対象リスト
	 * @param workParamId 業務パラメータID配列
	 * @param itemNm 金額キー項目名
	 * @return 請求単位料金合計がマイナスの場合:false、0以上の場合:true
	 */
	protected static boolean execMinusChk(CAANMsg inCBSMsg, AgentDispatchContext inContext, ArrayList<CAANMsg> inList, String[] workParamId, String itemNm)
	{
		for (int i = 0; i < workParamId.length; i++)
		{
			// 料金項目抽出変換を取得（単一）
			CAANMsg[] prcKmkCsChge = JCHModelCommon.getPrcKmkCsChge(inCBSMsg, inContext, false, workParamId[i]);

			String sPrcGrpCd = prcKmkCsChge[0].getString("PRC_GRP_CD");
			String sPcrsCd = prcKmkCsChge[0].getString("PCRS_CD");
			String sPrcSvcCd = prcKmkCsChge[0].getString("PRC_SVC_CD");
			String sPrcKmkCd = prcKmkCsChge[0].getString("PRC_KMK_CD");

			// 金額
			String sAmnt = null;

			// 処理対象リストの中からチェック対象の料金項目コードに該当するものを取得
			for (CAANMsg inMsg : inList){

				if (sPrcGrpCd.equals(inMsg.getString("prc_grp_cd"))
						&& sPcrsCd.equals(inMsg.getString("pcrs_cd"))
						&& sPrcSvcCd.equals(inMsg.getString("prc_svc_cd"))
						&& sPrcKmkCd.equals(inMsg.getString("prc_kmk_cd")))
				{
					sAmnt = inMsg.getString(itemNm);
					break;
				}
			}

			if (sAmnt != null)
			{
				if (sAmnt.trim().length() == 0){
					return false;
				}

				BigDecimal bdAmnt = new BigDecimal(sAmnt);
	
				// 金額がマイナスの場合はエラー
				if (bdAmnt.compareTo(new BigDecimal(0)) < 0)
				{
					return false;
				}
			}
		}

		return true;
	}

	/**
	 * <p>
	 * 料金項目抽出変換に対象のレコードが存在するか判定するメソッドです。
	 * システムコード未設定の場合、デフォルトで"CH"を指定する。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @param con1 コネクション
	 * @param pstmt1 プリペアステートメント
	 * @param rsltQuery リザルトセット
	 * @param inputMsg 入力データ
	 * @param opeDate 運用日
	 * @param workKinoSkbtCd 業務機能識別コード
	 * @return boolean true：存在する、false：存在しない
	 */
	protected static boolean isExistsPrcKmkCd(CAANMsg inCBSMsg, AgentDispatchContext inContext,
			Connection con1, PreparedStatement pstmt1, ResultSet rsltQuery, CAANMsg inputMsg, String opeDate, String workKinoSkbtCd) {

		return isExistsPrcKmkCd(inCBSMsg, inContext, con1, pstmt1, rsltQuery, inputMsg, opeDate, workKinoSkbtCd, JACStrConst.SYS_CD_CH);
	}

	/**
	 * <p>
	 * 料金項目抽出変換に対象のレコードが存在するか判定するメソッドです。
	 * </p>
	 * @param inCBSMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @param con1 コネクション
	 * @param pstmt1 プリペアステートメント
	 * @param rsltQuery リザルトセット
	 * @param inputMsg 入力データ
	 * @param opeDate 運用日
	 * @param workKinoSkbtCd 業務機能識別コード
	 * @param sysCd システムコード
	 * @return boolean true：存在する、false：存在しない
	 */
	protected static boolean isExistsPrcKmkCd(CAANMsg inCBSMsg, AgentDispatchContext inContext,
			Connection con1, PreparedStatement pstmt1, ResultSet rsltQuery, CAANMsg inputMsg, String opeDate, String workKinoSkbtCd, String sysCd) {

		// パラメータ設定リスト
		List<Object> replaceListCnt = new ArrayList<Object>();

		try{
			// パラメータ設定リストに値を設定
			replaceListCnt.add(sysCd);
			replaceListCnt.add(workKinoSkbtCd);
			replaceListCnt.add(JACStrConst.CHSHT_CHG_CD_1);
			replaceListCnt.add(inputMsg.getString("prc_grp_cd"));
			replaceListCnt.add(inputMsg.getString("pcrs_cd"));
			replaceListCnt.add(inputMsg.getString("prc_svc_cd"));
			replaceListCnt.add(inputMsg.getString("prc_kmk_cd"));
			replaceListCnt.add(opeDate);

			// PreparedStatementの指定されたパラメータカラムに 指定された値を設定
			for (int idx = 0; idx < replaceListCnt.size(); idx++ )
			{
				CAANJDBCUtil.setParam(pstmt1, idx+1, replaceListCnt.get(idx));
			}

			// ResultSetの取得
			rsltQuery = pstmt1.executeQuery();

			if (rsltQuery.next())
			{
				if (BigDecimal.ZERO.compareTo(rsltQuery.getBigDecimal("COUNT")) < 0)
				{
					return true;
				}
			}
			return false;
		}
		catch (SQLException e)
		{
			inCBSMsg.set(CH0401ETMsg.STATUS, StatusCodes.FIND_DB_ERR);
			throw new CAANRuntimeException(e);
		}
// OM-2017-0000488 2017/05/26 ADD START
		finally {
			try{
				// 資源の解放
				if (null != rsltQuery)
				{
					rsltQuery.close();
				}
			}
			catch (SQLException e) {
				inCBSMsg.set(CH0401ETMsg.STATUS, StatusCodes.FIND_DB_ERR);
				throw new CAANRuntimeException(e);
			}
		}
// OM-2017-0000488 2017/05/26 ADD END
	}

	/**
	 * <p>
	 * 料金調整登録、料金変更登録のフロアリミットチェック用のSQLを作成する。
	 * </p>
	 * @return StringBuffer
	 */
	private static StringBuffer getFlrlmtChkSql()
	{
		StringBuffer sql_Buff = new StringBuffer();
		sql_Buff.append(" SELECT ")
				.append(" 	SUM(CH0101.AMNT) AMNT ")
				.append(" FROM ")
				.append(" 	CH_T_SEIKY CH0051 ")
				.append(" 	INNER JOIN ")
				.append(" 		CH_T_SEIKY_UCWK CH0101 ")
				.append(" 		ON CH0051.SEIKY_NO = CH0101.SEIKY_NO ")
				.append(" 	INNER JOIN CH_M_PRC_KMK_CS_CHGE CH0401 ")
				.append(" 		ON  CH0101.PRC_GRP_CD = CH0401.PRC_GRP_CD ")
				.append(" 		AND CH0101.PCRS_CD = CH0401.PCRS_CD ")
				.append(" 		AND CH0101.PRC_SVC_CD = CH0401.PRC_SVC_CD ")
				.append(" 		AND CH0101.PRC_KMK_CD = CH0401.PRC_KMK_CD ")
				.append(" WHERE")
				.append(" 	CH0051.SEIKY_YM = ? ")
				.append(" 	AND CH0051.SEIKY_WAY_CD = ? ")
				// v24.00.00 MOD START
//				.append(" 	AND CH0051.CRECARD_NO = ? ")
				.append(" 	AND CH0051.CRECARD_NO_AZKRI_ID = ? ")
				// v24.00.00 MOD END
				.append(" 	AND CH0051.MK_FLG = '0' ")
				.append(" 	AND CH0101.SEIKY_YM = ? ")
				.append(" 	AND CH0101.MK_FLG = '0' ")
				.append(" 	AND CH0401.SYS_CD = ? ")
				.append(" 	AND CH0401.WORK_KINO_SKBT_CD = ? ")
				.append(" 	AND CH0401.CHSHT_CHG_CD = ? ")
				.append(" 	AND CH0401.PRC_KMK_CS_CHGE_TSTAYMD <= ? ")
				.append(" 	AND CH0401.PRC_KMK_CS_CHGE_TENDYMD >= ? ")
				.append(" 	AND CH0401.MK_FLG = '0' ");

		return sql_Buff;
	}

	/**
	 * <p>
	 * 料金スケジュール定義から利用開始年月日を取得するSQLを作成する。
	 * </p>
	 * @return StringBuffer
	 */
	private static StringBuffer getUseStaYmdSql()
	{
		StringBuffer sql_Buff = new StringBuffer();
		sql_Buff.append(" SELECT ")
				.append(" 	MIN(CH0501.EVENT_YMD) USE_STAYMD ")
				.append(" FROM ")
				.append(" 	CH_M_PRC_SCHDL_TEIGI CH0501 ")
				.append(" WHERE")
				.append(" 	CH0501.SEIKY_YM = ? ")
				.append(" 	AND CH0501.EVENT_CD = ? ")
				.append(" 	AND CH0501.MK_FLG = '0' ");

		return sql_Buff;
	}

	/**
	 * <p>
	 * 料金スケジュール定義から利用終了年月日を取得するSQLを作成する。
	 * </p>
	 * @return StringBuffer
	 */
	private static StringBuffer getUseEndYmdSql()
	{
		StringBuffer sql_Buff = new StringBuffer();
		sql_Buff.append(" SELECT ")
				.append(" 	MAX(CH0501.EVENT_YMD) USE_ENDYMD ")
				.append(" FROM ")
				.append(" 	CH_M_PRC_SCHDL_TEIGI CH0501 ")
				.append(" WHERE")
				.append(" 	CH0501.SEIKY_YM = ? ")
				.append(" 	AND CH0501.EVENT_CD = ? ")
				.append(" 	AND CH0501.MK_FLG = '0' ");

		return sql_Buff;
	}

	/**
	 * 左辺と右辺を乗算します。
	 * 
	 * @param str1 計算値（左辺）
	 * @param str2 計算値（右辺）
	 * @param isNullToZero Nullを0に置き換えて計算するかを判断
	 * @return 計算結果
	 */
	protected static String calcMultiply(String str1, String str2, Boolean isNullToZero)
	{
		if (isNullToZero)
		{
			if (isNullOrEmpty(str1))
			{
				str1 = "0";
			}

			if (isNullOrEmpty(str2))
			{
				str2 = "0";
			}
		}
		else
		{
			if (isNullOrEmpty(str1) || isNullOrEmpty(str2))
			{
				return null;
			}
		}

		BigDecimal val1 = new BigDecimal(str1);
		BigDecimal val2 = new BigDecimal(str2);

		BigDecimal rtnValue = val1.multiply(val2);

		return rtnValue.toString();
	}

	/**
	 * 絶対値を取得します。
	 * 
	 * @param strVal 計算値
	 * @param isNullToZero Nullを0に置き換えて計算するかを判断
	 * @return 計算結果
	 */
	protected static String getAbs(String strVal, Boolean isNullToZero)
	{
		if (isNullToZero)
		{
			if (isNullOrEmpty(strVal))
			{
				strVal = "0";
			}
		}
		else
		{
			if (isNullOrEmpty(strVal))
			{
				return null;
			}
		}

		BigDecimal val1 = new BigDecimal(strVal);
		BigDecimal val2 = new BigDecimal(strVal);
		
		if (val1.compareTo(BigDecimal.ZERO) < 0)
		{
			val2 = val1.multiply(new BigDecimal("-1"));
		}

		return val2.toString();
	}
	
	/**
	 * NULLか空文字の判定処理.<br>
	 * <br>
	 * 
	 * @param strMoji 判定文字
	 * @return 判定結果 true:Null か 空文字
	 */
	private static boolean isNullOrEmpty(String strMoji)
	{
		boolean isEmpty = false;

		if (strMoji == null || JACStrConst.KARA_MOJI.equals(strMoji))
		{
			isEmpty = true;
		}

		return isEmpty;
	}
}
