/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：オンラインシステム日付取得部品
*   ソースファイル名：JCCGetSystemDateUtil.java
*   作成者          ：富士通
*   日付            ：2011年04月12日
*＜機能概要＞
*   OS保持の日時または、テスト用に擬似的に設定した日時を返却します。
*   アプリケーションプロパティファイルの定義に基づいて、呼出元に
*   OS保持の日時を返すか、テスト用に擬似的に設定した日時を返すか
*   決定します。
*   テスト日時の設定方法は以下の2種類があります。
*       1. 年月日のみ変更し、時分秒はOS保持の値を使用する
*       2. 年月日と時分秒を全て変更する
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v1.00.00    2011/04/12   FST）伊藤   新規作成
*
**********************************************************************/
package eo.common.util;

import java.lang.System;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.HashMap;
import com.fujitsu.futurity.model.common.JCMAPLConstMgr;
import eo.common.util.JCCFrameworkException;

public class JCCGetSystemDateUtil {
	/**
	 * 返却値のハッシュマップから、yyyyMMddHHmmssSSS形式の日付文字列を取得するキー
	 */
	public static final String KEY_YYYYMMDDHHMMSS_SSS  = "sysDateTimeStamp";
	/**
	 * 返却値のハッシュマップから、yyyyMMddHHmmss形式の日付文字列を取得するキー
	 */
	public static final String KEY_YYYYMMDDHHMMSS      = "sysDateTime";
	/**
	 * 返却値のハッシュマップから、yyyyMMdd形式の日付文字列を取得するキー
	 */
	public static final String KEY_YYYYMMDD            = "sysDate";
	
	// アプリ定義の取得キー
	private static final String KEY_APL_SYSDATE_ENV    = "SYSDATE_ENV";
	private static final String KEY_APL_TEST_SYSDATE   = "TEST_SYSDATE";
	private static final String KEY_APL_BASE_SYSDATE   = "BASE_SYSDATE";
	// 日付の変換に使用する変数
	private static final SimpleDateFormat fmtYYYYMMDD          = new SimpleDateFormat("yyyyMMdd");
	private static final SimpleDateFormat fmtYYYYMMDDhhmmss    = new SimpleDateFormat("yyyyMMddHHmmss");
	private static final SimpleDateFormat fmtYYYYMMDDhhmmssSSS = new SimpleDateFormat("yyyyMMddHHmmssSSS");
	private static final SimpleDateFormat fmthhmmssSSS         = new SimpleDateFormat("HHmmssSSS");
	private static long lZeroBase = 0;			// 0時0分0秒に相当する時刻（long型）
	
	/**
	 * アプリケーションプロパティファイルの定義に基づいて、OS保持の時刻または
	 * テスト用に擬似的に変更したテスト日時を返却します。<br>
	 * 定義を省略した場合、OS保持の日時を返却します。
	 * @return フォーマット済み日付文字列を格納したハッシュマップ。<br>
	 *         値を取得するためのキーと、取得できる値は以下の通り。<br>
	 * <table>
	 *   <tr><th>キー</th><th>値</th></tr>
	 *   <tr><td>sysDateTimeStamp</td><td>yyyyMMddHHmmssSSS形式</td></tr>
	 *   <tr><td>sysDateTime</td><td>yyyyMMddHHmmss形式</td></tr>
	 *   <tr><td>sysDate</td><td>yyyyMMdd形式</td></tr>
	 * </table>
	 * @throws JCCFrameworkException
	 *         アプリケーションプロパティファイルの定義誤り
	 * @author FST）伊藤
	 */
	public static HashMap<String, String> getSystemDateTime() throws Exception {
		
		String sSysDateEnv;				// アプリ定義のシステム日付取得元
		String sTestTime;				// アプリ定義のテスト時間
		String sBaseTime;				// アプリ定義のテスト基準時間
		long lOsTime;					// OS保持の時間  （long型）
		long lOsHHMMSS;					// OS保持の時間の、HHmmssSSS部分 （long型）
		long lTestTime=0;				// テスト時間    （long型）
		long lTestTimeBase;				// テスト基準時間（long型）
		long lRet = 0;					// 返却値の時刻  （long型）
		Date dateOsTime=null;			// OS保持の時刻  （Date型）
		Date dateTestTime=null;			// テスト時間    （Date型）
		Date dateTestTimeBase=null;		// テスト基準時間（Date型）
		Date dateRet;					// 返却値の時刻  （Date型）
		HashMap<String, String> mapRet;	// 返却値
		int iSysDateEnv;				// アプリ定義のシステム日付取得元
		int iLenTestTime=0;				// テスト時間の文字列長
		
		//------------------------------------------------
		// (1) 定義取得処理
		//------------------------------------------------
		//--------------------------------------------------------
		// (1)-1 アプリ定数「システム日付取得元」の正当性確認処理
		//--------------------------------------------------------
		// アプリ定義の「システム日付取得元」を取得する。
		sSysDateEnv = JCMAPLConstMgr.getString(KEY_APL_SYSDATE_ENV);
		// 「システム日付取得元」が省略された場合、
		if ( sSysDateEnv == null )
		{
			throw new JCCFrameworkException(
				      "APLConstの["+KEY_APL_SYSDATE_ENV+"]は省略できません");
		}
		// アプリ定義値の前後の空白を除去する。
		sSysDateEnv = sSysDateEnv.trim();
		// 「システム日付取得元」が
		// 「1:アプリケーションプロパティファイルから取得」の場合
		if      ("1".equals(sSysDateEnv))
		{
			iSysDateEnv = 1;
		}
		// 「システム日付取得元」が「2:OS保持の時刻から取得」の場合
		else if ("2".equals(sSysDateEnv))
		{
			iSysDateEnv = 2;
		}
		else
		{
			throw new JCCFrameworkException(
				      "APLConstで設定された["+KEY_APL_SYSDATE_ENV+"]は無効な値です（" + sSysDateEnv + "）");
		}
		//------------------------------------------------
		// (1)-2 アプリ定数「テスト時間」の正当性確認処理
		//------------------------------------------------
		// 「システム日付取得元」が
		// 「1:アプリケーションプロパティファイルから取得」の場合
		if ( 1 == iSysDateEnv )
		{
			// アプリ定義の「テスト時間」を取得する。
			sTestTime = JCMAPLConstMgr.getString(KEY_APL_TEST_SYSDATE);
			// 「テスト時間」が定義されていない場合
			if (sTestTime == null )
			{
				throw new JCCFrameworkException(
					      "APLConstで["+KEY_APL_SYSDATE_ENV+"]に1を設定した場合、["+KEY_APL_TEST_SYSDATE+"]は省略できません");
			}
			// アプリ定義値の前後の空白を除去する。
			sTestTime = sTestTime.trim();
			//-----------------------------------------------
			// (1)-2-1 「テスト時間」が8桁の場合
			//-----------------------------------------------
			iLenTestTime = sTestTime.length();
			if( 8 == iLenTestTime )
			{
				//  String→Date→Stringと再変換することによって、
				// 変換結果がYYYYMMDD形式の実在する日時であることを確認する。
				try
				{
					dateTestTime = fmtYYYYMMDD.parse(sTestTime);
				}
				catch (ParseException pe)
				{
					throw new JCCFrameworkException(
						      "APLConstで設定された[" + KEY_APL_TEST_SYSDATE
						      + "]はyyyyMMdd形式またはyyyyMMddHHmmss形式または実在する日付ではありません（"
						      + sTestTime + "）");
				}
				// 変換結果が変換前と一致しない場合
				if ( ! sTestTime.equals(fmtYYYYMMDD.format(dateTestTime)) )
				{
					throw new JCCFrameworkException(
						      "APLConstで設定された[" + KEY_APL_TEST_SYSDATE
						      + "]はyyyyMMdd形式またはyyyyMMddHHmmss形式または実在する日付ではありません（"
						      + sTestTime + "）");
				}
			}
			//-----------------------------------------------
			// (1)-2-2 「テスト時間」が14桁の場合
			//-----------------------------------------------
			else if ( 14 == iLenTestTime )
			{
				//  String→Date→Stringと再変換することによって、
				// 変換結果がYYYYMMDDhhmmss形式の実在する日時であることを確認する。
				try
				{
					dateTestTime = fmtYYYYMMDDhhmmss.parse(sTestTime);
				}
				catch (ParseException pe)
				{
					throw new JCCFrameworkException(
						      "APLConstで設定された[" + KEY_APL_TEST_SYSDATE
						      + "]はyyyyMMdd形式またはyyyyMMddHHmmss形式または実在する日付ではありません（"
						      + sTestTime + "）");
				}
				// 変換結果が変換前と一致しない場合
				if ( ! sTestTime.equals(fmtYYYYMMDDhhmmss.format(dateTestTime)) )
				{
					throw new JCCFrameworkException(
						      "APLConstで設定された[" + KEY_APL_TEST_SYSDATE
						      + "]はyyyyMMdd形式またはyyyyMMddHHmmss形式または実在する日付ではありません（"
						      + sTestTime + "）");
				}
			}
			// (1)-2-3 「テスト時間」の桁数が8、14以外の場合
			else
			{
				throw new JCCFrameworkException(
					      "APLConstで設定された[" + KEY_APL_TEST_SYSDATE
					      + "]はyyyyMMdd形式またはyyyyMMddHHmmss形式ではありません（"
					      + sTestTime + "）");
			}

			//----------------------------------------------------
			// (1)-3 アプリ定数「テスト基準時間」の正当性確認処理
			//----------------------------------------------------
			// 「テスト時間」が14桁の場合
			if ( 14 == iLenTestTime )
			{
				// アプリ定義の「テスト基準時間」を取得する。
				sBaseTime = JCMAPLConstMgr.getString(KEY_APL_BASE_SYSDATE);
				// 「テスト基準時間」が定義されていない場合
				if (sBaseTime == null )
				{
					throw new JCCFrameworkException(
							"APLConstで["+KEY_APL_TEST_SYSDATE+
							"]にyyyyMMddHHmmss形式の日時を設定した場合、["
							+KEY_APL_BASE_SYSDATE+"]は省略できません");
				}
				// アプリ定義値の前後の空白を除去する。
				sBaseTime = sBaseTime.trim();
				//  String→Date→Stringと再変換することによって、
				// 変換結果がYYYYMMDDhhmmss形式の実在する日時であることを確認する。
				try
				{
					dateTestTimeBase = fmtYYYYMMDDhhmmss.parse(sBaseTime);
				}
				catch (ParseException pe)
				{
					throw new JCCFrameworkException(
						      "APLConstで設定された[" + KEY_APL_BASE_SYSDATE
						      + "]はyyyyMMddHHmmss形式または実在する日付ではありません（"
						      + sBaseTime + "）");
				}
				// 変換結果が変換前と一致しない場合
				if (! sBaseTime.equals(fmtYYYYMMDDhhmmss.format(dateTestTimeBase)) )
				{
					throw new JCCFrameworkException(
						      "APLConstで設定された[" + KEY_APL_BASE_SYSDATE
						      + "]はyyyyMMddHHmmss形式または実在する日付ではありません（"
						      + sBaseTime + "）");
				}
			}
		}
		//--------------------------
		// (2) OS保持時刻の取得処理
		//--------------------------
		lOsTime=System.currentTimeMillis();
		// 「システム日付取得元」が省略されている、または
		// 「2:OS保持の時刻から取得」の場合
		if ( 2 == iSysDateEnv )
		{
			// テスト日付の生成は行わない。
			lRet = lOsTime;
		}
		else
		{
			//------------------------
			// (3) テスト日時生成処理
			//------------------------
			//----------------------------------------------------
			// (3)-1 テスト時間が8桁の場合のテスト日時算出処理
			//----------------------------------------------------
			if( 8 == iLenTestTime )
			{
				// long型で以下の演算を行い、結果をテスト日付とする。
				// テスト時間 + OS保持の時刻のhhmmssSSS部分 - 0時0分0秒に相当する時刻
				lTestTime = dateTestTime.getTime();
				dateOsTime = new Date(lOsTime);
				// 0時0分0秒に相当するlong型の値がstatic領域に設定されていなければ、取得する。
				if ( 0 == lZeroBase )
				{
					lZeroBase = fmthhmmssSSS.parse("000000000").getTime();
				}
				lOsHHMMSS = fmthhmmssSSS.parse(fmthhmmssSSS.format(dateOsTime)).getTime();
				lRet = lTestTime + lOsHHMMSS - lZeroBase;
			}
			//----------------------------------------------------
			// (3)-2 テスト時間が14桁の場合のテスト日時算出処理
			//----------------------------------------------------
			else
			{
				// long型で以下の演算を行い、結果をテスト日付とする。
				// OS保持の時刻 - テスト基準時間 + テスト時間
				lTestTime = dateTestTime.getTime();
				lTestTimeBase = dateTestTimeBase.getTime();
				lRet = lOsTime - lTestTimeBase + lTestTime;
			}
		}
		//----------------------------------
		// (4) 返却用ハッシュマップ生成処理
		//----------------------------------
		mapRet = new HashMap<String,String>();
		dateRet = new Date(lRet);
		mapRet.put(KEY_YYYYMMDDHHMMSS_SSS ,fmtYYYYMMDDhhmmssSSS.format(dateRet));
		mapRet.put(KEY_YYYYMMDDHHMMSS ,fmtYYYYMMDDhhmmss.format(dateRet));
		mapRet.put(KEY_YYYYMMDD, fmtYYYYMMDD.format(dateRet));
		return mapRet;
	}
}
