/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JSCMobileOrderNoGenerator
*   ソースファイル名：JSCMobileOrderNoGenerator.java
*   作成者          ：富士通
*   日付            ：2012年09月18日
*＜機能概要＞
*   モバイルオーダ番号採番部品です。
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v3.00.00    2012/09/18   富士通      新規作成
*
**********************************************************************/
package eo.ejb.common.edit;

import java.util.concurrent.TimeoutException;

import com.fujitsu.futurity.common.JCMConstants;
import com.fujitsu.futurity.model.base.CAANException;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.ejb.common.fw.AgentDispatchContext;

import eo.common.constant.JPCModelConstant;
import eo.common.constant.JSCStrConstant;
import eo.ejb.cbm.entity.SC0031ETMsg;
import eo.ejb.cbm.entity.SC0111ETMsg;
import eo.ejb.cbm.entity.SC0121ETMsg;
import eo.ejb.cbm.entity.SC0131ETMsg;

/**
 * モバイルオーダ番号採番部品
 * @author 富士通
 *
 */
public class JSCMobileOrderNoGenerator
{

	/** 偶数奇数のみの機能コード判断を行うインプット */
	private static final int IN_MSG_NORMAL_FUNC_CD = 0;
	/** モバイルオーダ受付のインプットのため特殊な機能コード判断が必要 */
	private static final int IN_MSG_MOBILE_ORDER = 1;
	/**
	 * <p>
	 * モバイルオーダ番号を採番します。
	 * </p>
	 * @param inMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @return 採番されたモバイルオーダ番号
	 */
	public static String getMobileOrderNo(CAANMsg inMsg, AgentDispatchContext inContext)
	{
		String value = "";
		
		// 機能コードのチェック（チェックモードの場合は採番しない）
		if (JSCCommonNoGenerator.isFuncMode(inMsg))
		{
			return " ";
		}

		try
		{
			//モバイルオーダ番号採番
			value = getNextMobileOrderNo();
			
			//モバイルサービスオーダ存在確認
			existsMobileOrder(value);
		}
		catch (TimeoutException te)
		{
			throw new RuntimeException(te);
		}
		catch (CAANException ce)
		{
			throw new RuntimeException(ce);
		}
		return value;
	}
	
	/**
	 * 送受信管理番号採番(ＥＭ)
	 * @param inMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @return	採番された送受信管理番号（ＥＭ用）
	 */
	public static String getEmOrdSRInfoNo(CAANMsg inMsg, AgentDispatchContext inContext)
	{
		String value = "";
		
		// 機能コードのチェック（チェックモードの場合は採番しない）
		if (false == isFuncCodeForEMIns(inMsg))
		{
			return " ";
		}
		try
		{
			value = getNextEmOrdSRInfNo();
		}
		catch (TimeoutException te)
		{
			throw new RuntimeException(te);
		}
		catch (CAANException ce)
		{
			throw new RuntimeException(ce);
		}
		return value;
	}
	
	/**
	 * 送受信管理番号採番(ＵＱ)
	 * @param inMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @return	採番された送受信管理番号（ＵＱ用）
	 */
	public static String getUqOrdSRInfNo(CAANMsg inMsg, AgentDispatchContext inContext)
	{
		String value = "";
		
		// 機能コードのチェック（チェックモードの場合は採番しない）
		if (false == isFuncCodeForUQIns(inMsg))
		{
			return " ";
		}
		try
		{
			value = getNextUqOrdSRInfNo();
		}
		catch (TimeoutException te)
		{
			throw new RuntimeException(te);
		}
		catch (CAANException ce)
		{
			throw new RuntimeException(ce);
		}
		return value;
	}
	
	/**
	 * 送受信管理番号採番(ＳＰＯＴ)
	 * @param inMsg 処理対象のメッセージキャリア
	 * @param inContext Agentから渡されたAgentDispatchContext
	 * @return	採番された送受信管理番号（ＳＰＯＴ用）
	 */
	public static String getSpotOrdSRInfNo(CAANMsg inMsg, AgentDispatchContext inContext)
	{
		String value = "";
		
		// 機能コードのチェック（チェックモードの場合は採番しない）
		if (false == isFuncCodeForSPOTIns(inMsg))
		{
			return " ";
		}
		try
		{
			value = getNextSpotOrdSRInfNo();
		}
		catch (TimeoutException te)
		{
			throw new RuntimeException(te);
		}
		catch (CAANException ce)
		{
			throw new RuntimeException(ce);
		}
		return value;
	}
	
	/**
	 * 送受信管理番号採番(ＥＭ)
	 * @return	採番された送受信管理番号（ＥＭ用）
	 * @throws TimeoutException
	 * @throws CAANException
	 */
	private static String getNextEmOrdSRInfNo() throws TimeoutException, CAANException
	{
		String retStr = null;
		int loopCount = 0;
		String sodRenkeiSeq = null;
		JSCEMOrdSRInfoAccesser accObj = new JSCEMOrdSRInfoAccesser();
		
		while(true)
		{
			// ---タイムアウト処理
			
			++loopCount;
			if (loopCount > JSCStrConstant.MAX_NEXT_SEQ_COUNT) 
			{
				throw new TimeoutException();
			}
			
			// ---シーケンス取得
			
			retStr = JSCCommonNoGenerator.getFormatedNextSeq(JSCStrConstant.ORA_SEQ_SRINF_KANRI_NO_EM, JSCStrConstant.SRINF_KANRI_NO_LEN);
			
			// ---存在チェック
			
			// 条件設定
			CAANMsg sc0131Msg = new CAANMsg(SC0131ETMsg.class.getName());
			
			// 送受信管理番号
			sc0131Msg.set(SC0131ETMsg.SRINF_KANRI_NO, retStr);
			
			sc0131Msg = accObj.findByPrimaryKey(sc0131Msg);
			
			// 結果が存在しない場合
			if (null == sc0131Msg)
			{
				break;
			}
			
			// ---検索結果の削除処理
			
			sodRenkeiSeq = sc0131Msg.getString(SC0131ETMsg.SOD_RENKEI_SEQ);
			
			if (checkRestOrder(sodRenkeiSeq)) 
			{
				// 削除実行
				existsMobileOrder(sodRenkeiSeq);
				break;
			}
		}
		
		return retStr;
	}
	
	/**
	 * 送受信管理番号採番(ＵＱ)
	 * @return	採番された送受信管理番号（ＵＱ用）
	 * @throws TimeoutException
	 * @throws CAANException
	 */
	private static String getNextUqOrdSRInfNo() throws TimeoutException, CAANException
	{
		
		String retStr = null;
		int loopCount = 0;
		String sodRenkeiSeq = null;
		JSCUQOrdSRInfoAccesser accObj = new JSCUQOrdSRInfoAccesser();
		
		while(true)
		{
			// ---タイムアウト処理

			++loopCount;
			if (loopCount >= JSCStrConstant.MAX_NEXT_SEQ_COUNT) 
			{
				throw new TimeoutException();
			}
			
			// ---シーケンス取得
			
			retStr = JSCCommonNoGenerator.getFormatedNextSeq(JSCStrConstant.ORA_SEQ_SRINF_KANRI_NO_UQ, JSCStrConstant.SRINF_KANRI_NO_LEN);
			
			// ---存在チェック
			
			// 条件設定
			CAANMsg sc0111Msg = new CAANMsg(SC0111ETMsg.class.getName());
			
			// 送受信管理番号
			sc0111Msg.set(SC0111ETMsg.SRINF_KANRI_NO, retStr);
			
			sc0111Msg = accObj.findByPrimaryKey(sc0111Msg);
			
			// 結果が存在しない場合
			if (null == sc0111Msg)
			{
				break;
			}
			
			// ---検索結果の削除処理
			
			sodRenkeiSeq = sc0111Msg.getString(SC0111ETMsg.SOD_RENKEI_SEQ);
			
			if (checkRestOrder(sodRenkeiSeq)) 
			{
				// 削除実行
				existsMobileOrder(sodRenkeiSeq);
				break;
			}
		}
		
		return retStr;
	}
	
	/**
	 * 送受信管理番号採番(ＳＰＯＴ)
	 * @return	採番された送受信管理番号（ＳＰＯＴ用）
	 * @throws TimeoutException
	 * @throws CAANException
	 */
	private static String getNextSpotOrdSRInfNo() throws TimeoutException, CAANException
	{
		String retStr = null;
		int loopCount = 0;
		String sodRenkeiSeq = null;
		JSCSpotOrdSRInfoAccesser accObj = new JSCSpotOrdSRInfoAccesser();
		
		while(true)
		{
			// ---タイムアウト処理
			
			++loopCount;
			if (loopCount > JSCStrConstant.MAX_NEXT_SEQ_COUNT) 
			{
				throw new TimeoutException();
			}
			
			// ---シーケンス取得
			
			retStr = JSCCommonNoGenerator.getFormatedNextSeq(JSCStrConstant.ORA_SEQ_SRINF_KANRI_NO_SPOT, JSCStrConstant.SRINF_KANRI_NO_LEN);
			
			// ---存在チェック
			
			// 条件設定
			CAANMsg sc0121Msg = new CAANMsg(SC0121ETMsg.class.getName());
			
			// 送受信管理番号
			sc0121Msg.set(SC0121ETMsg.SRINF_KANRI_NO, retStr);
			
			sc0121Msg = accObj.findByPrimaryKey(sc0121Msg);
			
			// 結果が存在しない場合
			if (null == sc0121Msg)
			{
				break;
			}
			
			// ---検索結果の削除処理
			
			sodRenkeiSeq = sc0121Msg.getString(SC0111ETMsg.SOD_RENKEI_SEQ);
			
			if (checkRestOrder(sodRenkeiSeq)) 
			{
				// 削除実行
				existsMobileOrder(sodRenkeiSeq);
				break;
			}
		}
		
		return retStr;
	}

	/**
	 * <p>
	 * 次モバイルオーダ番号を採番します。
	 * </p>
	 * @return 採番されたモバイルオーダ番号
	 * @throws TimeoutException
	 * @throws CAANException
	 */
	private static String getNextMobileOrderNo() throws TimeoutException, CAANException
	{
		String nextSeq = null;
		int loopCount = 0;

		//利用可能なオーダ番号を取得できるまで継続
		while (true) 
		{
			++loopCount;
			
			//最大継続回数を過ぎた場合はTimeOutExceptionをThrow
			if (loopCount > JSCStrConstant.MAX_NEXT_SEQ_COUNT) 
			{
				throw new TimeoutException();
			}

			//次シーケンスを取得
			nextSeq = JSCCommonNoGenerator.getFormatedNextSeq(JSCStrConstant.ORA_SEQ_MOBILE_ORDER_NO, JSCStrConstant.ORDER_NO_LEN);
			
			// オーダ番号使用可能チェック
			if (checkRestOrder(nextSeq))
			{
				break;
			}
		}

		return nextSeq;
	}
	
	/**
	 * オーダ番号使用可能チェック
	 * 	不要なデータが残存する場合は削除し、使用可能とする
	 * @param orderNo	オーダ番号
	 * @return	boolean	false:オーダ番号使用不可
	 * @throws CAANException
	 */
	private static boolean checkRestOrder(String orderNo) throws CAANException
	{
		//EMサービスオーダ使用可能チェック
		if (false == checkRestEMOrder(orderNo)) 
		{ 
			return false;
		}
		//UQサービスオーダ使用可能チェック
		if (false == checkRestUQOrder(orderNo)) 
		{ 
			return false; 
		}
		//SPOTサービスオーダ使用可能チェック
		if (false == checkRestSpotOrder(orderNo)) 
		{ 
			return false;
		}
		
		return true;
	}

	/**
	 * EMオーダ使用可能チェック
	 * 	不要なデータが残存する場合は削除し、使用可能とする
	 * @param orderNo	オーダ番号
	 * @return boolean	false：オーダ番号使用不可
	 * @throws CAANException
	 */
	private static boolean checkRestEMOrder(String orderNo) throws CAANException
	{
		CAANMsg sc0131InMsg = new CAANMsg(SC0131ETMsg.class.getName());
		CAANMsg[] sc0131OutMsgs = null;

		// ---検索実行
		
		JSCEMOrdSRInfoAccesser scEMOrder = new JSCEMOrdSRInfoAccesser();
		sc0131InMsg.set(SC0111ETMsg.SOD_RENKEI_SEQ, orderNo);
		sc0131OutMsgs = scEMOrder.findByCondition(sc0131InMsg);
		
		// 取得出来ない場合は使用可能
		if (null == sc0131OutMsgs || sc0131OutMsgs.length == 0)
		{
			return true;
		}
		
		// ---ステータスのチェック
		
		//応答正常、再送依頼済以外が存在する場合はオーダ番号使用不可
		for (int i = 0; i < sc0131OutMsgs.length; i++)
		{
			String sodStat = sc0131OutMsgs[i].getString(SC0131ETMsg.SOD_STAT);
			if (false == JSCStrConstant.SOD_STAT_ACK_NORMAL.equals(sodStat)
				&& false == JSCStrConstant.SOD_STAT_REAPPLIED.equals(sodStat)) 
			{
					return false;
			}
		}
		
		// ---再利用のための削除処理
		
		for (int i = 0; i < sc0131OutMsgs.length; i++) 
		{
			scEMOrder.removeOrder(sc0131OutMsgs[i]);
		}
		return true;
	}
	
	/**
	 * UQオーダ使用可能チェック
	 * 	不要なデータが残存する場合は削除し、使用可能とする
	 * @param orderNo	オーダ番号
	 * @return boolean	false：オーダ番号使用不可
	 * @throws CAANException
	 */
	private static boolean checkRestUQOrder(String orderNo) throws CAANException
	{
		CAANMsg sc0111InMsg = new CAANMsg(SC0111ETMsg.class.getName());
		CAANMsg[] sc0111OutMsgs = null;

		// ---検索実行
		
		JSCUQOrdSRInfoAccesser scUQOrder = new JSCUQOrdSRInfoAccesser();
		sc0111InMsg.set(SC0111ETMsg.SOD_RENKEI_SEQ, orderNo);
		sc0111OutMsgs = scUQOrder.findByCondition(sc0111InMsg);
		
		// 取得出来ない場合は使用可能
		if (null == sc0111OutMsgs || sc0111OutMsgs.length == 0)
		{
			return true;
		}
		
		// ---ステータスのチェック
		
		//応答正常、再送依頼済以外が存在する場合はオーダ番号使用不可
		for (int i = 0; i < sc0111OutMsgs.length; i++)
		{
			String sodStat = sc0111OutMsgs[i].getString(SC0111ETMsg.SOD_STAT);
			if (false == sodStat.equals(JSCStrConstant.SOD_STAT_ACK_NORMAL)
				&& false == sodStat.equals(JSCStrConstant.SOD_STAT_REAPPLIED)) 
			{
					return false;
			}
		}

		// ---再利用のための削除処理
		
		for (int i = 0; i < sc0111OutMsgs.length; i++) 
		{
			scUQOrder.removeOrder(sc0111OutMsgs[i]);
		}
		return true;
	}

	/**
	 * SPOTオーダ使用可能チェック
	 * 	不要なデータが残存する場合は削除し、使用可能とする
	 * @param orderNo	オーダ番号
	 * @return boolean	false：オーダ番号使用不可
	 * @throws CAANException
	 */
	private static boolean checkRestSpotOrder(String orderNo) throws CAANException 
	{
		CAANMsg sc0121InMsg = new CAANMsg(SC0121ETMsg.class.getName());
		CAANMsg[] sc0121OutMsgs = null;

		// ---検索実行
		
		JSCSpotOrdSRInfoAccesser scSpotOrder = new JSCSpotOrdSRInfoAccesser();
		sc0121InMsg.set(SC0121ETMsg.SOD_RENKEI_SEQ, orderNo);
		sc0121OutMsgs = scSpotOrder.findByCondition(sc0121InMsg);
		
		// 取得出来ない場合は使用可能
		if (null == sc0121OutMsgs || sc0121OutMsgs.length == 0)
		{
			return true;
		}
		
		// ---ステータスのチェック
		
		//応答正常、再送依頼済以外が存在する場合はオーダ番号使用不可
		for (int i = 0; i < sc0121OutMsgs.length; i++)
		{
			String sodStat = sc0121OutMsgs[i].getString(SC0121ETMsg.SOD_STAT);
			if (false == sodStat.equals(JSCStrConstant.SOD_STAT_ACK_NORMAL)
				&& false == sodStat.equals(JSCStrConstant.SOD_STAT_REAPPLIED))
			{
					return false;
			}
		}
		
		// ---再利用のための削除処理
		
		for (int i = 0; i < sc0121OutMsgs.length; i++) 
		{
			scSpotOrder.removeOrder(sc0121OutMsgs[i]);
		}
		
		return true;
	}



	/**
	 * モバイルオーダ存在確認
	 * 	存在する場合は削除する
	 * @param orderNo	オーダ番号
	 * @throws CAANException
	 */
	private static void existsMobileOrder(String orderNo) throws CAANException
	{
		CAANMsg sc0031InMsg = new CAANMsg(SC0031ETMsg.class.getName());
		JSCMobileOrderAccesser scMobileOrder = new JSCMobileOrderAccesser();
		sc0031InMsg.set(SC0031ETMsg.MOBILE_ORDER_NO, orderNo);

		sc0031InMsg = scMobileOrder.findByPrimaryKey(sc0031InMsg);
		if (null != sc0031InMsg)
		{
			scMobileOrder.removeOrder(sc0031InMsg);
		}
	}
	
	/**
	 * func_codeを判断して、EM用のオーダ受付採番が必要な場合trueを返します。
	 * 
	 * @param inMsg inMsg
	 * @return 採番が必要な場合true
	 */
	private static boolean isFuncCodeForEMIns(CAANMsg inMsg)
	{
		boolean retBool = false;
		int checkResult =checkNormalFuncCode(inMsg);
		
		// モバイルオーダ受付による採番の場合
		if (IN_MSG_MOBILE_ORDER == checkResult)
		{
			retBool = inMsg.getObject(JCMConstants.FUNC_CODE_KEY).equals(JPCModelConstant.FUNC_CD_1);
		}
		// 通常の機能コードを持つインプットによる採番の場合
		else
		{
			// チェックモード以外の場合は採番する
			if (false == JSCCommonNoGenerator.isFuncMode(inMsg))
			{
				retBool = true;
			}
		}
		return retBool;
	}
	
	/**
	 * func_codeを判断して、UQ用のオーダ受付採番が必要な場合trueを返します。
	 * 
	 * @param inMsg inMsg
	 * @return 採番が必要な場合true
	 */
	private static boolean isFuncCodeForUQIns(CAANMsg inMsg)
	{
		boolean retBool = false;
		int checkResult =checkNormalFuncCode(inMsg);
		// モバイルオーダ受付による採番の場合
		if (IN_MSG_MOBILE_ORDER == checkResult)
		{
			retBool = inMsg.getObject(JCMConstants.FUNC_CODE_KEY).equals(JPCModelConstant.FUNC_CD_3);
		}
		// 通常の機能コードを持つインプットによる採番の場合
		else
		{
			// チェックモード以外の場合は採番する
			if (false == JSCCommonNoGenerator.isFuncMode(inMsg))
			{
				retBool = true;
			}
		}
		return retBool;
	}
	
	/**
	 * func_codeを判断して、SPOT用のオーダ受付採番が必要な場合trueを返します。
	 * 
	 * @param inMsg inMsg
	 * @return 採番が必要な場合true
	 */
	private static boolean isFuncCodeForSPOTIns(CAANMsg inMsg)
	{
		boolean retBool = false;
		int checkResult =checkNormalFuncCode(inMsg);
		// モバイルオーダ受付による採番の場合
		if (IN_MSG_MOBILE_ORDER == checkResult)
		{
			retBool = inMsg.getObject(JCMConstants.FUNC_CODE_KEY).equals(JPCModelConstant.FUNC_CD_5);
		}
		// 通常の機能コードを持つインプットによる採番の場合
		else
		{
			// チェックモード以外の場合は採番する
			if (false == JSCCommonNoGenerator.isFuncMode(inMsg))
			{
				retBool = true;
			}
		}
		return retBool;
	}
	
	/**
	 * 特殊な機能コード判断が必要なインプットであるかを確認する
	 * @param inMsg
	 * @return 0:基本的な機能コードによる判断を行うインプット
	 */
	private static int checkNormalFuncCode(CAANMsg inMsg)
	{
		// モバイルオーダ受付の場合
		if ("eo.ejb.cbs.cbsmsg.ESC0031D010CBSMsg".equals(inMsg.getSchemaName()))
		{
			return IN_MSG_MOBILE_ORDER;
		}
		
		// 特殊な判断が不要である場合
		return IN_MSG_NORMAL_FUNC_CD;
	}
}
