/*
 * 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.time.bean.impl;

import java.sql.Connection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;

import jp.mosp.framework.base.MospException;
import jp.mosp.framework.base.MospParams;
import jp.mosp.framework.utils.DateUtility;
import jp.mosp.platform.bean.human.EntranceReferenceBeanInterface;
import jp.mosp.platform.bean.human.RetirementReferenceBeanInterface;
import jp.mosp.platform.bean.workflow.WorkflowCommentReferenceBeanInterface;
import jp.mosp.platform.bean.workflow.WorkflowCommentRegistBeanInterface;
import jp.mosp.platform.bean.workflow.WorkflowReferenceBeanInterface;
import jp.mosp.platform.bean.workflow.WorkflowRegistBeanInterface;
import jp.mosp.platform.constant.PlatformConst;
import jp.mosp.platform.constant.PlatformMessageConst;
import jp.mosp.platform.dto.workflow.WorkflowCommentDtoInterface;
import jp.mosp.platform.dto.workflow.WorkflowDtoInterface;
import jp.mosp.time.base.TimeApplicationBean;
import jp.mosp.time.base.TimeBean;
import jp.mosp.time.bean.AttendanceCorrectionRegistBeanInterface;
import jp.mosp.time.bean.AttendanceReferenceBeanInterface;
import jp.mosp.time.bean.AttendanceRegistBeanInterface;
import jp.mosp.time.bean.CutoffUtilBeanInterface;
import jp.mosp.time.bean.DifferenceRequestReferenceBeanInterface;
import jp.mosp.time.bean.GoOutRegistBeanInterface;
import jp.mosp.time.bean.HolidayRequestReferenceBeanInterface;
import jp.mosp.time.bean.RequestUtilBeanInterface;
import jp.mosp.time.bean.RestRegistBeanInterface;
import jp.mosp.time.constant.TimeConst;
import jp.mosp.time.constant.TimeMessageConst;
import jp.mosp.time.dao.settings.AttendanceDaoInterface;
import jp.mosp.time.dao.settings.HolidayRequestDaoInterface;
import jp.mosp.time.dao.settings.OvertimeRequestDaoInterface;
import jp.mosp.time.dao.settings.SubHolidayRequestDaoInterface;
import jp.mosp.time.dao.settings.SubstituteDaoInterface;
import jp.mosp.time.dao.settings.WorkOnHolidayRequestDaoInterface;
import jp.mosp.time.dao.settings.WorkTypeItemDaoInterface;
import jp.mosp.time.dto.settings.AttendanceDtoInterface;
import jp.mosp.time.dto.settings.DifferenceRequestDtoInterface;
import jp.mosp.time.dto.settings.GoOutDtoInterface;
import jp.mosp.time.dto.settings.HolidayRequestDtoInterface;
import jp.mosp.time.dto.settings.OvertimeRequestDtoInterface;
import jp.mosp.time.dto.settings.RestDtoInterface;
import jp.mosp.time.dto.settings.SubHolidayRequestDtoInterface;
import jp.mosp.time.dto.settings.SubstituteDtoInterface;
import jp.mosp.time.dto.settings.TimeSettingDtoInterface;
import jp.mosp.time.dto.settings.WorkOnHolidayRequestDtoInterface;
import jp.mosp.time.dto.settings.WorkTypeItemDtoInterface;
import jp.mosp.time.dto.settings.impl.TmdAttendanceDto;

/**
 * 勤怠データ登録クラス。
 */
public class AttendanceRegistBean extends TimeApplicationBean implements AttendanceRegistBeanInterface {
	
	/**
	 * 勤怠データマスタDAOクラス。<br>
	 */
	private AttendanceDaoInterface					dao;
	/**
	 * 勤怠データ参照インターフェース。<br>
	 */
	private AttendanceReferenceBeanInterface		attendanceReference;
	
	/**
	 * 勤務形態項目DAOインターフェース。<br>
	 */
	protected WorkTypeItemDaoInterface				workTypeItemDao;
	
	/**
	 * 休暇申請参照インターフェース。<br>
	 */
	private HolidayRequestReferenceBeanInterface	holidayRequestReference;
	/**
	 * ワークフロー参照インターフェース。<br>
	 */
	protected WorkflowReferenceBeanInterface		workflowReference;
	/**
	 * 残業申請DAOインターフェース。<br>
	 */
	private OvertimeRequestDaoInterface				overtimeDao;
	/**
	 * 時差出勤申請参照インターフェース。<br>
	 */
	private DifferenceRequestReferenceBeanInterface	differenceReference;
	/**
	 * 休暇申請DAOインターフェース。<br>
	 */
	private HolidayRequestDaoInterface				holidayDao;
	/**
	 * 休日出勤申請DAOインターフェース。<br>
	 */
	protected WorkOnHolidayRequestDaoInterface		workOnHolidayRequestDao;
	/**
	 * 振替休日データDAOインターフェース。
	 */
	private SubstituteDaoInterface					substituteDao;
	/**
	 * 代休申請DAOインターフェース。
	 */
	private SubHolidayRequestDaoInterface			subHolidayDao;
	/**
	 * 人事入社情報参照インターフェース
	 */
	private EntranceReferenceBeanInterface			entranceReference;
	/**
	 * 人事退職情報参照クラス。<br>
	 */
	private RetirementReferenceBeanInterface		retirementReference;
	/**
	 * ワークフローコメント登録クラス。<br>
	 */
	private WorkflowCommentReferenceBeanInterface	workflowCommentReference;
	/**
	 * 勤怠データ修正情報登録インターフェース。<br>
	 */
	private AttendanceCorrectionRegistBeanInterface	attendanceCorrectionRegist;
	/**
	 * 勤怠データ休憩情報登録インターフェース。	<br>
	 */
	private RestRegistBeanInterface					restRegist;
	/**
	 * 勤怠データ外出情報登録インターフェース。	<br>
	 */
	private GoOutRegistBeanInterface				goOutRegist;
	/**
	 * ワークフロー登録インターフェース。<br>
	 */
	private WorkflowRegistBeanInterface				workflowRegist;
	/**
	 * ワークフローコメント登録インターフェース。<br>
	 */
	private WorkflowCommentRegistBeanInterface		workflowCommentRegist;
	/**
	 * 締日ユーティリティ。<br>
	 */
	private CutoffUtilBeanInterface					cutoffUtil;
	
	/**
	 * 申請ユーティリティ。
	 */
	protected RequestUtilBeanInterface				requestUtil;
	
	/**
	 * 休暇範囲(午前休かつ午後休)。
	 */
	protected int									CODE_HOLIDAY_RANGE_AM_PM	= 5;
	

	/**
	 * {@link TimeApplicationBean#TimeApplicationBean()}を実行する。<br>
	 */
	public AttendanceRegistBean() {
		super();
	}
	
	/**
	 * {@link TimeApplicationBean#TimeApplicationBean(MospParams, Connection)}を実行する。<br>
	 * @param mospParams MosPパラメータクラス
	 * @param connection DBコネクション
	 */
	public AttendanceRegistBean(MospParams mospParams, Connection connection) {
		super(mospParams, connection);
	}
	
	@Override
	public void initBean() throws MospException {
		super.initBean();
		dao = (AttendanceDaoInterface)createDao(AttendanceDaoInterface.class);
		attendanceReference = (AttendanceReferenceBeanInterface)createBean(AttendanceReferenceBeanInterface.class);
		workTypeItemDao = (WorkTypeItemDaoInterface)createDao(WorkTypeItemDaoInterface.class);
		holidayRequestReference = (HolidayRequestReferenceBeanInterface)createBean(HolidayRequestReferenceBeanInterface.class);
		workflowReference = (WorkflowReferenceBeanInterface)createBean(WorkflowReferenceBeanInterface.class);
		overtimeDao = (OvertimeRequestDaoInterface)createDao(OvertimeRequestDaoInterface.class);
		differenceReference = (DifferenceRequestReferenceBeanInterface)createBean(DifferenceRequestReferenceBeanInterface.class);
		holidayDao = (HolidayRequestDaoInterface)createDao(HolidayRequestDaoInterface.class);
		workOnHolidayRequestDao = (WorkOnHolidayRequestDaoInterface)createDao(WorkOnHolidayRequestDaoInterface.class);
		substituteDao = (SubstituteDaoInterface)createDao(SubstituteDaoInterface.class);
		subHolidayDao = (SubHolidayRequestDaoInterface)createDao(SubHolidayRequestDaoInterface.class);
		entranceReference = (EntranceReferenceBeanInterface)createBean(EntranceReferenceBeanInterface.class);
		retirementReference = (RetirementReferenceBeanInterface)createBean(RetirementReferenceBeanInterface.class);
		workflowCommentReference = (WorkflowCommentReferenceBeanInterface)createBean(WorkflowCommentReferenceBeanInterface.class);
		attendanceCorrectionRegist = (AttendanceCorrectionRegistBeanInterface)createBean(AttendanceCorrectionRegistBeanInterface.class);
		restRegist = (RestRegistBeanInterface)createBean(RestRegistBeanInterface.class);
		goOutRegist = (GoOutRegistBeanInterface)createBean(GoOutRegistBeanInterface.class);
		workflowRegist = (WorkflowRegistBeanInterface)createBean(WorkflowRegistBeanInterface.class);
		workflowCommentRegist = (WorkflowCommentRegistBeanInterface)createBean(WorkflowCommentRegistBeanInterface.class);
		cutoffUtil = (CutoffUtilBeanInterface)createBean(CutoffUtilBeanInterface.class);
		requestUtil = (RequestUtilBeanInterface)createBean(RequestUtilBeanInterface.class);
	}
	
	@Override
	public AttendanceDtoInterface getInitDto() {
		return new TmdAttendanceDto();
	}
	
	@Override
	public void regist(AttendanceDtoInterface dto) throws MospException {
		if (dao.findForKey(dto.getPersonalId(), dto.getWorkDate(), dto.getTimesWork()) == null) {
			// 新規登録
			insert(dto);
		} else {
			// 履歴追加
			add(dto);
		}
	}
	
	@Override
	public void insert(AttendanceDtoInterface dto) throws MospException {
		// DTOの妥当性確認
		validate(dto);
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// ロック対象テーブルの追加
		addTargetTable(dao.getTable(dao.getClass()), true);
		// ロック開始
		lockTables();
		// 新規登録情報の検証
		checkInsert(dto);
		if (mospParams.hasErrorMessage()) {
			// ロック解除
			unLockTable();
			return;
		}
		// レコード識別ID最大値をインクリメントしてDTOに設定
		dto.setTmdAttendanceId(findForMaxId(dao) + 1);
		// 登録処理
		dao.insert(dto);
		// ロック解除
		unLockTable();
	}
	
	@Override
	public void add(AttendanceDtoInterface dto) throws MospException {
		// DTOの妥当性確認
		validate(dto);
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// ロック対象テーブルの追加
		addTargetTable(dao.getTable(dao.getClass()), true);
		// ロック開始
		lockTables();
		// 履歴追加情報の検証
		checkAdd(dto);
		if (mospParams.hasErrorMessage()) {
			// ロック解除
			unLockTable();
			return;
		}
		// 論理削除
		logicalDelete(dao, dto.getTmdAttendanceId());
		// レコード識別ID最大値をインクリメントしてDTOに設定
		dto.setTmdAttendanceId(findForMaxId(dao) + 1);
		// 登録処理
		dao.insert(dto);
		// ロック解除
		unLockTable();
	}
	
	/**
	 * 新規登録時の確認処理を行う。<br>
	 * @param dto 対象DTO
	 * @throws MospException SQLの作成に失敗した場合、或いはSQL例外が発生した場合
	 */
	protected void checkInsert(AttendanceDtoInterface dto) throws MospException {
		// 対象レコードの有効日が重複していないかを確認
		checkDuplicateInsert(dao.findForHistory(dto.getPersonalId(), dto.getWorkDate(), dto.getTimesWork()));
	}
	
	/**
	 * 履歴追加時の確認処理を行う。<br>
	 * @param dto 対象DTO
	 * @throws MospException SQLの作成に失敗した場合、或いはSQL例外が発生した場合
	 */
	protected void checkAdd(AttendanceDtoInterface dto) throws MospException {
		// 対象レコード識別IDのデータが削除されていないかを確認
		checkExclusive(dao, dto.getTmdAttendanceId());
	}
	
	@Override
	public void validate(AttendanceDtoInterface dto) throws MospException {
		// 時刻の必須チェック
		checkTimeExist(dto);
		// 時刻妥当性チェック
		checkTimeValidity(dto);
		// 基本情報のチェック
		attendanceReference.chkBasicInfo(dto.getPersonalId(), dto.getWorkDate());
	}
	
	@Override
	public void checkDraft(AttendanceDtoInterface dto) throws MospException {
		checkTemporaryClosingFinal(dto);
		if (dto.getStartTime() != null || dto.getEndTime() != null) {
			// 勤怠設定情報の取得
			setTimeSettings(dto.getPersonalId(), dto.getWorkDate());
			if (mospParams.hasErrorMessage()) {
				return;
			}
			// 始業時刻チェック
			checkDraftStartTimeForWork(dto);
			// 終業時刻チェック
			checkDraftEndTimeForWork(dto);
		}
		// 休日出勤申請及び休暇申請チェック
		checkHolidayAndWorkOnHolidayRequest(dto);
	}
	
	@Override
	public void checkAppli(AttendanceDtoInterface dto) throws MospException {
		// 下書き同様の処理を行う。
		checkDraft(dto);
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 必須チェック
		checkRequired(dto);
		// 申請期間チェック
		checkPeriod(dto);
		// 遅刻の限度チェック
		checkLateTime(dto);
		// 早退の限度チェック
		checkLeaveEarlyTime(dto);
		// 残業のチェック
		checkOvertime(dto);
		// 申請チェック
		checkRequest(dto);
		// 勤怠の申請チェック
		checkAttendance(dto);
	}
	
	@Override
	public void checkApproval(AttendanceDtoInterface dto) throws MospException {
		// 申請時と同様の処理を行う
		checkAppli(dto);
		// 翌日の勤怠チェック
		checkTomorrowAttendance(dto);
	}
	
	@Override
	public void checkCancel(AttendanceDtoInterface dto) {
		// 現在処理無し。処理が必要になった場合追加される予定。
	}
	
	@Override
	public void checkPeriod(AttendanceDtoInterface dto) {
		if (dto.getWorkDate().after(DateUtility.addMonth(getSystemDate(), 1))) {
			addAttendancePeriodErrorMessage();
		}
	}
	
	@Override
	public void checkLateTime(AttendanceDtoInterface dto) throws MospException {
		// 勤怠設定情報の取得
		setTimeSettings(dto.getPersonalId(), dto.getWorkDate());
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 限度の超過チェック
		if (checkLateLimit(dto, timeSettingDto)) {
			// 超過していた場合、休暇申請の取得
			List<HolidayRequestDtoInterface> list = holidayRequestReference.getHolidayRequestList(dto.getPersonalId(),
					dto.getWorkDate());
			// 休暇申請チェック
			if (list != null && !list.isEmpty()) {
				// 午前休の申請チェック
				for (HolidayRequestDtoInterface holidayRequestDto : list) {
					if (holidayRequestDto.getHolidayRange() == TimeConst.CODE_HOLIDAY_RANGE_AM) {
						WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(holidayRequestDto
							.getWorkflow());
						// 下書の場合は参照しない
						if (workflowDto != null
								&& !workflowDto.getWorkflowStatus().equals(PlatformConst.CODE_STATUS_DRAFT)) {
							// 1件でも午前休があればエラーメッセージ無し
							return;
						}
					}
				}
			}
			// メッセージ設定
			mospParams.addErrorMessage(TimeMessageConst.MSG_TARGET_DATE_TARDINESS_LEAVE_EARLY_LIMIT_OVER, new String[]{
				getStringDate(dto.getWorkDate()), mospParams.getName("Tardiness"), mospParams.getName("Tardiness"),
				mospParams.getName("AmRest") });
		}
	}
	
	@Override
	public void checkLeaveEarlyTime(AttendanceDtoInterface dto) throws MospException {
		// 勤怠設定情報の取得
		setTimeSettings(dto.getPersonalId(), dto.getWorkDate());
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 限度の超過チェック
		if (checkLeaveEarlyLimit(dto, timeSettingDto)) {
			// 超過していた場合、休暇申請の取得
			List<HolidayRequestDtoInterface> list = holidayRequestReference.getHolidayRequestList(dto.getPersonalId(),
					dto.getWorkDate());
			// 休暇申請チェック
			if (list != null && !list.isEmpty()) {
				// 午後休の申請チェック
				for (HolidayRequestDtoInterface holidayRequestDto : list) {
					if (holidayRequestDto.getHolidayRange() == TimeConst.CODE_HOLIDAY_RANGE_PM) {
						WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(holidayRequestDto
							.getWorkflow());
						// 下書の場合は参照しない
						if (workflowDto != null
								&& !workflowDto.getWorkflowStatus().equals(PlatformConst.CODE_STATUS_DRAFT)) {
							// 1件でも午後休があればエラーメッセージ無し
							return;
						}
					}
				}
			}
			// メッセージ設定
			mospParams.addErrorMessage(TimeMessageConst.MSG_TARGET_DATE_TARDINESS_LEAVE_EARLY_LIMIT_OVER, new String[]{
				getStringDate(dto.getWorkDate()), mospParams.getName("LeaveEarly"), mospParams.getName("LeaveEarly"),
				mospParams.getName("PmRest") });
		}
	}
	
	/**
	 * 下書時の始業時刻のチェック。<br>
	 * @param dto 対象DTO
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	public void checkDraftStartTimeForWork(AttendanceDtoInterface dto) throws MospException {
		if (dto.getStartTime() == null) {
			// 始業時刻が入力されていない場合はチェックを行わない
			return;
		}
		String workDate = getStringDate(dto.getWorkDate());
		if (!dto.getStartTime().before(addDay(dto.getWorkDate(), 1))) {
			// 始業時刻が翌日の場合
			StringBuffer sb = new StringBuffer();
			sb.append(mospParams.getName("StartWork"));
			sb.append(mospParams.getName("Moment"));
			mospParams.addErrorMessage(TimeMessageConst.MSG_START_DAY_TIME_CHECK, new String[]{
				workDate,
				DateUtility.getStringTime(DateUtility
					.addHour(DateUtility.getDefaultTime(), TimeConst.TIME_DAY_ALL_HOUR), DateUtility.getDefaultTime()),
				sb.toString() });
		}
		if (!dto.getStartTime().before(getTime(timeSettingDto.getStartDayTime(), dto.getWorkDate()))) {
			// 始業時刻が一日の起算時刻より前でない場合
			return;
		}
		AttendanceDtoInterface yesterdayDto = attendanceReference.findForKey(dto.getPersonalId(), addDay(dto
			.getWorkDate(), -1), TimeBean.TIMES_WORK_DEFAULT);
		if (yesterdayDto == null || yesterdayDto.getEndTime() == null) {
			return;
		}
		if (dto.getStartTime().after(yesterdayDto.getEndTime())) {
			// 始業時刻が前日の終業時刻より後の場合
			return;
		}
		StringBuffer sb = new StringBuffer();
		sb.append(mospParams.getName("Ahead"));
		sb.append(mospParams.getName("Day"));
		sb.append(mospParams.getName("Kara"));
		mospParams.addErrorMessage(TimeMessageConst.MSG_START_TIME_CHECK,
				new String[]{
					workDate,
					sb.toString(),
					DateUtility.getStringTime(timeSettingDto.getStartDayTime()),
					DateUtility.getStringTime(DateUtility.addHour(timeSettingDto.getStartDayTime(),
							TimeConst.TIME_DAY_ALL_HOUR), DateUtility.getDefaultTime()) });
	}
	
	/**
	 * 下書時の終業時刻のチェック。<br>
	 * @param dto 対象DTO
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	public void checkDraftEndTimeForWork(AttendanceDtoInterface dto) throws MospException {
		if (dto.getEndTime() == null) {
			// 終業時刻が入力されていない場合はチェックを行わない
			return;
		}
		String workDate = getStringDate(dto.getWorkDate());
		Date tomorrowDate = addDay(dto.getWorkDate(), 1);
		Date afterTwentyFourHoursTime = getTime(timeSettingDto.getStartDayTime(), tomorrowDate);
		String afterTwentyFourHours = DateUtility.getStringTime(afterTwentyFourHoursTime, dto.getWorkDate());
		if (dto.getEndTime().after(afterTwentyFourHoursTime)) {
			// 終業時刻が一日の起算時刻の24時間後より後の場合
			StringBuffer sb = new StringBuffer();
			sb.append(mospParams.getName("EndWork"));
			sb.append(mospParams.getName("Moment"));
			mospParams.addErrorMessage(TimeMessageConst.MSG_START_DAY_TIME_CHECK, new String[]{ workDate,
				afterTwentyFourHours, sb.toString() });
		}
		if (afterTwentyFourHoursTime.equals(dto.getEndTime())) {
			// 終業時刻が一日の起算時刻の24時間後の場合
			return;
		}
		AttendanceDtoInterface tomorrowDto = attendanceReference.findForKey(dto.getPersonalId(), tomorrowDate,
				TimeBean.TIMES_WORK_DEFAULT);
		if (tomorrowDto == null || tomorrowDto.getStartTime() == null) {
			return;
		}
		if (dto.getEndTime().before(tomorrowDto.getStartTime())) {
			// 終業時刻が翌日の始業時刻より前の場合
			return;
		}
		StringBuffer sb = new StringBuffer();
		sb.append(mospParams.getName("NextDay"));
		sb.append(mospParams.getName("To"));
		mospParams.addErrorMessage(TimeMessageConst.MSG_START_TIME_CHECK, new String[]{ workDate, sb.toString(),
			DateUtility.getStringTime(timeSettingDto.getStartDayTime()), afterTwentyFourHours });
	}
	
	/**
	 * @param dto 勤怠データ
	 * @param timeSettingDto 勤怠設定
	 * @return 限度時間を超えた場合true それ以外false
	 */
	public boolean checkLateLimit(AttendanceDtoInterface dto, TimeSettingDtoInterface timeSettingDto) {
		int lateEarlyHalf = (DateUtility.getHour(timeSettingDto.getLateEarlyHalf()) * TimeConst.CODE_DEFINITION_HOUR)
				+ DateUtility.getMinute(timeSettingDto.getLateEarlyHalf());
		if (lateEarlyHalf < dto.getLateTime()) {
			return true;
		}
		return false;
	}
	
	/**
	 * @param dto 勤怠データ
	 * @param timeSettingDto 勤怠設定
	 * @return 限度時間を超えた場合true それ以外false
	 */
	public boolean checkLeaveEarlyLimit(AttendanceDtoInterface dto, TimeSettingDtoInterface timeSettingDto) {
		int lateEarlyHalf = (DateUtility.getHour(timeSettingDto.getLateEarlyHalf()) * TimeConst.CODE_DEFINITION_HOUR)
				+ DateUtility.getMinute(timeSettingDto.getLateEarlyHalf());
		if (lateEarlyHalf < dto.getLeaveEarlyTime()) {
			return true;
		}
		return false;
	}
	
	@Override
	public void checkOvertime(AttendanceDtoInterface dto) throws MospException {
		// 各種申請情報取得
		requestUtil.setRequests(dto.getPersonalId(), dto.getWorkDate());
		// 設定締日情報の取得
		setCutoffSettings(dto.getPersonalId(), dto.getWorkDate());
		if (mospParams.hasErrorMessage()) {
			return;
		}
		int noApproval = cutoffDto.getNoApproval();
		if (noApproval == 0 || noApproval == 1) {
			// 未承認仮締が有効又は無効(残業事後申請可)の場合
			return;
		}
		if (dto.getOvertimeAfter() == 0) {
			return;
		}
		// 振出・休出申請
		WorkOnHolidayRequestDtoInterface workOnHolidayRequestDto = requestUtil.getWorkOnHolidayDto(true);
		if (workOnHolidayRequestDto != null
				&& workOnHolidayRequestDto.getSubstitute() == TimeConst.CODE_WORK_ON_HOLIDAY_SUBSTITUTE_OFF) {
			// 振り替えない場合
			return;
		}
		// 残業申請
		List<OvertimeRequestDtoInterface> overtimeRequestList = requestUtil.getOverTimeList(true);
		for (OvertimeRequestDtoInterface overtimeRequestDto : overtimeRequestList) {
			if (overtimeRequestDto.getOvertimeType() == TimeConst.CODE_OVERTIME_WORK_AFTER) {
				// 勤務後残業申請が承認済の場合
				return;
			}
		}
		mospParams.addErrorMessage(TimeMessageConst.MSG_REQUEST_CHECK_11, new String[]{
			getStringDate(dto.getWorkDate()), mospParams.getName("OvertimeWork"), mospParams.getName("OvertimeWork") });
	}
	
	@Override
	public void checkRequest(AttendanceDtoInterface dto) throws MospException {
		String personalId = dto.getPersonalId();
		Date requestDate = dto.getWorkDate();
		String requestName = "";
		// 残業申請
		List<OvertimeRequestDtoInterface> overtimeList = overtimeDao.findForList(personalId, requestDate);
		for (OvertimeRequestDtoInterface requestDto : overtimeList) {
			WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(requestDto.getWorkflow());
			if (workflowDto == null) {
				continue;
			}
			if (PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())) {
				// 承認状況が取下の場合
				continue;
			}
			if (PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())) {
				// 承認状況が下書の場合
				continue;
			}
			if (!PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
				// 承認状況が承認済でない場合は、エラーメッセージの表示
				// 残業申請のメッセージ追加
				requestName = mospParams.getName("OvertimeWork") + mospParams.getName("Application");
				mospParams.addErrorMessage(TimeMessageConst.MSG_NOT_REQUEST_STATE_COMPLETE, getStringDate(requestDate),
						requestName);
			}
		}
		// 時差出勤申請
		DifferenceRequestDtoInterface differenceDto = differenceReference.findForKeyOnWorkflow(personalId, requestDate);
		if (differenceDto != null) {
			WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(differenceDto.getWorkflow());
			if (workflowDto != null) {
				if (!PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())
						&& !PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())
						&& !PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が取下でなく、下書でなく、承認済でない場合は、エラーメッセージの表示
					// 時差出勤申請のメッセージ追加
					requestName = mospParams.getName("TimeDifference") + mospParams.getName("GoingWork")
							+ mospParams.getName("Application");
					mospParams.addErrorMessage(TimeMessageConst.MSG_NOT_REQUEST_STATE_COMPLETE,
							getStringDate(requestDate), requestName);
				}
			}
		}
		// 休暇申請（半休）
		List<HolidayRequestDtoInterface> holidayList = holidayDao.findForList(personalId, requestDate);
		for (HolidayRequestDtoInterface requestDto : holidayList) {
			int holidayRange = requestDto.getHolidayRange();
			if (holidayRange == TimeConst.CODE_HOLIDAY_RANGE_AM || holidayRange == TimeConst.CODE_HOLIDAY_RANGE_PM) {
				// 休暇が午前休又は午後休の場合
				WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(requestDto.getWorkflow());
				if (workflowDto == null) {
					continue;
				}
				if (PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が取下の場合
					continue;
				}
				if (PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が下書の場合
					continue;
				}
				if (!PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が承認済でない場合は、エラーメッセージの表示
					// 休暇申請のメッセージ追加
					requestName = mospParams.getName("Vacation") + mospParams.getName("Application");
					mospParams.addErrorMessage(TimeMessageConst.MSG_NOT_REQUEST_STATE_COMPLETE,
							getStringDate(requestDate), requestName);
				}
			}
		}
		// 休日出勤申請に伴う振替申請（半休）
		List<SubstituteDtoInterface> substituteList = substituteDao.findForList(personalId, requestDate);
		for (SubstituteDtoInterface substituteDto : substituteList) {
			int range = substituteDto.getSubstituteRange();
			if (range == TimeConst.CODE_HOLIDAY_RANGE_AM || range == TimeConst.CODE_HOLIDAY_RANGE_PM) {
				// 振替日が午前休又は午後休の場合
				WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(substituteDto.getWorkflow());
				if (workflowDto == null) {
					continue;
				}
				if (PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が取下の場合
					continue;
				}
				if (PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が下書の場合
					continue;
				}
				if (!PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が承認済でない場合は、エラーメッセージの表示
					// 休日出勤申請のメッセージ追加
					requestName = mospParams.getName("Holiday") + mospParams.getName("GoingWork")
							+ mospParams.getName("Application");
					mospParams.addErrorMessage(TimeMessageConst.MSG_NOT_REQUEST_STATE_COMPLETE,
							getStringDate(requestDate), requestName);
				}
			}
		}
		// 代休申請（半休）
		List<SubHolidayRequestDtoInterface> subHolidayList = subHolidayDao.findForList(personalId, requestDate);
		for (SubHolidayRequestDtoInterface requestDto : subHolidayList) {
			int holidayRange = requestDto.getHolidayRange();
			if (holidayRange == TimeConst.CODE_HOLIDAY_RANGE_AM || holidayRange == TimeConst.CODE_HOLIDAY_RANGE_PM) {
				// 代休が午前休又は午後休の場合
				WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(requestDto.getWorkflow());
				if (workflowDto == null) {
					continue;
				}
				if (PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が取下の場合
					continue;
				}
				if (PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が下書の場合
					continue;
				}
				if (!PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
					// 承認状況が承認済でない場合は、エラーメッセージの表示
					// 代休申請のメッセージ追加
					requestName = mospParams.getName("CompensatoryHoliday") + mospParams.getName("Application");
					mospParams.addErrorMessage(TimeMessageConst.MSG_NOT_REQUEST_STATE_COMPLETE,
							getStringDate(requestDate), requestName);
				}
			}
		}
	}
	
	@Override
	public void checkHolidayAndWorkOnHolidayRequest(AttendanceDtoInterface dto) throws MospException {
		// 振出・休出申請
		boolean workOnHoliday = false;
		// 休日出勤申請情報を取得
		WorkOnHolidayRequestDtoInterface workOnHolidayRequestDto = workOnHolidayRequestDao.findForKeyOnWorkflow(dto
			.getPersonalId(), dto.getWorkDate());
		if (workOnHolidayRequestDto != null) {
			// 最新のワークフロー取得
			WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(workOnHolidayRequestDto
				.getWorkflow());
			if (workflowDto != null) {
				if (PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
					// 承認完了である場合
					workOnHoliday = true;
				} else if (!PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())
						&& !PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())) {
					// 取下でなく且つ下書でない場合
					mospParams.addErrorMessage(TimeMessageConst.MSG_NOT_REQUEST_STATE_COMPLETE_2, getStringDate(dto
						.getWorkDate()), mospParams.getName("jp.mosp.time.input.vo.WorkOnHolidayRequestVo"));
					return;
				}
			}
		}
		// 振替休日
		boolean substituteAm = false;
		boolean substitutePm = false;
		if (!workOnHoliday) {
			// 振出・休出でない場合
			// 個人IDと振替日から振替休日データリストを取得
			List<SubstituteDtoInterface> substituteList = substituteDao.findForList(dto.getPersonalId(), dto
				.getWorkDate());
			// 振替休日データリスト毎に処理
			for (SubstituteDtoInterface substituteDto : substituteList) {
				// 最新のワークフロー取得
				WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(substituteDto.getWorkflow());
				if (workflowDto == null || PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())
						|| PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())) {
					// 取下又は下書の場合
					continue;
				}
				// 振替範囲
				int range = substituteDto.getSubstituteRange();
				if (range == TimeConst.CODE_HOLIDAY_RANGE_ALL) {
					// 全休の場合
					StringBuffer sb = new StringBuffer();
					sb.append(mospParams.getName("WorkManage"));
					sb.append(mospParams.getName("Application"));
					mospParams.addErrorMessage(TimeMessageConst.MSG_REQUEST_CHECK_10, new String[]{
						getStringDate(dto.getWorkDate()), mospParams.getName("ObservedHoliday"), sb.toString() });
					return;
				} else if (!substituteAm && range == TimeConst.CODE_HOLIDAY_RANGE_AM) {
					// 午前休の場合
					substituteAm = true;
				} else if (!substitutePm && range == TimeConst.CODE_HOLIDAY_RANGE_PM) {
					// 午後休の場合
					substitutePm = true;
				}
			}
		}
		// 休暇
		boolean holidayAm = false;
		boolean holidayPm = false;
		List<HolidayRequestDtoInterface> holidayList = holidayDao.findForList(dto.getPersonalId(), dto.getWorkDate());
		for (HolidayRequestDtoInterface requestDto : holidayList) {
			WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(requestDto.getWorkflow());
			if (workflowDto == null || PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())
					|| PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())) {
				// 取下又は下書の場合
				continue;
			}
			int range = requestDto.getHolidayRange();
			if (range == TimeConst.CODE_HOLIDAY_RANGE_ALL) {
				// 全休の場合
				StringBuffer sb = new StringBuffer();
				sb.append(mospParams.getName("WorkManage"));
				sb.append(mospParams.getName("Application"));
				mospParams.addErrorMessage(TimeMessageConst.MSG_REQUEST_CHECK_10, new String[]{
					getStringDate(dto.getWorkDate()), mospParams.getName("Vacation"), sb.toString() });
				return;
			} else if (!holidayAm && range == TimeConst.CODE_HOLIDAY_RANGE_AM) {
				// 午前休の場合
				holidayAm = true;
			} else if (!holidayPm && range == TimeConst.CODE_HOLIDAY_RANGE_PM) {
				// 午後休の場合
				holidayPm = true;
			}
		}
		// 代休
		boolean subHolidayAm = false;
		boolean subHolidayPm = false;
		List<SubHolidayRequestDtoInterface> subHolidayList = subHolidayDao.findForList(dto.getPersonalId(), dto
			.getWorkDate());
		for (SubHolidayRequestDtoInterface requestDto : subHolidayList) {
			WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(requestDto.getWorkflow());
			if (workflowDto == null || PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())
					|| PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())) {
				// 取下又は下書の場合
				continue;
			}
			int range = requestDto.getHolidayRange();
			if (range == TimeConst.CODE_HOLIDAY_RANGE_ALL) {
				// 全休の場合
				StringBuffer sb = new StringBuffer();
				sb.append(mospParams.getName("WorkManage"));
				sb.append(mospParams.getName("Application"));
				mospParams.addErrorMessage(TimeMessageConst.MSG_REQUEST_CHECK_10, new String[]{
					getStringDate(dto.getWorkDate()), mospParams.getName("CompensatoryHoliday"), sb.toString() });
				return;
			} else if (!subHolidayAm && range == TimeConst.CODE_HOLIDAY_RANGE_AM) {
				// 午前休の場合
				subHolidayAm = true;
			} else if (!subHolidayPm && range == TimeConst.CODE_HOLIDAY_RANGE_PM) {
				// 午後休の場合
				subHolidayPm = true;
			}
		}
		boolean am = holidayAm || subHolidayAm || substituteAm;
		boolean pm = holidayPm || subHolidayPm || substitutePm;
		if (am && pm) {
			// 午前休且つ午後休の場合
			String requestName = "";
			if (holidayAm) {
				// 休暇の場合
				requestName = mospParams.getName("Vacation");
			} else if (subHolidayAm) {
				// 代休の場合
				requestName = mospParams.getName("CompensatoryHoliday");
			} else if (substituteAm) {
				// 振替休日の場合
				requestName = mospParams.getName("ObservedHoliday");
			}
			StringBuffer sb = new StringBuffer();
			sb.append(mospParams.getName("WorkManage"));
			sb.append(mospParams.getName("Application"));
			mospParams.addErrorMessage(TimeMessageConst.MSG_REQUEST_CHECK_10, new String[]{
				getStringDate(dto.getWorkDate()), requestName, sb.toString() });
			return;
		}
	}
	
	/**
	 * @param dto 対象DTO
	 */
	public void checkTimeExist(AttendanceDtoInterface dto) {
		if (dto.getStartTime() == null && dto.getEndTime() == null) {
			// 始業時刻、終了時刻両方共無い場合
			// エラーメッセージ設定
			mospParams.addErrorMessage(TimeMessageConst.MSG_DRAFT_TIME_NOT_INPUT, null);
		}
	}
	
	/**
	 * @param dto 対象DTO
	 */
	public void checkTimeValidity(AttendanceDtoInterface dto) {
		if (dto.getStartTime() == null || dto.getEndTime() == null) {
			return;
		}
		if (dto.getEndTime().before(dto.getStartTime())) {
			// エラーメッセージ設定
			addInvalidOrderMessage(mospParams.getName("StartWork"), mospParams.getName("EndWork"));
		}
	}
	
	@Override
	public void checkAttendance(AttendanceDtoInterface dto) throws MospException {
		AttendanceDtoInterface attendanceDto = dao.findForKey(dto.getPersonalId(), dto.getWorkDate(), 1);
		if (attendanceDto == null) {
			return;
		}
		WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(attendanceDto.getWorkflow());
		if (workflowDto == null) {
			return;
		}
		if (PlatformConst.CODE_STATUS_WITHDRAWN.equals(workflowDto.getWorkflowStatus())) {
			// 取下の場合
			return;
		}
		if (PlatformConst.CODE_STATUS_DRAFT.equals(workflowDto.getWorkflowStatus())) {
			// 下書の場合
			return;
		}
		if (PlatformConst.CODE_STATUS_REVERT.equals(workflowDto.getWorkflowStatus())) {
			// 差戻の場合
			if (workflowDto.getWorkflowStage() == PlatformConst.WORKFLOW_STAGE_ZERO) {
				// ワークフロー段階が0の場合
				return;
			}
		}
		if (dto.getWorkflow() == workflowDto.getWorkflow()) {
			// ワークフロー番号が同じ場合は同じ申請
			return;
		}
		addAttendanceTargetWorkDateAttendanceRequestErrorMessage(dto.getWorkDate());
	}
	
	@Override
	public void checkRequired(AttendanceDtoInterface dto) {
		// 始業時刻チェック
		checkRegistStartTimeForWork(dto);
		// 終業時刻チェック
		checkRegistEndTimeForWork(dto);
	}
	
	/**
	 * 申請時の始業時刻チェック。
	 * @param dto 対象DTO
	 */
	protected void checkRegistStartTimeForWork(AttendanceDtoInterface dto) {
		if (dto == null || dto.getStartTime() == null) {
			mospParams.addErrorMessage(TimeMessageConst.MSG_TIME_FORMAT_CHECK,
					new String[]{ getNameStartTimeForWork() });
		}
	}
	
	/**
	 * 申請時の終業時刻チェック。
	 * @param dto 対象DTO
	 */
	protected void checkRegistEndTimeForWork(AttendanceDtoInterface dto) {
		if (dto == null || dto.getEndTime() == null) {
			mospParams.addErrorMessage(TimeMessageConst.MSG_TIME_FORMAT_CHECK, new String[]{ getNameEndTimeForWork() });
		}
	}
	
	@Override
	public void checkPrivateGoOut(AttendanceDtoInterface dto, List<RestDtoInterface> restList,
			List<GoOutDtoInterface> privateList) throws MospException {
		requestUtil.setRequests(dto.getPersonalId(), dto.getWorkDate());
		// 勤怠設定情報の取得
		setTimeSettings(dto.getPersonalId(), dto.getWorkDate());
		if (mospParams.hasErrorMessage()) {
			return;
		}
		
		int regWorkStart = 0;
		int regWorkEnd = 0;
		boolean isWorkOnDayOff = false;
		WorkOnHolidayRequestDtoInterface workOnHolidayRequestDto = requestUtil.getWorkOnHolidayDto(true);
		if (workOnHolidayRequestDto != null
				&& workOnHolidayRequestDto.getSubstitute() == TimeConst.CODE_WORK_ON_HOLIDAY_SUBSTITUTE_OFF) {
			// 休日出勤の場合
			isWorkOnDayOff = true;
			regWorkStart = getDefferenceMinutes(dto.getWorkDate(), dto.getStartTime());
			regWorkEnd = getDefferenceMinutes(dto.getWorkDate(), dto.getEndTime());
		}
		boolean isDifferenceWork = false;
		DifferenceRequestDtoInterface differenceDto = requestUtil.getDifferenceDto(true);
		if (differenceDto != null) {
			// 時差出勤の場合
			isDifferenceWork = true;
			regWorkStart = getDefferenceMinutes(dto.getWorkDate(), differenceDto.getRequestStart());
			regWorkEnd = getDefferenceMinutes(dto.getWorkDate(), differenceDto.getRequestEnd());
		}
		if (!isWorkOnDayOff && !isDifferenceWork) {
			// 休日出勤でなく且つ時差出勤でない場合
			WorkTypeItemDtoInterface workStartDto = workTypeItemDao.findForInfo(dto.getWorkTypeCode(), dto
				.getWorkDate(), TimeConst.CODE_WORKSTART);
			WorkTypeItemDtoInterface workEndDto = workTypeItemDao.findForInfo(dto.getWorkTypeCode(), dto.getWorkDate(),
					TimeConst.CODE_WORKEND);
			regWorkStart = getDefferenceMinutes(getDefaultStandardDate(), workStartDto.getWorkTypeItemValue());
			regWorkEnd = getDefferenceMinutes(getDefaultStandardDate(), workEndDto.getWorkTypeItemValue());
		}
		
		int workStart = getDefferenceMinutes(dto.getWorkDate(), dto.getStartTime());
		if (workStart < regWorkStart) {
			workStart = regWorkStart;
		}
		int workEnd = getDefferenceMinutes(dto.getWorkDate(), dto.getEndTime());
		if (workEnd > regWorkEnd) {
			workEnd = regWorkEnd;
		}
		
		// 休憩Map
		Map<Integer, Integer> restMap = new TreeMap<Integer, Integer>();
		for (RestDtoInterface restDto : restList) {
			int start = getDefferenceMinutes(dto.getWorkDate(), restDto.getRestStart());
			int end = getDefferenceMinutes(dto.getWorkDate(), restDto.getRestEnd());
			if (start >= regWorkEnd || end <= regWorkStart) {
				continue;
			}
			if (start < workStart) {
				start = workStart;
			}
			if (end > workEnd) {
				end = workEnd;
			}
			if (!restMap.containsKey(start) || restMap.get(start).intValue() < end) {
				restMap.put(start, end);
			}
		}
		
		// 私用外出Map
		Map<Integer, GoOutDtoInterface> privateMap = new TreeMap<Integer, GoOutDtoInterface>();
		for (GoOutDtoInterface privateDto : privateList) {
			int start = getDefferenceMinutes(dto.getWorkDate(), privateDto.getGoOutStart());
			int end = getDefferenceMinutes(dto.getWorkDate(), privateDto.getGoOutEnd());
			if (start >= regWorkEnd || end <= regWorkStart) {
				continue;
			}
			if (start < workStart) {
				start = workStart;
			}
			if (end > workEnd) {
				end = workEnd;
			}
			GoOutDtoInterface goOutDto = privateMap.get(start);
			if (goOutDto == null) {
				privateMap.put(start, privateDto);
			} else {
				int goOutEnd = getDefferenceMinutes(dto.getWorkDate(), goOutDto.getGoOutEnd());
				if (goOutEnd > workEnd) {
					goOutEnd = workEnd;
				}
				if (goOutEnd < end) {
					privateMap.put(start, privateDto);
				}
			}
		}
		
		// 限度時間
		int limitTime = getDefferenceMinutes(getDefaultStandardDate(), timeSettingDto.getLateEarlyHalf());
		// 休暇範囲
		int holidayRange = requestUtil.checkHolidayRangeHoliday(requestUtil.getHolidayList(false));
		// 代休範囲
		int subHolidayRange = requestUtil.checkHolidayRangeSubHoliday(requestUtil.getSubHolidayList(false));
		if (holidayRange != TimeConst.CODE_HOLIDAY_RANGE_AM && subHolidayRange != TimeConst.CODE_HOLIDAY_RANGE_AM
				&& dto.getLateTime() <= limitTime) {
			// 午前休でなく且つ遅刻時間が限度時間以下の場合
			int time = workStart;
			int privateTime = dto.getLateTime();
			while (privateTime <= limitTime) {
				int count = 0;
				for (Entry<Integer, GoOutDtoInterface> entry : privateMap.entrySet()) {
					GoOutDtoInterface privateDto = entry.getValue();
					int start = entry.getKey().intValue();
					int end = getDefferenceMinutes(dto.getWorkDate(), privateDto.getGoOutEnd());
					if (end > workEnd) {
						end = workEnd;
					}
					if (start == time && end > time) {
						privateTime += privateDto.getGoOutTime();
						time = end;
						count++;
					}
				}
				for (Entry<Integer, Integer> entry : restMap.entrySet()) {
					int start = entry.getKey().intValue();
					int end = entry.getValue().intValue();
					if (start == time && end > time) {
						time = end;
						count++;
					}
				}
				if (count == 0) {
					break;
				}
			}
			if (privateTime > limitTime) {
				// 遅刻時間 + 私用外出時間が遅刻早退限度時間を超える場合
				// メッセージ設定
				mospParams.addErrorMessage(TimeMessageConst.MSG_TARGET_DATE_TARDINESS_LEAVE_EARLY_LIMIT_OVER,
						new String[]{ getStringDate(dto.getWorkDate()), mospParams.getName("PrivateGoingOut"),
							mospParams.getName("Tardiness"), mospParams.getName("AmRest") });
				return;
			}
		}
		if (holidayRange != TimeConst.CODE_HOLIDAY_RANGE_PM && subHolidayRange != TimeConst.CODE_HOLIDAY_RANGE_PM
				&& dto.getLeaveEarlyTime() <= limitTime) {
			// 午後休でなく且つ早退時間が限度時間以下の場合
			int time = workEnd;
			int privateTime = dto.getLeaveEarlyTime();
			while (privateTime <= limitTime) {
				int count = 0;
				for (Entry<Integer, GoOutDtoInterface> entry : privateMap.entrySet()) {
					GoOutDtoInterface privateDto = entry.getValue();
					int start = entry.getKey().intValue();
					int end = getDefferenceMinutes(dto.getWorkDate(), privateDto.getGoOutEnd());
					if (end > workEnd) {
						end = workEnd;
					}
					if (end == time && start < time) {
						privateTime += privateDto.getGoOutTime();
						time = start;
						count++;
					}
				}
				for (Entry<Integer, Integer> entry : restMap.entrySet()) {
					int start = entry.getKey().intValue();
					int end = entry.getValue().intValue();
					if (end == time && start < time) {
						time = start;
						count++;
					}
				}
				if (count == 0) {
					break;
				}
			}
			if (privateTime > limitTime) {
				// 早退時間 + 私用外出時間が遅刻早退限度時間を超える場合
				// メッセージ設定
				mospParams.addErrorMessage(TimeMessageConst.MSG_TARGET_DATE_TARDINESS_LEAVE_EARLY_LIMIT_OVER,
						new String[]{ getStringDate(dto.getWorkDate()), mospParams.getName("PrivateGoingOut"),
							mospParams.getName("LeaveEarly"), mospParams.getName("PmRest") });
			}
		}
	}
	
	@Override
	public void checkTemporaryClosingFinal(AttendanceDtoInterface dto) throws MospException {
		// 対象個人IDにつき対象日付が未締であるかの確認
		cutoffUtil.checkTighten(dto.getPersonalId(), dto.getWorkDate(), getNameWorkDate());
	}
	
	@Override
	public void checkApprover(AttendanceDtoInterface dto, WorkflowDtoInterface workDto) throws MospException {
		String approverId = workDto.getApproverId();
		// 自己承認以外
		if (PlatformConst.APPROVAL_ROUTE_SELF.equals(approverId)) {
			return;
		}
		String[] arrayApproverId = approverId.split(",");
		for (String element : arrayApproverId) {
			// 対象データが1件しかない場合のチェック
			if (element.isEmpty()) {
				if (0 >= arrayApproverId.length) {
					mospParams.addErrorMessage(PlatformMessageConst.MSG_NOT_EXIST_AND_CHANGE_SOMETHING, mospParams
						.getName("Approver"), getNameWorkDate());
				}
			} else {
				// 入社チェック
				if (!entranceReference.isEntered(element, dto.getWorkDate())) {
					mospParams.addErrorMessage(PlatformMessageConst.MSG_NOT_EXIST_AND_CHANGE_SOMETHING, mospParams
						.getName("Approver"), getNameWorkDate());
				}
				// 退社チェック
				if (retirementReference.isRetired(element, dto.getWorkDate())) {
					mospParams.addErrorMessage(PlatformMessageConst.MSG_NOT_EXIST_AND_CHANGE_SOMETHING, mospParams
						.getName("Approver"), getNameWorkDate());
				}
			}
		}
	}
	
	/**
	 * 翌日の勤怠チェック。<br>
	 * @param dto 対象DTO
	 * @throws MospException SQLの作成に失敗した場合、或いはSQL例外が発生した場合
	 */
	protected void checkTomorrowAttendance(AttendanceDtoInterface dto) throws MospException {
		RequestUtilBeanInterface tomorrowRequestUtil = (RequestUtilBeanInterface)createBean(RequestUtilBeanInterface.class);
		tomorrowRequestUtil.setRequests(dto.getPersonalId(), addDay(dto.getWorkDate(), 1));
		AttendanceDtoInterface tomorrowDto = tomorrowRequestUtil.getApplicatedAttendance();
		if (tomorrowDto == null || tomorrowDto.getStartTime() == null) {
			return;
		}
		if (tomorrowDto.getStartTime().before(dto.getEndTime())) {
			// 翌日の始業時刻が当日の終業時刻より前の場合
			mospParams.addErrorMessage(TimeMessageConst.MSG_TOMORROW_WORK_BEGIN, new String[]{ getStringDate(dto
				.getWorkDate()) });
		}
	}
	
	public void delete(String personalId, Date workDate) throws MospException {
		// デフォルト勤務回数準備
		int timesWork = TIMES_WORK_DEFAULT;
		// 対象の勤怠日を取得
		AttendanceDtoInterface dto = dao.findForKey(personalId, workDate, timesWork);
		if (null != dto) {
			// 勤怠の削除
			delete(dto);
			attendanceCorrectionRegist.delete(personalId, workDate, timesWork);
			// 休憩関連の削除
			restRegist.delete(personalId, workDate, timesWork);
			goOutRegist.delete(personalId, workDate, timesWork);
			// ワークフローの削除
			WorkflowDtoInterface workflowDto = workflowReference.getLatestWorkflowInfo(dto.getWorkflow());
			workflowRegist.delete(workflowDto);
			List<WorkflowCommentDtoInterface> workflowCommentList = workflowCommentReference.getWorkflowCommentList(dto
				.getWorkflow());
			workflowCommentRegist.deleteList(workflowCommentList);
		}
	}
	
	@Override
	public void delete(AttendanceDtoInterface dto) throws MospException {
		// ロック対象テーブルの追加
		addTargetTable(dao.getTable(dao.getClass()), true);
		// ロック開始
		lockTables();
		// 論理削除
		logicalDelete(dao, dto.getTmdAttendanceId());
		// ロック解除
		unLockTable();
	}
	
	/**
	 * 勤務日名称を取得する。
	 * @return 勤務日名称
	 */
	protected String getNameWorkDate() {
		return mospParams.getName("Work") + mospParams.getName("Day");
	}
	
	/**
	 * 始業時刻名称を取得する。
	 * @return 始業時刻名称
	 */
	protected String getNameStartTimeForWork() {
		StringBuffer sb = new StringBuffer();
		sb.append(mospParams.getName("StartWork"));
		sb.append(mospParams.getName("Moment"));
		return sb.toString();
	}
	
	/**
	 * 終業時刻名称を取得する。
	 * @return 終業時刻名称
	 */
	protected String getNameEndTimeForWork() {
		StringBuffer sb = new StringBuffer();
		sb.append(mospParams.getName("EndWork"));
		sb.append(mospParams.getName("Moment"));
		return sb.toString();
	}
	
}
