/*
 * MosP - Mind Open Source Project    http://www.mosp.jp/
 * Copyright (C) MIND Co., Ltd.       http://www.e-mind.co.jp/
 * 
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package jp.mosp.platform.base;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;

import jp.mosp.framework.base.BaseAction;
import jp.mosp.framework.base.BaseDtoInterface;
import jp.mosp.framework.base.BaseVo;
import jp.mosp.framework.base.MospException;
import jp.mosp.framework.base.MospParametersMapper;
import jp.mosp.framework.base.MospParams;
import jp.mosp.framework.base.TopicPath;
import jp.mosp.framework.constant.ExceptionConst;
import jp.mosp.framework.constant.MospConst;
import jp.mosp.framework.instance.InstanceFactory;
import jp.mosp.framework.property.RangeProperty;
import jp.mosp.framework.property.RoleMenuProperty;
import jp.mosp.framework.property.RoleProperty;
import jp.mosp.framework.utils.DateUtility;
import jp.mosp.framework.utils.MospUtility;
import jp.mosp.framework.utils.TopicPathUtility;
import jp.mosp.framework.utils.ViewFileLocationUtility;
import jp.mosp.platform.bean.human.HumanSearchBeanInterface;
import jp.mosp.platform.constant.PlatformConst;
import jp.mosp.platform.constant.PlatformMessageConst;
import jp.mosp.platform.dto.human.HumanDtoInterface;
import jp.mosp.platform.dto.system.UserMasterDtoInterface;

/**
 * MosPプラットフォームにおけるActionの基本機能を提供する。<br>
 */
public abstract class PlatformAction extends BaseAction {
	
	/**
	 * MosPアプリケーション設定キー(テンプレートJSPファイルパス)。
	 */
	public static final String				APP_TEMPLATE_JSP	= "TemplateJsp";
	
	/**
	 * MosPアプリケーション設定キー(テンプレートJSPファイルパス)。
	 */
	public static final String				APP_NAVI_JSP		= "NaviJsp";
	
	/**
	 * MosPアプリケーション設定キー(標準CSSファイルパス)。
	 */
	public static final String				APP_BASE_CSS_FILES	= "BaseCssFiles";
	
	/**
	 * MosPアプリケーション設定キー(標準JSファイルパス)。
	 */
	public static final String				APP_BASE_JS_FILES	= "BaseJsFiles";
	
	/**
	 * MosPアプリケーション設定キー(ポータル表示コマンド)。
	 */
	protected static final String			APP_COMMAND_PORTAL	= "CommandPortal";
	
	/**
	 * MosPアプリケーション設定キー(初期表示コマンド)。
	 */
	protected static final String			APP_COMMAND_INDEX	= "CommandIndex";
	
	/**
	 * MosPアプリケーション設定キー(一覧表示数)。
	 */
	protected static final String			APP_LIST_LENGTH		= "ListLength";
	
	/**
	 * MosP汎用パラメータキー(画面表示時にスクロールさせるHTML要素のID)。<br>
	 * このキーで設定したStringは、画面表示時にJavaScriptの変数として宣言される。<br>
	 */
	protected static final String			MGP_JS_SCROLL_TO	= "jsScrollTo";
	
	/**
	 * MosPプラットフォーム用BeanHandler。
	 */
	protected PlatformBeanHandlerInterface	platform;
	
	/**
	 * MosPプラットフォーム参照用BeanHandler。
	 */
	protected ReferenceBeanHandlerInterface	platformReference;
	
	/**
	 * パンくずリスト用コマンド。<br>
	 * コマンドは、各アクションで設定する。<br>
	 */
	protected String						topicPathCommand	= null;
	

	/**
	 * アクションの前処理を実行する。<br><br>
	 * <ul><li>
	 * BaseActionのpreActionを実行<br><br>
	 * </li><li>
	 * リクエストされたメニューキーを取得<br>
	 * {@link #getTransferredMenuKey()}で取得する。<br><br>
	 * </li><li>
	 * パンくずリスト初期化(ポータルのみ残す)<br>
	 * メニューキーが存在する場合のみ実施する。<br><br>
	 * </li><li>
	 * 範囲設定の読込<br>
	 * メニューキーが存在する場合のみ実施する。<br><br>
	 * </li></ul>
	 */
	@Override
	protected void preAction() throws MospException {
		// BaseActionのpreActionを実行
		super.preAction();
		// リクエストされたメニューキーを取得
		String menuKey = getTransferredMenuKey();
		// ユーザ確認
		checkLoginUser();
		// メニューキー確認(連続実行の場合は実施しない)
		if (menuKey != null && menuKey.isEmpty() == false && mospParams.getNextCount() == 0) {
			// 範囲設定読込
			setRangeMap(menuKey);
			// パンくずリスト初期化(ポータルのみ残す)
			removeAfterIndex(mospParams.getTopicPathList(), 0);
		}
	}
	
	/**
	 * ログインユーザを確認する。<br>
	 * ログインしている(ログインユーザが存在する)場合、
	 * システム日付において、ユーザ情報、人事基本情報が存在することを確認する。<br>
	 * これらが存在しない場合、MosP例外を発行し、ログアウト処理をする。<br>
	 * @throws MospException ユーザ情報、人事基本情報が存在しない場合
	 */
	protected void checkLoginUser() throws MospException {
		/* THINK 個人履歴削除の削除対象ユーザのためのチェック
		 * 当処理には、DBへの接続と検索が必ず実施されるため
		 * 影多くの人が同時に使う場合など、レスポンスに影響あり
		 * 削除した人だけ、削除処理のアクションを実行して1週間以内だけなど
		 * したいが何処に削除した人や削除処理の日を保持しておくか問題
		 */
		// ユーザがいない場合
		if (mospParams.getUser() == null) {
			return;
		}
		// ログインユーザを取得
		String userlId = mospParams.getUser().getUserId();
		// 個人ID取得
		String personalId = mospParams.getUser().getPersonalId();
		// システム日付取得
		Date systemTime = DateUtility.getSystemTime();
		// システム日付でユーザ情報取得
		UserMasterDtoInterface userMasterDto = reference().user().getUserInfo(userlId, systemTime);
		// システム日付で人事基本情報取得
		HumanDtoInterface humanDto = reference().human().getHumanInfo(personalId, systemTime);
		// ユーザ情報或いは人事基本情報が存在しない場合
		if (userMasterDto == null || humanDto == null) {
			// ログアウト処理(MosPセッション保持情報初期化)
			mospParams.getStoredInfo().initStoredInfo();
			// 初期表示コマンド設定
			String nextCommand = mospParams.getApplicationProperty(APP_COMMAND_INDEX);
			mospParams.setNextCommand(nextCommand);
			// ログアウトメッセージ追加
			mospParams.addErrorMessage(PlatformMessageConst.MSG_LOGOUT_NOT_EXIST_USER, null);
			// MosP例外を発行
			throw new MospException(PlatformMessageConst.MSG_LOGOUT_NOT_EXIST_USER);
		}
	}
	
	/**
	 * 範囲設定を設定する。<br>
	 * ログインユーザからロールを取得し、メニューキーで範囲情報を取得する。<br>
	 * @param menuKey メニューキー
	 */
	protected void setRangeMap(String menuKey) {
		// ロール設定情報を取得
		RoleProperty role = mospParams.getUserRole();
		// ロールメニュー設定情報を取得
		RoleMenuProperty menu = role.getRoleMenuMap().get(menuKey);
		// 範囲情報を取得し設定
		mospParams.getStoredInfo().setRangeMap(menu.getRangeMap());
	}
	
	/**
	 * 範囲設定を確認する。<br>
	 * 範囲設定が存在しない場合、
	 * ログインユーザからロールを取得し、メニューキーで範囲情報を取得する。<br>
	 * @param menuKey メニューキー
	 */
	protected void checkRangeMap(String menuKey) {
		// 範囲設定取得及び確認
		Map<String, RangeProperty> rangeMap = mospParams.getStoredInfo().getRangeMap();
		if (rangeMap != null && rangeMap.isEmpty() == false) {
			return;
		}
		// 範囲設定
		setRangeMap(menuKey);
	}
	
	/**
	 * VOインスタンスの取得及び設定。<br><br>
	 * {@link #prepareVo(boolean, boolean)}を実行する。引数はtrue、true。<br>
	 * @return 取得したVOインスタンス
	 * @throws MospException パラメータがマッピングできなかった場合
	 */
	protected BaseVo prepareVo() throws MospException {
		return prepareVo(true, true);
	}
	
	/**
	 * VOインスタンスの取得及び設定。<br><br>
	 * <ul><li>
	 * VOインスタンス取得<br>
	 * {@link #getSpecificVo()}で、処理対象VOインスタンスを取得する。<br><br>
	 * </li><li>
	 * 保存VO確認<br>
	 * {@link MospParams#getStoredVo(String)}で、VOインスタンスのクラス名を
	 * キーとして保存VOを取得する。<br><br>
	 * </li><li>
	 * パラメータマッピング<br>
	 * {@link MospParametersMapper#mapParameters(Object, Map)}を行う。<br><br>
	 * </li><li>
	 * フォワード先URLの設定<br>
	 * {@link #setViewPath(String)}を行う。<br><br>
	 * </li><li>
	 * VOの設定<br>
	 * {@link MospParams#setVo(BaseVo)}を行う。<br><br>
	 * </li><li>
	 * パンくずリストの設定<br>
	 * {@link #setTopicPath()}を行う。<br><br>
	 * </li></ul>
	 * @param useStoredVo         保持VO利用フラグ(true：保持VOを使う、false：保持VOがあろうと新規VOを使う)
	 * @param useParametersMapper マッピングフラグ(true：パラメータをVOにマッピングする、false：マッピングしない)
	 * @return 取得したVOインスタンス
	 * @throws MospException パラメータがマッピングできなかった場合
	 */
	protected BaseVo prepareVo(boolean useStoredVo, boolean useParametersMapper) throws MospException {
		// VOインスタンス取得
		BaseVo baseVo = getSpecificVo();
		// 保存VO確認
		BaseVo storedVo = mospParams.getStoredVo(baseVo.getClassName());
		if (storedVo != null && useStoredVo) {
			baseVo = storedVo;
		}
		// パラメータマッピング
		if (useParametersMapper) {
			MospParametersMapper.mapParameters(baseVo, mospParams.getRequestParamsMap());
		}
		// VO及びフォワード先URLの設定
		setTemplateUrl();
		addBaseJsCssFiles();
		setViewPath(baseVo.getClassName());
		mospParams.setVo(baseVo);
		setTopicPath();
		return baseVo;
	}
	
	/**
	 * VO取得。<br><br>
	 * {@link #prepareVo()}で用いられる。<br>
	 * {@link BaseAction}を拡張したクラスでこのメソッドをオーバーライドすることで、
	 * {@link #prepareVo()}を用いて{@link BaseVo}を拡張した任意のVOインスタンスを
	 * 取得することができる。
	 * @return VOインスタンス
	 */
	protected BaseVo getSpecificVo() {
		return new PlatformVo();
	}
	
	/**
	 * MosPフレームワーク表示用ファイルパス設定
	 * @param className 対象VOクラス名
	 * <p>{@link BaseVo}を継承している対象VOの表示用ファイルパスを設定するメソッド。</p>
	 * <p>{@link BaseVo#BaseVo()}を呼び出した後、{@link PlatformVo#getClassName()}をパラメータにセットすることで、<br>
	 * 対象VOに直接JSP、CSS、JSのファイルパスをハードコードしなくても呼び出すことができる。<br>
	 * その代わり、ファイルの場所は必ず規約通りの場所にしなければならない。<br>
	 * もちろん、このメソッドを利用せず、従来の方法を利用することも可能である。
	 * </p>
	 * <p>
	 * ファイルの場所の規約は{@link ViewFileLocationUtility#ViewFileLocationUtility(String)}を参照すること。
	 * </p>
	 */
	protected void setViewPath(String className) {
		ViewFileLocationUtility location = new ViewFileLocationUtility(className);
		mospParams.setArticleUrl(location.getRetUrl());
		mospParams.addCssFile(location.getExtraCss());
		mospParams.addJsFile(location.getExtraJs());
	}
	
	/**
	 * テンプレートJSP用のURLを設定する。
	 */
	protected void setTemplateUrl() {
		// MosP設定情報からテンプレートJSPファイルパスを取得し設定
		mospParams.setUrl(mospParams.getApplicationProperty(APP_TEMPLATE_JSP));
		// ナビ(メニュー)URLを設定(パスワード変更画面等でnullにされることがある)
		mospParams.setNaviUrl(mospParams.getApplicationProperty(APP_NAVI_JSP));
	}
	
	/**
	 * 標準JavaScriptファイル及びCSSファイルを設定する。
	 */
	protected void addBaseJsCssFiles() {
		// MosP設定情報から標準ファイルパスを取得
		String[] baseCssFiles = mospParams.getApplicationProperties(APP_BASE_CSS_FILES);
		String[] baseJsFiles = mospParams.getApplicationProperties(APP_BASE_JS_FILES);
		// MosPパラメータに標準ファイルパスを設定
		for (String baseCssFile : baseCssFiles) {
			mospParams.addCssFile(baseCssFile);
		}
		for (String baseJsFile : baseJsFiles) {
			mospParams.addJsFile(baseJsFile);
		}
	}
	
	/**
	 * パンくずをリストにセットする。<br>
	 * 既にパンくずリストに操作対象が存在する場合は、VOを上書きする。<br>
	 * 操作対象が存在しない場合は、パンくずリストに追加する。<br>
	 */
	private void setTopicPath() {
		// セッションからパンくずリストを取得
		List<TopicPath> topicPathList = mospParams.getTopicPathList();
		// パンくず操作対象VOを取得
		BaseVo vo = mospParams.getVo();
		// 操作対象のパンくずリストにおけるインデックスを取得
		int idx = TopicPathUtility.getTopicPathIndex(topicPathList, vo.getClassName());
		// インデックス確認
		if (idx >= 0) {
			// パンくず操作対象より後のパンくずを除去
			removeAfterIndex(topicPathList, idx);
			// パンくず操作対象のVOを上書き
			topicPathList.get(idx).setVo(vo);
			return;
		}
		// パンくず追加(操作対象のパンくずが存在しない場合)
		topicPathList.add(createTopicPath());
	}
	
	/**
	 * パンくずを生成する。<br>
	 * @return パンくず
	 */
	private TopicPath createTopicPath() {
		// パンくず生成
		TopicPath topicPath = new TopicPath();
		// 対象VO取得
		BaseVo vo = mospParams.getVo();
		// ID(VOのName)、NAME、VOを設定
		topicPath.setId(vo.getClassName());
		topicPath.setName(mospParams.getName(vo.getClassName()));
		topicPath.setVo(vo);
		// メニューキー設定(メニューからの遷移時以外はnull)
		topicPath.setMenuKey(getTransferredMenuKey());
		// コマンド設定
		if (topicPathCommand != null && topicPathCommand.isEmpty() == false) {
			// パンくずリスト用コマンドを設定
			topicPath.setCommand(topicPathCommand);
		} else {
			// リクエストされたコマンドを設定
			topicPath.setCommand(mospParams.getCommand());
		}
		return topicPath;
	}
	
	/**
	 * リストから指定インデックスより後の要素を除去する。<br>
	 * @param list  削除対象リスト
	 * @param index インデックス
	 */
	protected void removeAfterIndex(List<?> list, int index) {
		for (int i = list.size() - 1; i > index; i--) {
			list.remove(i);
		}
	}
	
	/**
	 * MosPプラットフォーム用BeanHandlerを取得する。<br>
	 * @return MosPプラットフォーム用BeanHandler
	 * @throws MospException インスタンスの取得に失敗した場合
	 */
	protected PlatformBeanHandlerInterface platform() throws MospException {
		// MosPプラットフォーム用BeanHandler存在確認
		if (platform != null) {
			return platform;
		}
		// MosPプラットフォーム用BeanHandler取得
		platform = (PlatformBeanHandlerInterface)createHandler(PlatformBeanHandlerInterface.class);
		return platform;
	}
	
	/**
	 * MosPプラットフォーム参照用BeanHandlerを取得する。<br>
	 * @return MosPプラットフォーム参照用BeanHandler
	 * @throws MospException インスタンスの取得に失敗した場合
	 */
	protected ReferenceBeanHandlerInterface reference() throws MospException {
		// MosPプラットフォーム参照用BeanHandler存在確認
		if (platformReference != null) {
			return platformReference;
		}
		// MosPプラットフォーム参照用BeanHandler取得
		platformReference = (ReferenceBeanHandlerInterface)createHandler(ReferenceBeanHandlerInterface.class);
		return platformReference;
	}
	
	/**
	 * ページ繰り設定。<br>
	 * @param command ページ繰りコマンド
	 * @param dataPerPage 1ページ当たりの表示件数
	 */
	protected void setPageInfo(String command, int dataPerPage) {
		// VO準備
		PlatformVo vo = (PlatformVo)mospParams.getVo();
		vo.setPageCommand(command);
		vo.setDataPerPage(dataPerPage);
		vo.setSelectIndex(String.valueOf(1));
	}
	
	/**
	 * リスト長(一画面表示件数)取得。<br>
	 * @return リスト長
	 */
	protected int getListLength() {
		// 設定ファイルからリスト長を取得
		return mospParams.getApplicationProperty(APP_LIST_LENGTH, 0);
	}
	
	/**
	 * リストをソートし、1ページ目のリストを取得する。<br>
	 * @param sortKey ソートキー(比較クラス名)
	 * @return ソート後1ページ目分のリスト
	 * @throws MospException 比較クラスのインスタンス生成に失敗した場合
	 */
	public List<? extends BaseDtoInterface> sortList(String sortKey) throws MospException {
		// VO取得
		PlatformVo vo = (PlatformVo)mospParams.getVo();
		// ソートキー確認
		if (vo.getComparatorName().equals(sortKey)) {
			// 昇順降順フラグ設定
			if (vo.isAscending()) {
				vo.setAscending(false);
			} else {
				vo.setAscending(true);
			}
		} else {
			vo.setAscending(false);
		}
		// ソートキー確認
		if (sortKey != null) {
			// ソートキーをVOに設定
			vo.setComparatorName(sortKey);
		}
		// 比較クラスインスタンス取得
		Comparator<Object> comp = InstanceFactory.loadComparator(vo.getComparatorName());
		// ソート
		if (vo.isAscending()) {
			Collections.sort(vo.getList(), Collections.reverseOrder(comp));
		} else {
			Collections.sort(vo.getList(), comp);
		}
		// 1ページ目のリストを取得
		return getFirstPageList();
	}
	
	/**
	 * 1ページ目のリストを取得する。<br>
	 * @return 1ページ目分のリスト
	 */
	protected List<? extends BaseDtoInterface> getFirstPageList() {
		// VO取得
		PlatformVo vo = (PlatformVo)mospParams.getVo();
		// 選択ページ番号設定
		vo.setSelectIndex(String.valueOf(1));
		// リスト取得
		return pageList();
	}
	
	/**
	 * 選択ページのリストを取得する。<br>
	 * @return 選択ページ分のリスト
	 */
	protected List<? extends BaseDtoInterface> pageList() {
		// VO取得
		PlatformVo vo = (PlatformVo)mospParams.getVo();
		int offset = (Integer.parseInt(vo.getSelectIndex()) - 1) * vo.getDataPerPage();
		List<BaseDtoInterface> list = new ArrayList<BaseDtoInterface>();
		for (int i = offset; i < (offset + vo.getDataPerPage() < vo.getList().size() ? offset + vo.getDataPerPage()
				: vo.getList().size()); i++) {
			list.add(vo.getList().get(i));
		}
		return list;
	}
	
	/**
	 * 操作範囲の確認を行う。<br>
	 * 確認対象個人IDが参照範囲に含まれない場合、パンくずリストの最初の画面に遷移する。<br>
	 * JavaScriptで個人を指定してリクエストが投げられる場合、
	 * このメソッドを実行して操作権限があるかどうかを確認する必要がある。<br>
	 * @param personalId    確認対象個人ID
	 * @param targetDate    確認対象日
	 * @param operationType 操作範囲
	 * @throws MospException 確認対象個人IDが参照範囲に含まれない場合
	 */
	protected void checkRange(String personalId, Date targetDate, String operationType) throws MospException {
		// 範囲及び個人ID(社員コードに変換)を指定して検索
		HumanSearchBeanInterface bean = reference().humanSearch();
		bean.setTargetDate(targetDate);
		bean.setEmployeeCode(reference().human().getEmployeeCode(personalId, targetDate));
		bean.setEmployeeCodeType(PlatformConst.SEARCH_EXACT_MATCH);
		bean.setOperationType(operationType);
		List<HumanDtoInterface> list = bean.search();
		// 検索結果確認
		if (list.size() == 1) {
			// 操作可能
			return;
		}
		// パンくずリストからコマンドを取得
		mospParams.setNextCommand(mospParams.getTopicPathList().get(0).getCommand());
		// メッセージ設定
		mospParams.addErrorMessage(ExceptionConst.EX_NO_AUTHORITY, null);
		// 例外発行
		throw new MospException(ExceptionConst.EX_NO_AUTHORITY);
	}
	
	/**
	 * コマンドが不正な場合のMosP例外を発行する。<br>
	 * @throws MospException コマンドが不正な場合
	 */
	protected void throwInvalidCommandException() throws MospException {
		String[] rep = { getClass().getName(), mospParams.getCommand() };
		mospParams.setErrorViewUrl();
		throw new MospException(ExceptionConst.EX_INVALID_COMMAND, rep);
	}
	
	/**
	 * システム日付を取得する。<br>
	 * @return システム日付
	 */
	protected Date getSystemDate() {
		return DateUtility.getSystemDate();
	}
	
	/**
	 * 日付オブジェクトを取得する(String→Date)。
	 * @param date 日付文字列(yyyy/MM/dd)
	 * @return 日付
	 */
	protected Date getDate(String date) {
		return DateUtility.getDate(date);
	}
	
	/**
	 * 日付文字列を取得する(Date→String)。
	 * @param date 対象日付オブジェクト
	 * @return 日付文字列(yyyy/MM/dd)
	 */
	protected String getStringDate(Date date) {
		return DateUtility.getStringDate(date);
	}
	
	/**
	 * 日付文字列を取得する(Date→String)。
	 * @param date 対象日付オブジェクト
	 * @return 日付文字列(yyyy/MM/dd(E))
	 */
	protected String getStringDateAndDay(Date date) {
		return DateUtility.getStringDateAndDay(date);
	}
	
	/**
	 * 日付文字列を取得する(Date→String)。
	 * @param date 対象日付オブジェクト
	 * @return 日付文字列(hh:mm)
	 */
	protected String getStringTime(Date date) {
		return DateUtility.getStringTime(date);
	}
	
	/**
	 * 年を取得する。<br>
	 * @param date 日付
	 * @return 年
	 */
	protected String getStringYear(Date date) {
		return DateUtility.getStringYear(date);
	}
	
	/**
	 * 月を取得する。<br>
	 * @param date 日付
	 * @return 月
	 */
	protected String getStringMonth(Date date) {
		return DateUtility.getStringMonth(date);
	}
	
	/**
	 * 日を取得する。<br>
	 * @param date 日付
	 * @return 日
	 */
	protected String getStringDay(Date date) {
		return DateUtility.getStringDay(date);
	}
	
	/**
	 * 時間を取得する。<br>
	 * @param date 日付
	 * @return 時間
	 */
	protected String getStringHour(Date date) {
		return DateUtility.getStringHour(date);
	}
	
	/**
	 * 分を取得する。<br>
	 * @param date 日付
	 * @return 分
	 */
	protected String getStringMinute(Date date) {
		return DateUtility.getStringMinute(date);
	}
	
	/**
	 * 日付オブジェクトを取得する(String→Date)。<br>
	 * 日付オブジェクトの取得に失敗した場合は、
	 * {@link #mospParams}にエラーメッセージを追加する。<br>
	 * @param year 年
	 * @param month 月
	 * @param day 日
	 * @return 日付
	 */
	protected Date getDate(String year, String month, String day) {
		try {
			return DateUtility.getDate(year, month, day);
		} catch (Throwable e) {
			mospParams.addErrorMessage(PlatformMessageConst.MSG_DATE_CHECK, null);
			return null;
		}
	}
	
	/**
	 * 日付オブジェクトを取得する(String→Date)。<br>
	 * 日は、1とする。<br>
	 * 日付オブジェクトの取得に失敗した場合は、
	 * {@link #mospParams}にエラーメッセージを追加する。<br>
	 * @param year 年
	 * @param month 月
	 * @return 日付
	 */
	protected Date getYearMonth(String year, String month) {
		try {
			return DateUtility.getDate(year, month, String.valueOf(1));
		} catch (Throwable e) {
			mospParams.addErrorMessage(PlatformMessageConst.MSG_DATE_CHECK, null);
			return null;
		}
	}
	
	/**
	 * 日付オブジェクト(時間)を取得する。<br>
	 * 時、分、日がいずれも空白の場合、nullを返す。<br>
	 * 引数にnullが含まれる場合は、例外を発行する。<br>
	 * @param hour   時間
	 * @param minute 分
	 * @return 日付オブジェクト
	 */
	protected Date getTime(String hour, String minute) {
		try {
			return DateUtility.getTime(hour, minute);
		} catch (Throwable e) {
			mospParams.addErrorMessage(PlatformMessageConst.MSG_TIME_CHECK, null);
			return null;
		}
	}
	
	/**
	 * 数値を取得する(String→long)。<br>
	 * 数値の取得に失敗した場合は、{@link #mospParams}にエラーメッセージを追加する。<br>
	 * @param value 値(String)
	 * @return 値(long)
	 */
	protected long getLong(String value) {
		try {
			return Long.parseLong(value);
		} catch (Throwable e) {
			mospParams.addErrorMessage(PlatformMessageConst.MSG_NUMBER_CHECK, null);
			return 0;
		}
	}
	
	/**
	 * 数値を取得する(String→int)。<br>
	 * 数値の取得に失敗した場合は、{@link #mospParams}にエラーメッセージを追加する。<br>
	 * @param value 値(String)
	 * @return 値(int)
	 */
	protected int getInt(String value) {
		try {
			return Integer.parseInt(value);
		} catch (Throwable e) {
			mospParams.addErrorMessage(PlatformMessageConst.MSG_NUMBER_CHECK, null);
			return 0;
		}
	}
	
	/**
	 * コード配列を取得する。<br>
	 * @param codeKey コードキー
	 * @param needBlank 空白行要否(true：空白行要、false：空白行不要)
	 * @return コード配列
	 */
	protected String[][] getCodeArray(String codeKey, boolean needBlank) {
		// コード配列を取得
		return mospParams.getProperties().getCodeArray(codeKey, needBlank);
	}
	
	/**
	 * コード名称を取得する。<br>
	 * @param code    コード
	 * @param codeKey コードキー
	 * @return コード名称
	 */
	protected String getCodeName(String code, String codeKey) {
		// コード名称を取得
		return MospUtility.getCodeName(code, getCodeArray(codeKey, false));
	}
	
	/**
	 * コード名称を取得する。<br>
	 * @param code    コード
	 * @param codeKey コードキー
	 * @return コード名称
	 */
	protected String getCodeName(int code, String codeKey) {
		// コード名称を取得
		return getCodeName(String.valueOf(code), codeKey);
	}
	
	/**
	 * 無効フラグ名称を取得する。<br>
	 * @param inactivateFlag 無効フラグ
	 * @return 無効フラグ名称
	 */
	protected String getInactivateFlagName(int inactivateFlag) {
		return getCodeName(inactivateFlag, PlatformConst.CODE_KEY_INACTIVATE_FLAG);
	}
	
	/**
	 * 対象DTOを登録したユーザのユーザ名を取得する。<br>
	 * @param dto 対象DTO
	 * @return 登録ユーザ名
	 * @throws MospException ユーザ情報の取得に失敗した場合
	 */
	protected String getInsertUserName(BaseDtoInterface dto) throws MospException {
		// ユーザ情報取得及び確認
		UserMasterDtoInterface userDto = reference().user().getUserInfo(dto.getInsertUser(), dto.getInsertDate());
		if (userDto == null) {
			return "";
		}
		// 人事情報取得及び確認
		HumanDtoInterface humanDto = reference().human().getHumanInfo(userDto.getPersonalId(), dto.getInsertDate());
		if (humanDto == null) {
			return "";
		}
		return MospUtility.getHumansName(humanDto.getFirstName(), humanDto.getLastName());
	}
	
	/**
	 * 有効日編集中のプルダウンを取得する。<br>
	 * @return 有効日編集中プルダウン
	 */
	protected String[][] getInputActivateDatePulldown() {
		String[][] aryPulldown = { { "", mospParams.getName("InputActiveDate") } };
		return aryPulldown;
	}
	
	/**
	 * 開始日編集中のプルダウンを取得する。<br>
	 * @return 開始日編集中プルダウン
	 */
	protected String[][] getInputStartDatePulldown() {
		String[][] aryPulldown = { { "", mospParams.getName("InputStartDate") } };
		return aryPulldown;
	}
	
	/**
	 * 期間編集中のプルダウンを取得する。<br>
	 * @return 開始日編集中プルダウン
	 */
	protected String[][] getInputTermPulldown() {
		String[][] aryPulldown = { { "", mospParams.getName("InputTerm") } };
		return aryPulldown;
	}
	
	/**
	 * コード検索中のプルダウンを取得する。<br>
	 * @return コード検索中プルダウン
	 */
	protected String[][] getSearchCodePulldown() {
		String[][] aryPulldown = { { "", mospParams.getName("SearchCode") } };
		return aryPulldown;
	}
	
	/**
	 * 文字列配列からレコード識別ID配列を作成する。<br>
	 * 但し、空文字列は除く。<br>
	 * @param aryString 文字列配列
	 * @return レコード識別ID配列
	 */
	protected long[] getIdArray(String[] aryString) {
		// 文字列配列確認
		if (aryString == null) {
			return new long[0];
		}
		// リスト準備
		List<String> list = new ArrayList<String>();
		// レコード識別IDリスト作成
		for (String id : aryString) {
			// ID確認
			if (id == null || id.isEmpty()) {
				continue;
			}
			// レコード識別ID確認
			if (getLong(id) == 0) {
				continue;
			}
			// リストに追加
			list.add(id);
		}
		// レコード識別ID配列作成
		long[] aryLong = new long[list.size()];
		for (int i = 0; i < list.size(); i++) {
			aryLong[i] = getLong(list.get(i));
		}
		return aryLong;
	}
	
	/**
	 * 文字列配列からインデックス配列を作成する。<br>
	 * @param aryString 文字列配列
	 * @return インデックス配列
	 */
	protected int[] getIndexArray(String[] aryString) {
		// 文字列配列確認
		if (aryString == null) {
			return new int[0];
		}
		// インデックス配列作成
		int[] aryInt = new int[aryString.length];
		for (int i = 0; i < aryString.length; i++) {
			aryInt[i] = getInt(aryString[i]);
		}
		return aryInt;
	}
	
	/**
	 * インデックス配列内に対象インデックスが含まれるかを確認する。<br>
	 * @param target   対象インデックス
	 * @param aryIndex インデックス配列
	 * @return 確認結果(true：含まれる、false：含まれない)
	 */
	protected boolean isIndexed(int target, int[] aryIndex) {
		for (int idx : aryIndex) {
			if (target == idx) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 文字列配列からレコード識別ID配列を作成する。<br>
	 * @param aryIndex 対象index配列
	 * @param aryId    レコード識別ID配列(String)
	 * @return レコード識別ID配列
	 */
	protected long[] getIdArray(int[] aryIndex, String[] aryId) {
		// 文字列配列確認
		if (aryIndex == null) {
			return new long[0];
		}
		// 配列準備
		String[] idArray = new String[aryIndex.length];
		// 値設定
		for (int i = 0; i < aryIndex.length; i++) {
			idArray[i] = aryId[aryIndex[i]];
		}
		return getIdArray(idArray);
	}
	
	/**
	 * 選択データの存在確認を行う。<br>
	 * 選択データが存在しなかった場合は、ポータル画面に戻される。<br>
	 * 一覧からデータを選択し画面遷移する際等に用いる。<br>
	 * @param obj 確認対象オブジェクト
	 * @throws MospException 確認対象オブジェクトがNULLである場合
	 */
	protected void checkSelectedDataExist(Object obj) throws MospException {
		// 対象オブジェクト確認
		if (obj != null) {
			return;
		}
		// エラーメッセージ設定
		mospParams.addErrorMessage(PlatformMessageConst.MSG_NO_ITEM, mospParams.getName("Information"), null);
		// 連続実行コマンド設定(ポータル画面へ)
		mospParams.setNextCommand(mospParams.getApplicationProperty(APP_COMMAND_PORTAL));
		// 例外発行
		throw new MospException(ExceptionConst.EX_NO_DATA);
	}
	
	/**
	 * 画面表示時にスクロールさせるHTML要素のIDを設定する。<br>
	 * 画面表示時に、JavaScriptの変数として宣言される。<br>
	 * @param target 画面表示時にスクロールさせるHTML要素のID
	 */
	protected void setJsScrollTo(String target) {
		// MosP汎用パラメータに設定
		mospParams.addGeneralParam(MGP_JS_SCROLL_TO, target);
	}
	
	/**
	 * 有効日モードを設定する。<br>
	 * @param modeActivateDate 有効日モード
	 */
	protected void setModeActivateDate(String modeActivateDate) {
		// VO取得
		PlatformVo vo = (PlatformVo)mospParams.getVo();
		// 有効日モード設定
		vo.setModeActivateDate(modeActivateDate);
	}
	
	/**
	 * ドキュメントルートを取得する。<br>
	 * @return ドキュメントルート
	 */
	protected String getDocBase() {
		return mospParams.getApplicationProperty(MospConst.APP_DOCBASE);
	}
	
	/**
	 * リクエストされた譲渡インデックスを取得する。
	 * @return 譲渡インデックス
	 */
	protected int getTransferredIndex() {
		return getInt(mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_INDEX));
	}
	
	/**
	 * 対象個人IDを設定する。<br>
	 * 画面遷移用のパラメータをMosP処理情報に設定する。<br>
	 * @param targetPersonalId 対象個人ID
	 */
	protected void setTargetPersonalId(String targetPersonalId) {
		mospParams.addGeneralParam(PlatformConst.PRM_TARGET_PERSONAL_ID, targetPersonalId);
	}
	
	/**
	 * 対象個人IDを取得する。<br>
	 * 画面遷移用のパラメータをMosP処理情報から取得する。<br>
	 * @return 対象個人ID
	 */
	protected String getTargetPersonalId() {
		return (String)mospParams.getGeneralParam(PlatformConst.PRM_TARGET_PERSONAL_ID);
	}
	
	/**
	 * 対象日を設定する。<br>
	 * 画面遷移用のパラメータをMosP処理情報に設定する。<br>
	 * @param targetDate 対象日
	 */
	protected void setTargetDate(Date targetDate) {
		mospParams.addGeneralParam(PlatformConst.PRM_TARGET_DATE, targetDate);
	}
	
	/**
	 * 対象日を取得する。<br>
	 * 画面遷移用のパラメータをMosP処理情報から取得する。<br>
	 * @return 対象日
	 */
	protected Date getTargetDate() {
		return (Date)mospParams.getGeneralParam(PlatformConst.PRM_TARGET_DATE);
	}
	
	/**
	 * リクエストされたメニューキーを取得する。<br>
	 * メニューキーは、メニューをクリックした時のみリクエストされる。<br>
	 * 範囲設定、パンくずリセット等に利用される。<br>
	 * @return メニューキー
	 */
	protected String getTransferredMenuKey() {
		return mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_MENU_KEY);
	}
	
	/**
	 * リクエストされた譲渡汎用コードを取得する。
	 * @return 譲渡汎用コード
	 */
	protected String getTransferredCode() {
		return mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_CODE);
	}
	
	/**
	* リクエストされた譲渡ワークフロー番号を取得する。
	* @return 譲渡ワークフロー番号
	*/
	protected String getTransferredWorkflow() {
		return mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_WORKFLOW);
	}
	
	/**
	* リクエストされた譲渡レコード識別IDを取得する。
	* @return 譲渡レコード識別ID
	*/
	protected String getTransferredRecordId() {
		return mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_RECORD_ID);
	}
	
	/**
	 * リクエストされた譲渡有効日を取得する。
	 * @return 譲渡有効日
	 */
	protected String getTransferredActivateDate() {
		return mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_ACTIVATE_DATE);
	}
	
	/**
	 * リクエストされた譲渡汎用区分を取得する。
	 * @return 譲渡汎用区分
	 */
	protected String getTransferredType() {
		return mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_TYPE);
	}
	
	/**
	 * リクエストされた譲渡汎用コマンドを取得する。<br>
	 * 遷移先から戻るためのコマンド等を受け取る場合に用いる。<br>
	 * @return 譲渡汎用コマンド
	 */
	protected String getTransferredCommand() {
		return mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_COMMAND);
	}
	
	/**
	 * リクエストされた譲渡ソートキーを取得する。
	 * @return 譲渡ソートキー
	 */
	protected String getTransferredSortKey() {
		return mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_SORT_KEY);
	}
	
	/**
	 * リクエストされた譲渡Actionクラス名を取得する。
	 * @return 譲渡Actionクラス名
	 */
	protected String getTransferredAction() {
		return mospParams.getRequestParam(PlatformConst.PRM_TRANSFERRED_ACTION);
	}
	
	/**
	 * 検索結果無しメッセージの設定。
	 */
	protected void addNoSearchResultMessage() {
		mospParams.addMessage(PlatformMessageConst.MSG_NO_DATA, null);
	}
	
	/**
	 * 登録成功メッセージの設定。
	 */
	protected void addInsertMessage() {
		String[] aryMeassage = { mospParams.getName("Insert") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_SUCCEED, aryMeassage);
	}
	
	/**
	 * 更新成功メッセージの設定。
	 */
	protected void addUpdateMessage() {
		String[] aryMeassage = { mospParams.getName("Update") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_SUCCEED, aryMeassage);
	}
	
	/**
	 * 新規登録成功メッセージの設定。
	 */
	protected void addInsertNewMessage() {
		String[] aryMeassage = { mospParams.getName("New") + mospParams.getName("Insert") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_SUCCEED, aryMeassage);
	}
	
	/**
	 * 履歴追加成功メッセージの設定。
	 */
	protected void addInsertHistoryMessage() {
		String[] aryMeassage = { mospParams.getName("History") + mospParams.getName("Add") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_SUCCEED, aryMeassage);
	}
	
	/**
	 * 履歴編集成功メッセージの設定。
	 */
	protected void addUpdateHistoryMessage() {
		String[] aryMeassage = { mospParams.getName("History") + mospParams.getName("Edit") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_SUCCEED, aryMeassage);
	}
	
	/**
	 * 削除成功メッセージの設定。
	 */
	protected void addDeleteMessage() {
		String[] aryMeassage = { mospParams.getName("Delete") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_SUCCEED, aryMeassage);
	}
	
	/**
	 * 履歴削除成功メッセージの設定。
	 * @param count 削除履歴件数
	 */
	protected void addDeleteHistoryMessage(int count) {
		String[] aryMeassage = { String.valueOf(count) };
		mospParams.addMessage(PlatformMessageConst.MSG_DELETE_HISTORY, aryMeassage);
	}
	
	/**
	 * インポート成功メッセージの設定。
	 * @param count 登録件数
	 */
	protected void addImportMessage(int count) {
		String[] aryMeassage = { String.valueOf(count) };
		mospParams.addMessage(PlatformMessageConst.MSG_IMPORT_SUCCEED, aryMeassage);
	}
	
	/**
	 * 登録失敗メッセージの設定。
	 */
	protected void addInsertFailedMessage() {
		String[] aryMeassage = { mospParams.getName("Insert") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_FAILED, aryMeassage);
	}
	
	/**
	 * 更新失敗メッセージの設定。
	 */
	protected void addUpdateFailedMessage() {
		String[] aryMeassage = { mospParams.getName("Update") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_FAILED, aryMeassage);
	}
	
	/**
	 * 一括更新失敗メッセージの設定。
	 */
	protected void addBatchUpdateFailedMessage() {
		String[] aryMeassage = { mospParams.getName("Bulk") + mospParams.getName("Update") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_FAILED, aryMeassage);
	}
	
	/**
	 * 削除失敗メッセージの設定。
	 */
	protected void addDeleteFailedMessage() {
		String[] aryMeassage = { mospParams.getName("Delete") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_FAILED, aryMeassage);
	}
	
	/**
	 * 履歴削除失敗メッセージの設定。
	 */
	protected void addDeleteHistoryFailedMessage() {
		String[] aryMeassage = { mospParams.getName("History") + mospParams.getName("Delete") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_FAILED, aryMeassage);
	}
	
	/**
	 * 決定(有効日等)失敗メッセージの設定。
	 */
	protected void addFixFailedMessage() {
		String[] aryMeassage = { mospParams.getName("Decision") };
		mospParams.addMessage(PlatformMessageConst.MSG_PROCESS_FAILED, aryMeassage);
	}
	
	/**
	 * 決定した日付時点で入社日を過ぎていない社員の社員コードが入力されている場合の設定。
	 * @param employeesCode 社員コード
	 * @param targetDate 対象日
	 */
	protected void addNotJoinedEmployeesErrorMessage(Date targetDate, String employeesCode) {
		mospParams.addErrorMessage(PlatformMessageConst.MSG_NOT_JOINED_EMPLOYEES,
				DateUtility.getStringDate(targetDate), employeesCode);
	}
	
	/**
	 * 決定した日付時点で退職日を過ぎている社員の社員はコードが入力されている場合の設定。
	 * @param employeesCode 社員コード
	 * @param targetDate 対象日
	 */
	protected void addNotRetirementEmployeesErrorMessage(Date targetDate, String employeesCode) {
		mospParams.addErrorMessage(PlatformMessageConst.MSG_NOT_RETIREMENT_EMPLOYEES, DateUtility
			.getStringDate(targetDate), employeesCode);
	}
}
