package jp.mosp.time.bean.impl;

import java.util.Date;
import java.util.List;

import jp.mosp.framework.base.MospException;
import jp.mosp.framework.utils.DateUtility;
import jp.mosp.time.base.TimeBean;
import jp.mosp.time.bean.TimeRecordBeanInterface;
import jp.mosp.time.dto.settings.AttendanceDtoInterface;
import jp.mosp.time.dto.settings.RestDtoInterface;
import jp.mosp.time.utils.TimeRecordUtility;

/**
 * 打刻クラス。
 */
public class TimeRecordBean extends AttendanceListRegistBean implements TimeRecordBeanInterface {
	
	/**
	 * 最大休憩回数。<br>
	 */
	protected static final int	MAX_REST_TIMES	= 6;
	

	/**
	 * {@link TimeBean#TimeBean()}を実行する。<br>
	 */
	public TimeRecordBean() {
		super();
	}
	
	@Override
	public void recordStartWork(String personalId, Date recordTime) throws MospException {
		// 対象個人ID設定
		this.personalId = personalId;
		// 対象日設定
		targetDate = DateUtility.getDate(recordTime);
		// 勤怠データ取得
		AttendanceDtoInterface dto = attendanceReference.findForKey(this.personalId, targetDate, TIMES_WORK_DEFAULT);
		// 勤怠情報確認
		if (dto != null) {
			// エラーメッセージ設定
			TimeRecordUtility.addAlreadyRecordedErrorMessage(TimeRecordUtility.getNameStartWork(mospParams),
					targetDate, mospParams);
			return;
		}
		// 勤怠データ作成
		dto = getAttendanceDto(recordTime, null, false);
		// エラーメッセージ確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 妥当性チェック
		attendanceRegist.validate(dto);
		// 申請の相関チェック
		attendanceRegist.checkDraft(dto);
		// エラー確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// ワークフロー番号設定
		draft(dto);
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 勤怠データ登録
		attendanceRegist.regist(dto);
	}
	
	@Override
	public void recordEndWork(String personalId, Date recordTime) throws MospException {
		// 対象個人ID設定
		this.personalId = personalId;
		// 対象日設定及び対象日の勤怠情報取得
		AttendanceDtoInterface dto = setTargetDate(TimeRecordUtility.getNameEndWork(mospParams));
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 休憩デフォルト日時取得
		Date restDefaultTime = getRestDefaultTime();
		// 休憩情報取得(0も登録されている)
		List<RestDtoInterface> list = restDao.findForList(this.personalId, targetDate, TIMES_WORK_DEFAULT);
		// 休憩情報毎に処理
		for (RestDtoInterface restDto : list) {
			// 休憩戻り確認
			if (restDefaultTime.equals(restDto.getRestStart()) == false && restDefaultTime.equals(restDto.getRestEnd())) {
				// エラーメッセージ設定
				TimeRecordUtility.addStartNotRecordedErrorMessage(TimeRecordUtility.getNameEndWork(mospParams),
						targetDate, TimeRecordUtility.getNameEndRest(mospParams), mospParams);
				return;
			}
		}
		// 登録用勤怠データを取得(各種自動計算実施)
		dto = getAttendanceDto(dto.getStartTime(), recordTime, true);
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 妥当性チェック
		attendanceRegist.validate(dto);
		// 申請の相関チェック
		attendanceRegist.checkAppli(dto);
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// ワークフロー番号設定
		apply(dto);
		// エラー確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 勤怠データ登録
		attendanceRegist.regist(dto);
	}
	
	@Override
	public void recordStartRest(String personalId, Date recordTime) throws MospException {
		// 対象個人ID設定
		this.personalId = personalId;
		// 対象日設定及び対象日の勤怠情報取得
		setTargetDate(TimeRecordUtility.getNameStartRest(mospParams));
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 休憩情報取得
		List<RestDtoInterface> list = restDao.findForList(this.personalId, targetDate, TIMES_WORK_DEFAULT);
		// 休憩デフォルト日時取得
		Date restDefaultTime = getRestDefaultTime();
		// 処理対象情報準備
		RestDtoInterface dto = null;
		// 休憩情報毎に処理
		for (RestDtoInterface restDto : list) {
			// 休憩入日時確認
			if (restDefaultTime.equals(restDto.getRestStart())) {
				// 処理対象情報設定
				dto = restDto;
				dto.setRestStart(recordTime);
				break;
			}
			// 休憩戻り確認
			if (restDefaultTime.equals(restDto.getRestEnd())) {
				// エラーメッセージ追加
				TimeRecordUtility.addAlreadyRecordedErrorMessage(TimeRecordUtility.getNameStartRest(mospParams),
						targetDate, mospParams);
				return;
			}
		}
		// 処理対象情報確認
		if (dto == null && list.size() < MAX_REST_TIMES) {
			// 処理対象情報作成
			dto = restRegist.getInitDto();
			dto.setPersonalId(this.personalId);
			dto.setWorkDate(targetDate);
			dto.setTimesWork(TIMES_WORK_DEFAULT);
			dto.setRest(list.size() + 1);
			dto.setRestStart(recordTime);
			dto.setRestEnd(restDefaultTime);
			dto.setRestTime(0);
		}
		// 処理対象情報確認
		if (dto == null) {
			// エラーメッセージ設定
			TimeRecordUtility.addOverLimitErrorMessage(targetDate, mospParams);
			return;
		}
		// 休憩情報登録
		restRegist.regist(dto);
	}
	
	@Override
	public void recordEndRest(String personalId, Date recordTime) throws MospException {
		// 対象個人ID設定
		this.personalId = personalId;
		// 対象日設定及び対象日の勤怠情報取得
		setTargetDate(TimeRecordUtility.getNameEndRest(mospParams));
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 勤怠関連各種情報取得
		setTimeDtos();
		// エラーメッセージ確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 休憩情報取得
		List<RestDtoInterface> list = restDao.findForList(this.personalId, targetDate, TIMES_WORK_DEFAULT);
		// 休憩デフォルト日時取得
		Date restDefaultTime = getRestDefaultTime();
		// 処理対象情報準備
		RestDtoInterface dto = null;
		// 休憩情報毎に処理
		for (RestDtoInterface restDto : list) {
			// 休憩入日時確認
			if (restDefaultTime.equals(restDto.getRestStart()) == false && restDefaultTime.equals(restDto.getRestEnd())) {
				// 処理対象情報設定
				dto = restDto;
				dto.setRestEnd(recordTime);
				// 休憩時間計算
				dto.setRestTime(attendanceCalc.getRoundMinute(attendanceCalc.getDefferenceMinutes(dto.getRestStart(),
						dto.getRestEnd()), timeSettingDto.getRoundDailyRestTime(), timeSettingDto
					.getRoundDailyRestTimeUnit()));
				break;
			}
		}
		// 処理対象情報確認
		if (dto == null) {
			// エラーメッセージ設定
			TimeRecordUtility.addStartNotRecordedErrorMessage(TimeRecordUtility.getNameEndRest(mospParams), targetDate,
					TimeRecordUtility.getNameStartRest(mospParams), mospParams);
			return;
		}
		// 休憩情報登録
		restRegist.regist(dto);
	}
	
	@Override
	public void recordStartWork() throws MospException {
		// 対象個人ID(ログインユーザの個人ID)及び打刻日時(システム日時)を取得し打刻
		recordStartWork(mospParams.getUser().getPersonalId(), getSystemTime());
	}
	
	@Override
	public void recordEndWork() throws MospException {
		// 対象個人ID(ログインユーザの個人ID)及び打刻日時(システム日時)を取得し打刻
		recordEndWork(mospParams.getUser().getPersonalId(), getSystemTime());
	}
	
	@Override
	public void recordStartRest() throws MospException {
		// 対象個人ID(ログインユーザの個人ID)及び打刻日時(システム日時)を取得し打刻
		recordStartRest(mospParams.getUser().getPersonalId(), getSystemTime());
	}
	
	@Override
	public void recordEndRest() throws MospException {
		// 対象個人ID(ログインユーザの個人ID)及び打刻日時(システム日時)を取得し打刻
		recordEndRest(mospParams.getUser().getPersonalId(), getSystemTime());
	}
	
	/**
	 * 休憩のデフォルト日時を取得する。<br>
	 * @return 休憩のデフォルト日時
	 */
	protected Date getRestDefaultTime() {
		return attendanceCalc.getAttendanceTime(targetDate, "0", "0");
	}
	
	/**
	 * 打刻対象日を設定する。<br>
	 * <br>
	 * 打刻した日の勤怠情報が存在し終業時間が登録されていない場合は、
	 * 打刻した日が打刻対象日となる。<br>
	 * <br>
	 * 打刻した日の勤怠情報が存在しない場合、前日の勤怠情報を確認する。<br>
	 * 前日の勤怠情報が存在し終業時間が登録されていない場合は、
	 * 前日が打刻対象日となる。<br>
	 * <br>
	 * 上記の場合以外は、打刻対象日を設定しない。<br>
	 * <br>
	 * @param process 打刻対象処理
	 * @return 打刻対象日の勤怠情報
	 * @throws MospException 勤怠情報の取得に失敗した場合
	 */
	protected AttendanceDtoInterface setTargetDate(String process) throws MospException {
		// 対象日設定(システム日付)
		Date recordDate = getSystemDate();
		// 勤怠データ取得
		AttendanceDtoInterface dto = attendanceReference.findForKey(personalId, recordDate, TIMES_WORK_DEFAULT);
		// 打刻した日の勤怠情報が存在しない場合
		if (dto == null) {
			// 前日の勤怠を取得
			Date beforeDate = addDay(recordDate, -1);
			dto = attendanceReference.findForKey(personalId, beforeDate, TIMES_WORK_DEFAULT);
			// 前日の勤怠を確認
			if (dto != null && dto.getEndTime() == null) {
				// 対象日として前日を設定(深夜に日付を超えて打刻した場合等)
				targetDate = beforeDate;
			} else {
				// エラーメッセージ設定
				TimeRecordUtility.addStartNotRecordedErrorMessage(process, recordDate, TimeRecordUtility
					.getNameStartWork(mospParams), mospParams);
			}
		} else if (dto.getEndTime() != null) {
			// エラーメッセージ設定
			TimeRecordUtility.addAlreadyRecordedErrorMessage(TimeRecordUtility.getNameEndWork(mospParams), recordDate,
					mospParams);
		} else {
			targetDate = recordDate;
		}
		return dto;
	}
	
}
