/*
 * 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.util.ArrayList;
import java.util.Date;
import java.util.List;

import jp.mosp.framework.base.MospException;
import jp.mosp.framework.constant.MospConst;
import jp.mosp.framework.utils.DateUtility;
import jp.mosp.platform.base.PlatformBean;
import jp.mosp.platform.bean.workflow.WorkflowCommentRegistBeanInterface;
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.RouteApplicationDtoInterface;
import jp.mosp.platform.dto.workflow.WorkflowDtoInterface;
import jp.mosp.time.bean.AttendanceBean;
import jp.mosp.time.bean.AttendanceCalcBeanInterface;
import jp.mosp.time.bean.AttendanceListRegistBeanInterface;
import jp.mosp.time.bean.AttendanceRegistBeanInterface;
import jp.mosp.time.bean.DifferenceRequestReferenceBeanInterface;
import jp.mosp.time.bean.GoOutRegistBeanInterface;
import jp.mosp.time.bean.HolidayRequestReferenceBeanInterface;
import jp.mosp.time.bean.RestRegistBeanInterface;
import jp.mosp.time.bean.SubHolidayRegistBeanInterface;
import jp.mosp.time.bean.SubHolidayRequestReferenceBeanInterface;
import jp.mosp.time.constant.TimeConst;
import jp.mosp.time.dao.settings.RestDaoInterface;
import jp.mosp.time.dto.settings.ApplicationDtoInterface;
import jp.mosp.time.dto.settings.AttendanceDtoInterface;
import jp.mosp.time.dto.settings.DifferenceRequestDtoInterface;
import jp.mosp.time.dto.settings.HolidayRequestDtoInterface;
import jp.mosp.time.dto.settings.RestDtoInterface;
import jp.mosp.time.dto.settings.ScheduleDateDtoInterface;
import jp.mosp.time.dto.settings.SubHolidayDtoInterface;
import jp.mosp.time.dto.settings.SubHolidayRequestDtoInterface;
import jp.mosp.time.dto.settings.TimeSettingDtoInterface;
import jp.mosp.time.dto.settings.WorkOnHolidayRequestDtoInterface;
import jp.mosp.time.dto.settings.WorkTypeDtoInterface;
import jp.mosp.time.dto.settings.WorkTypeItemDtoInterface;
import jp.mosp.time.dto.settings.impl.TmmWorkTypeItemDto;

/**
 * 勤怠一覧登録クラス。
 */
public class AttendanceListRegistBean extends AttendanceBean implements AttendanceListRegistBeanInterface {
	
	/**
	 * 勤怠データ登録クラス。
	 */
	protected AttendanceRegistBeanInterface				attendanceRegist;
	
	/**
	 * 休憩データ登録クラス。
	 */
	protected RestRegistBeanInterface					restRegist;
	
	/**
	 * 休憩データDAOインターフェース
	 */
	protected RestDaoInterface							restDao;
	
	/**
	 * 外出データ登録クラス。
	 */
	protected GoOutRegistBeanInterface					goOutRegist;
	
	/**
	 * 代休データ登録クラス。
	 */
	protected SubHolidayRegistBeanInterface				subHolidayRegist;
	
	/**
	 * 休暇申請データ参照クラス。
	 */
	protected HolidayRequestReferenceBeanInterface		holidayRequestReference;
	
	/**
	 * 代休申請データ参照クラス。
	 */
	protected SubHolidayRequestReferenceBeanInterface	subHolidayRequestReference;
	
	/**
	 * 時差出勤申請参照クラス。
	 */
	protected DifferenceRequestReferenceBeanInterface	differenceReference;
	
	/**
	 * 時差出勤申請DTOインターフェース
	 */
	protected DifferenceRequestDtoInterface				differenceDto;
	
	/**
	 * 勤怠データ自動計算クラス。
	 */
	protected AttendanceCalcBeanInterface				attendanceCalc;
	
	/**
	 * ワークフロー登録クラス。
	 */
	WorkflowRegistBeanInterface							workflowRegist;
	
	/**
	 * ワークフローコメント登録クラス。
	 */
	WorkflowCommentRegistBeanInterface					workflowCommentRegist;
	
	/**
	 * 対象個人ID。<br>
	 * インターフェースに定義されたメソッドの最初で設定される。<br>
	 */
	protected String									personalId;
	
	/**
	 * 対象日。<br>
	 * インターフェースに定義されたメソッドにおける日毎処理の最初で設定される。<br>
	 */
	protected Date										targetDate;
	
	/**
	 * 設定適用マスタ情報。<br>
	 * 勤怠データ新規作成時に取得及び設定をされる。<br>
	 */
	protected ApplicationDtoInterface					applicationDto;
	
	/**
	 * カレンダ日情報。<br>
	 * 勤怠データ新規作成時に取得及び設定をされる。<br>
	 */
	protected ScheduleDateDtoInterface					scheduleDateDto;
	
	/**
	 * 勤務形態マスタ情報。<br>
	 * 勤怠データ新規作成時に取得及び設定をされる。<br>
	 */
	protected WorkTypeDtoInterface						workTypeDto;
	
	/**
	 * 勤怠設定マスタ情報。<br>
	 * 勤怠データ新規作成時に取得及び設定をされる。<br>
	 */
	protected TimeSettingDtoInterface					timeSettingDto;
	

	@Override
	public void initBean() throws MospException {
		// 継承元クラスのメソッドを実行
		super.initBean();
		// 各種クラス準備
		attendanceRegist = (AttendanceRegistBeanInterface)createBean(AttendanceRegistBeanInterface.class);
		restRegist = (RestRegistBeanInterface)createBean(RestRegistBeanInterface.class);
		restDao = (RestDaoInterface)createDao(RestDaoInterface.class);
		goOutRegist = (GoOutRegistBeanInterface)createBean(GoOutRegistBeanInterface.class);
		subHolidayRegist = (SubHolidayRegistBeanInterface)createBean(SubHolidayRegistBeanInterface.class);
		attendanceCalc = (AttendanceCalcBeanInterface)createBean(AttendanceCalcBeanInterface.class);
		workflowRegist = (WorkflowRegistBeanInterface)createBean(WorkflowRegistBeanInterface.class);
		workflowCommentRegist = (WorkflowCommentRegistBeanInterface)createBean(WorkflowCommentRegistBeanInterface.class);
		holidayRequestReference = (HolidayRequestReferenceBeanInterface)createBean(HolidayRequestReferenceBeanInterface.class);
		subHolidayRequestReference = (SubHolidayRequestReferenceBeanInterface)createBean(SubHolidayRequestReferenceBeanInterface.class);
		differenceReference = (DifferenceRequestReferenceBeanInterface)createBean(DifferenceRequestReferenceBeanInterface.class);
	}
	
	@Override
	public void draft(String personalId, String[] targetDates, String[] startTimes, String[] endTimes)
			throws MospException {
		// 対象個人ID設定
		this.personalId = personalId;
		// 日付リスト取得
		List<Date> targetDateList = getDateList(targetDates);
		// 始業時刻リスト取得
		List<Date> startTimeList = getAttendanceTimeList(targetDateList, startTimes);
		// 終業時刻リスト取得
		List<Date> endTimeList = getAttendanceTimeList(targetDateList, endTimes);
		// エラー確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 対象日毎に勤怠情報を作成して登録
		for (int i = 0; i < targetDateList.size(); i++) {
			// 対象日付設定
			targetDate = targetDateList.get(i);
			// 勤怠データ取得
			AttendanceDtoInterface dto = getAttendanceDto(startTimeList.get(i), endTimeList.get(i));
			// エラー確認
			if (mospParams.hasErrorMessage()) {
				continue;
			}
			// 妥当性チェック
			attendanceRegist.validate(dto);
			// 申請の相関チェック
			attendanceRegist.checkDraft(dto);
			// エラー確認
			if (mospParams.hasErrorMessage()) {
				continue;
			}
			// ワークフロー番号設定
			draft(dto);
			// エラー確認
			if (mospParams.hasErrorMessage()) {
				continue;
			}
			// 勤怠データ登録
			attendanceRegist.regist(dto);
		}
	}
	
	@Override
	public void apply(String personalId, String[] targetDates, String[] startTimes, String[] endTimes)
			throws MospException {
		// 対象個人ID設定
		this.personalId = personalId;
		// 日付リスト取得
		List<Date> targetDateList = getDateList(targetDates);
		// 始業時刻リスト取得
		List<Date> startTimeList = getAttendanceTimeList(targetDateList, startTimes);
		// 終業時刻リスト取得
		List<Date> endTimeList = getAttendanceTimeList(targetDateList, endTimes);
		// エラー確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 対象日毎に勤怠情報を作成して登録
		for (int i = 0; i < targetDateList.size(); i++) {
			// 対象日付設定
			targetDate = targetDateList.get(i);
			// 勤怠データ取得
			AttendanceDtoInterface dto = getAttendanceDto(startTimeList.get(i), endTimeList.get(i));
			// エラー確認
			if (mospParams.hasErrorMessage()) {
				continue;
			}
			// 申請の相関チェック
			attendanceRegist.checkAppli(dto);
			// エラー確認
			if (mospParams.hasErrorMessage()) {
				continue;
			}
			// ワークフロー番号設定
			apply(dto);
			// エラー確認
			if (mospParams.hasErrorMessage()) {
				continue;
			}
			registSubHoliday(dto);
			// 勤怠データ登録
			attendanceRegist.regist(dto);
		}
	}
	
	/**
	 * 登録用勤怠データを取得する。<br>
	 * 対象日における勤怠データが存在する場合は、始業時刻及び終業時刻を設定して返す。<br>
	 * <br>
	 * 存在しない場合は、新規に勤怠データを作成し、始業時刻及び終業時刻を設定する。<br>
	 * 勤怠データは、設定適用から各種情報を取得し、作成する。<br>
	 * 勤怠休憩情報、勤怠外出情報が勤務形態に設定されている場合は、これらを登録する。<br>
	 * <br>
	 * 設定適用情報等が存在せず勤怠データを作成できない場合は、nullを返す。<br>
	 * <br>
	 * @param startTime  始業時刻
	 * @param endTime    終業時刻
	 * @return 登録用勤怠データ
	 * @throws MospException インスタンスの取得或いはSQL実行に失敗した場合
	 */
	protected AttendanceDtoInterface getAttendanceDto(Date startTime, Date endTime) throws MospException {
		// 勤怠データ新規作成に必要な情報を取得及び設定
		setTimeDtos();
		// 勤怠データ取得(個人ID及び日付で取得)
		AttendanceDtoInterface dto = attendanceReference.findForKey(personalId, targetDate, TIMES_WORK_DEFAULT);
		// 対象日における勤怠データが存在する場合
		if (dto != null) {
			// 勤務形態設定
			dto.setWorkTypeCode(workTypeDto.getWorkTypeCode());
			if (differenceDto != null) {
				dto.setWorkTypeCode(differenceDto.getDifferenceType());
			}
			// 始業時刻及び終業時刻を設定
			dto.setStartTime(startTime);
			dto.setEndTime(endTime);
			if (startTime == null || endTime == null) {
				// 休憩時間を削除
				restRegist.delete(personalId, targetDate, TIMES_WORK_DEFAULT);
				// 外出時間を削除
				goOutRegist.delete(personalId, targetDate, TIMES_WORK_DEFAULT);
			} else {
				// 休憩時間を削除
				restRegist.delete(personalId, targetDate, TIMES_WORK_DEFAULT);
				// 休憩時間登録
				registRest(endTime);
			}
			// 勤怠データ自動計算
			attendanceCalc.attendanceCalc(dto);
			return dto;
		}
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return null;
		}
		// 勤怠データを新規に取得
		dto = attendanceRegist.getInitDto();
		// 個人ID設定
		dto.setPersonalId(personalId);
		// 勤務日設定
		dto.setWorkDate(targetDate);
		// 勤務回数設定
		dto.setTimesWork(TIMES_WORK_DEFAULT);
		// 勤務形態設定
		if (differenceDto != null) {
			dto.setWorkTypeCode(differenceDto.getDifferenceType());
		} else {
			dto.setWorkTypeCode(workTypeDto.getWorkTypeCode());
		}
		// 始業時刻設定
		dto.setStartTime(startTime);
		// 終業時刻設定
		dto.setEndTime(endTime);
		// その他項目の初期化
		dto.setDirectStart(Integer.parseInt(MospConst.CHECKBOX_OFF));
		dto.setDirectEnd(Integer.parseInt(MospConst.CHECKBOX_OFF));
		dto.setTimeComment("");
		dto.setLateReason("");
		dto.setLateCertificate("");
		dto.setLateComment("");
		dto.setLeaveEarlyReason("");
		dto.setLeaveEarlyCertificate("");
		dto.setLeaveEarlyComment("");
		if (startTime == null || endTime == null) {
			// 休憩時間を削除
			restRegist.delete(personalId, targetDate, TIMES_WORK_DEFAULT);
			// 外出時間を削除
			goOutRegist.delete(personalId, targetDate, TIMES_WORK_DEFAULT);
		} else {
			// 休憩時間登録
			registRest(endTime);
		}
		// 勤怠データ自動計算
		attendanceCalc.attendanceCalc(dto);
		return dto;
	}
	
	/**
	 * 対象個人IDの対象日における勤怠データを新規作成するのに必要な
	 * 各種情報を、取得及び設定する。<br>
	 * @throws MospException インスタンスの取得或いはSQL実行に失敗した場合
	 */
	protected void setTimeDtos() throws MospException {
		// 設定適用情報取得及び確認
		applicationDto = applicationReference.findForPerson(personalId, targetDate);
		// 確認
		if (applicationDto == null) {
			// エラーメッセージ設定
			addApplicationNotExistErrorMessage(targetDate);
			return;
		}
		// カレンダコード取得
		String scheduleCode = applicationDto.getScheduleCode();
		// カレンダ日情報取得
		scheduleDateDto = scheduleDateReference.getScheduleDateInfo(scheduleCode, targetDate, targetDate);
		// 確認
		if (scheduleDateDto == null) {
			// エラーメッセージ設定
			addScheduleNotExistErrorMessage(targetDate);
			return;
		}
		// 勤務形態コード取得
		String workTypeCode = scheduleDateDto.getWorkTypeCode();
		// 勤怠データ取得
		AttendanceDtoInterface attendanceDto = attendanceReference.findForKey(personalId, targetDate,
				TIMES_WORK_DEFAULT);
		// 勤怠データ確認
		if (attendanceDto != null && attendanceDto.getWorkTypeCode().isEmpty() == false) {
			// 勤怠データの勤務形態を取得
			workTypeCode = attendanceDto.getWorkTypeCode();
		}
		// 休日出勤情報取得
		WorkOnHolidayRequestDtoInterface workOnHolidayRequestDto = workOnHoliday.findForKey(personalId, targetDate,
				TIMES_WORK_DEFAULT);
		// 休日出勤申請確認
		if (workOnHolidayRequestDto != null) {
			// 休日出勤申請情報から休日出勤時の予定勤務形態を取得
			workTypeCode = getWorkOnHolidayWorkType(workOnHolidayRequestDto);
		}
		// 勤務形態情報取得
		workTypeDto = workTypeReference.getWorkTypeInfo(workTypeCode, targetDate);
		// 確認
		if (workTypeDto == null) {
			// エラーメッセージ設定
			addWorkTypeNotExistErrorMessage(targetDate);
			return;
		}
		// 勤怠設定情報取得
		timeSettingDto = timeSettingReference.getTimeSettingInfo(applicationDto.getWorkSettingCode(), targetDate);
		// 確認
		if (timeSettingDto == null) {
			// エラーメッセージ設定
			addTimeSettingNotExistErrorMessage(targetDate);
			return;
		}
		// 時差出勤
		DifferenceRequestDtoInterface differenceRequestDto = differenceReference.findForKeyOnWorkflow(personalId,
				targetDate);
		if (differenceRequestDto == null) {
			return;
		}
		WorkflowDtoInterface workflowDto = workflow.getLatestWorkflowInfo(differenceRequestDto.getWorkflow());
		if (workflowDto == null) {
			return;
		}
		if (PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
			differenceDto = differenceRequestDto;
		}
	}
	
	/**
	 * 設定されている勤務形態情報から休憩情報を取得し、登録する。<br>
	 * @param endTime 終業時刻
	 * @throws MospException インスタンスの取得或いはSQL実行に失敗した場合
	 */
	protected void registRest(Date endTime) throws MospException {
		// 勤務形態コード及び勤務形態有効日取得
		String workTypeCode = workTypeDto.getWorkTypeCode();
		Date activateDate = workTypeDto.getActivateDate();
		// 勤務形態マスタ項目情報リスト準備
		List<WorkTypeItemDtoInterface> startList = new ArrayList<WorkTypeItemDtoInterface>();
		List<WorkTypeItemDtoInterface> endList = new ArrayList<WorkTypeItemDtoInterface>();
		boolean holidayAm = false;
		boolean holidayPm = false;
		List<HolidayRequestDtoInterface> holidayList = holidayRequestReference.getHolidayRequestList(personalId,
				targetDate);
		for (HolidayRequestDtoInterface dto : holidayList) {
			WorkflowDtoInterface workflowDto = workflow.getLatestWorkflowInfo(dto.getWorkflow());
			if (workflowDto == null) {
				continue;
			}
			if (!PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
				continue;
			}
			int range = dto.getHolidayRange();
			if (range == 2) {
				holidayAm = true;
			} else if (range == 3) {
				holidayPm = true;
			}
		}
		List<SubHolidayRequestDtoInterface> subHolidayList = subHolidayRequestReference.getSubHolidayRequestList(
				personalId, targetDate);
		for (SubHolidayRequestDtoInterface dto : subHolidayList) {
			WorkflowDtoInterface workflowDto = workflow.getLatestWorkflowInfo(dto.getWorkflow());
			if (workflowDto == null) {
				continue;
			}
			if (!PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
				continue;
			}
			int range = dto.getHolidayRange();
			if (range == 2) {
				holidayAm = true;
			} else if (range == 3) {
				holidayPm = true;
			}
		}
		if (holidayAm || holidayPm) {
			if (holidayAm) {
				WorkTypeItemDtoInterface halfRestDto = workTypeItemReference.findForKey(workTypeCode, activateDate,
						TimeConst.CODE_HALFREST);
				if (endTime != null
						&& DateUtility.getHour(endTime) * 60 + DateUtility.getMinute(endTime) >= DateUtility
							.getHour(halfRestDto.getWorkTypeItemValue())
								* 60 + DateUtility.getMinute(halfRestDto.getWorkTypeItemValue())) {
					startList.add(workTypeItemReference.findForKey(workTypeCode, activateDate,
							TimeConst.CODE_HALFRESTSTART));
					endList.add(workTypeItemReference
						.findForKey(workTypeCode, activateDate, TimeConst.CODE_HALFRESTEND));
				}
			}
		} else {
			// 勤務形態マスタ項目情報(休憩1～4)を取得しリストに追加
			if (differenceDto != null) {
				WorkTypeItemDtoInterface workTypeItemDto = new TmmWorkTypeItemDto();
				workTypeItemDto.setWorkTypeItemValue(DateUtility.getTime(0, 0));
				WorkTypeItemDtoInterface workTypeItemStartDto = new TmmWorkTypeItemDto();
				workTypeItemStartDto.setWorkTypeItemValue(getDifferenceRestStart());
				WorkTypeItemDtoInterface workTypeItemEndDto = new TmmWorkTypeItemDto();
				workTypeItemEndDto.setWorkTypeItemValue(getDifferenceRestEnd());
				startList.add(workTypeItemStartDto);
				startList.add(workTypeItemDto);
				startList.add(workTypeItemDto);
				startList.add(workTypeItemDto);
				endList.add(workTypeItemEndDto);
				endList.add(workTypeItemDto);
				endList.add(workTypeItemDto);
				endList.add(workTypeItemDto);
			} else {
				startList.add(workTypeItemReference.findForKey(workTypeCode, activateDate, TimeConst.CODE_RESTSTART1));
				startList.add(workTypeItemReference.findForKey(workTypeCode, activateDate, TimeConst.CODE_RESTSTART2));
				startList.add(workTypeItemReference.findForKey(workTypeCode, activateDate, TimeConst.CODE_RESTSTART3));
				startList.add(workTypeItemReference.findForKey(workTypeCode, activateDate, TimeConst.CODE_RESTSTART4));
				endList.add(workTypeItemReference.findForKey(workTypeCode, activateDate, TimeConst.CODE_RESTEND1));
				endList.add(workTypeItemReference.findForKey(workTypeCode, activateDate, TimeConst.CODE_RESTEND2));
				endList.add(workTypeItemReference.findForKey(workTypeCode, activateDate, TimeConst.CODE_RESTEND3));
				endList.add(workTypeItemReference.findForKey(workTypeCode, activateDate, TimeConst.CODE_RESTEND4));
			}
		}
		// 勤務形態マスタ項目毎に処理
		for (int i = 0; i < startList.size(); i++) {
			// 休憩情報存在確認
			if (startList.get(i) == null || endList.get(i) == null) {
				// 休憩情報が存在しない場合は登録不要
				continue;
			}
			// 勤務形態マスタ項目情報から休憩開始終了時刻を取得
			Date restStartTime = getTime(startList.get(i).getWorkTypeItemValue(), targetDate);
			Date restEndTime = getTime(endList.get(i).getWorkTypeItemValue(), targetDate);
			// 休憩開始終了時刻確認
			if (restStartTime.equals(restEndTime)) {
				// 休憩開始時刻と休憩終了時刻が同じ場合は登録不要
				continue;
			}
			// 休憩情報準備(休憩回数はi+1)
			RestDtoInterface dto = restRegist.getInitDto();
			RestDtoInterface restDto = restDao.findForKey(personalId, targetDate, TIMES_WORK_DEFAULT, i + 1);
			if (restDto != null) {
				dto.setTmdRestId(restDto.getTmdRestId());
			}
			dto.setPersonalId(personalId);
			dto.setWorkDate(targetDate);
			dto.setTimesWork(TIMES_WORK_DEFAULT);
			dto.setRest(i + 1);
			dto.setRestStart(restStartTime);
			dto.setRestEnd(restEndTime);
			Date roundRestStartTime = attendanceCalc.getRoundMinute(restStartTime, timeSettingDto
				.getRoundDailyRestStart(), timeSettingDto.getRoundDailyRestStartUnit());
			Date roundRestEndTime = attendanceCalc.getRoundMinute(restEndTime, timeSettingDto.getRoundDailyRestEnd(),
					timeSettingDto.getRoundDailyRestEndUnit());
			dto.setRestTime(attendanceCalc.getRoundMinute(getDefferenceMinutes(roundRestStartTime, roundRestEndTime),
					timeSettingDto.getRoundDailyRestTime(), timeSettingDto.getRoundDailyRestTimeUnit()));
			// 休憩情報登録
			restRegist.regist(dto);
		}
	}
	
	/**
	 * 代休データを登録する。<br>
	 * @param dto 対象勤怠データ情報
	 * @throws MospException インスタンスの取得或いはSQL実行に失敗した場合
	 */
	protected void registSubHoliday(AttendanceDtoInterface dto) throws MospException {
		subHolidayRegist.delete(dto.getPersonalId(), dto.getWorkDate());
		if (dto.getWorkTime() - dto.getLateNightTime() >= 7 * 60) {
			// 勤務時間 - 深夜勤務時間
			// が7時間以上の場合
			if (dto.getLateNightTime() >= 3 * 60) {
				// 深夜勤務時間が3時間以上6時間未満の場合
				SubHolidayDtoInterface subHolidayDto = subHolidayRegist.getInitDto();
				subHolidayDto.setPersonalId(dto.getPersonalId());
				subHolidayDto.setWorkDate(dto.getWorkDate());
				subHolidayDto.setTimesWork(1);
				subHolidayDto.setSubHolidayType(TimeConst.CODE_MIDNIGHT_SUBHOLIDAY_CODE);
				subHolidayDto.setSubHolidayDays(0.5);
				if (dto.getLateNightTime() >= 6 * 60) {
					// 深夜勤務時間が6時間以上の場合
					subHolidayDto.setSubHolidayDays(1);
				}
				subHolidayRegist.insert(subHolidayDto);
			}
		}
		WorkOnHolidayRequestDtoInterface workOnHolidayRequestDto = workOnHoliday.findForKeyOnWorkflow(dto
			.getPersonalId(), dto.getWorkDate());
		if (workOnHolidayRequestDto == null) {
			return;
		}
		if (workOnHolidayRequestDto.getSubstitute() == TimeConst.CODE_WORK_ON_HOLIDAY_SUBSTITUTE_ON) {
			// 振替休日を申請している場合
			return;
		}
		WorkflowDtoInterface workflowDto = workflow.getLatestWorkflowInfo(workOnHolidayRequestDto.getWorkflow());
		if (workflowDto == null) {
			return;
		}
		if (!PlatformConst.CODE_STATUS_COMPLETE.equals(workflowDto.getWorkflowStatus())) {
			return;
		}
		SubHolidayDtoInterface subHolidayDto = subHolidayRegist.getInitDto();
		subHolidayDto.setPersonalId(dto.getPersonalId());
		subHolidayDto.setWorkDate(dto.getWorkDate());
		subHolidayDto.setTimesWork(1);
		if (TimeConst.CODE_HOLIDAY_LEGAL_HOLIDAY.equals(workOnHolidayRequestDto.getWorkOnHolidayType())) {
			// 法定休日代休
			subHolidayDto.setSubHolidayType(TimeConst.CODE_LEGAL_SUBHOLIDAY_CODE);
		} else if (TimeConst.CODE_HOLIDAY_PRESCRIBED_HOLIDAY.equals(workOnHolidayRequestDto.getWorkOnHolidayType())) {
			// 所定休日代休
			subHolidayDto.setSubHolidayType(TimeConst.CODE_PRESCRIBED_SUBHOLIDAY_CODE);
		} else {
			return;
		}
		if (dto.getWorkTime() >= DateUtility.getHour(timeSettingDto.getSubHolidayHalfNorm()) * 60
				+ DateUtility.getMinute(timeSettingDto.getSubHolidayHalfNorm())) {
			subHolidayDto.setSubHolidayDays(0.5);
			if (dto.getWorkTime() >= DateUtility.getHour(timeSettingDto.getSubHolidayAllNorm()) * 60
					+ DateUtility.getMinute(timeSettingDto.getSubHolidayAllNorm())) {
				subHolidayDto.setSubHolidayDays(1);
			}
			subHolidayRegist.insert(subHolidayDto);
		}
	}
	
	/**
	 * 対象勤怠データ情報に対し、
	 * ワークフロー(下書)を作成して、ワークフロー番号を設定する。<br>
	 * 但し、既にワークフロー番号が設定されている場合は、何もしない。<br>
	 * @param dto 対象勤怠データ情報
	 * @throws MospException インスタンスの取得或いはSQL実行に失敗した場合
	 */
	protected void draft(AttendanceDtoInterface dto) throws MospException {
		// ワークフロー番号確認
		if (dto.getWorkflow() != 0) {
			// 既にワークフロー番号が設定されている場合
			return;
		}
		// ワークフロー情報準備
		WorkflowDtoInterface workflowDto = workflowRegist.getInitDto();
		workflowDto.setFunctionCode(TimeConst.CODE_FUNCTION_WORK_MANGE);
		// ワークフロー登録(下書)
		workflowDto = workflowRegist.draft(workflowDto, personalId, targetDate, PlatformConst.WORKFLOW_TYPE_TIME);
		// ワークフロー番号を勤怠データに設定
		dto.setWorkflow(workflowDto.getWorkflow());
	}
	
	/**
	 * 対象勤怠データ情報に対し、
	 * ワークフロー(申請)を作成して、ワークフロー番号を設定する。<br>
	 * @param dto 対象勤怠データ情報
	 * @throws MospException インスタンスの取得或いはSQL実行に失敗した場合
	 */
	protected void apply(AttendanceDtoInterface dto) throws MospException {
		// ワークフロー情報準備
		WorkflowDtoInterface workflowDto = workflowRegist.getInitDto();
		// ワークフロー情報確認
		if (dto.getWorkflow() != 0) {
			// ワークフロー情報取得(新規でない場合)
			workflowDto = workflow.getLatestWorkflowInfo(dto.getWorkflow());
		}
		// ルートコード或いは承認者を設定
		setRouteApprover(workflowDto);
		// ワークフロー情報機能コード設定
		workflowDto.setFunctionCode(TimeConst.CODE_FUNCTION_WORK_MANGE);
		// ワークフロー申請
		workflowDto = workflowRegist.appli(workflowDto, personalId, targetDate, PlatformConst.WORKFLOW_TYPE_TIME);
		// ワークフローコメント登録
		workflowCommentRegist.addComment(workflowDto, mospParams.getUser().getPersonalId(),
				getApplicationSucceedMessage());
		// ワークフロー番号を勤怠データに設定
		dto.setWorkflow(workflowDto.getWorkflow());
	}
	
	/**
	 * ワークフロー情報に、ルートコード或いは承認者を設定する。<br>
	 * @param workflowDto ワークフロー情報
	 * @throws MospException インスタンスの取得或いはSQL実行に失敗した場合
	 */
	protected void setRouteApprover(WorkflowDtoInterface workflowDto) throws MospException {
		// ルート適用情報取得及び確認
		RouteApplicationDtoInterface routeApplicationDto = workflow.findForPerson(personalId, targetDate,
				PlatformConst.WORKFLOW_TYPE_TIME);
		if (routeApplicationDto != null) {
			// ルートコード設定
			workflowDto.setRouteCode(routeApplicationDto.getRouteCode());
			workflowDto.setApproverId("");
			return;
		}
		// 承認者リスト取得
		List<List<String[]>> routeApproverList = workflow.getRouteApproverList(personalId, targetDate,
				PlatformConst.WORKFLOW_TYPE_TIME);
		// デフォルト承認者リスト作成
		List<String> defaultApproverList = new ArrayList<String>();
		// 承認者リスト毎に処理
		for (List<String[]> stageApproverList : routeApproverList) {
			// デフォルト承認者設定
			defaultApproverList.add(stageApproverList.get(0)[0]);
		}
		// ワークフロー情報に設定
		workflowDto.setApproverId(toSeparatedString(defaultApproverList, PlatformBean.SEPARATOR_DATA));
		workflowDto.setRouteCode("");
	}
	
	/**
	 * 日付文字列配列を日付オブジェクトリストに変換して取得する。<br>
	 * @param dates 日付文字列配列
	 * @return 日付オブジェクトリスト
	 */
	protected List<Date> getDateList(String[] dates) {
		// リスト準備
		List<Date> list = new ArrayList<Date>();
		// 変換して追加
		for (String date : dates) {
			list.add(DateUtility.getDate(date));
		}
		return list;
	}
	
	/**
	 * 時刻文字列配列を日付オブジジェクトリスト(時刻)に変換して取得する。<br>
	 * 変換の際に、日付リストの日付が基準となる。<br>
	 * @param dateList 日付リスト
	 * @param times 時刻文字列配列
	 * @return 日付オブジェクトリスト(時刻)
	 */
	protected List<Date> getAttendanceTimeList(List<Date> dateList, String[] times) {
		// リスト準備
		List<Date> list = new ArrayList<Date>();
		// 変換して追加
		for (int i = 0; i < times.length; i++) {
			list.add(!times[i].equals("") ? getAttendanceTime(dateList.get(i), times[i]) : null);
		}
		return list;
	}
	
	/**
	 * 申請が成功した場合のメッセージを取得する。<br>
	 * @return 申請が成功した場合のメッセージ
	 */
	protected String getApplicationSucceedMessage() {
		String[] rep = { mospParams.getName("Application") };
		return mospParams.getProperties().getMessage(PlatformMessageConst.MSG_PROCESS_SUCCEED, rep);
	}
	
	/**
	 * @return
	 * @throws MospException 
	 */
	protected Date getDifferenceRestStart() throws MospException {
		if (TimeConst.CODE_DIFFERENCE_TYPE_S.equals(differenceDto.getDifferenceType())) {
			int hour = DateUtility.getHour(differenceDto.getRequestStart());
			return DateUtility.getTime(hour + 3, 0);
		} else {
			return DateUtility.getTime(12, 0);
		}
	}
	
	/**
	 * @return
	 * @throws MospException 
	 */
	protected Date getDifferenceRestEnd() throws MospException {
		if (TimeConst.CODE_DIFFERENCE_TYPE_S.equals(differenceDto.getDifferenceType())) {
			int hour = DateUtility.getHour(differenceDto.getRequestStart());
			return DateUtility.getTime(hour + 4, 0);
		} else {
			return DateUtility.getTime(13, 0);
		}
	}
	
}
