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

import jp.mosp.framework.base.MospException;
import jp.mosp.framework.base.MospParams;
import jp.mosp.framework.utils.DateUtility;
import jp.mosp.platform.bean.human.HumanSearchBeanInterface;
import jp.mosp.platform.constant.PlatformConst;
import jp.mosp.platform.constant.PlatformMessageConst;
import jp.mosp.time.base.TimeApplicationBean;
import jp.mosp.time.base.TimeBean;
import jp.mosp.time.bean.CutoffUtilBeanInterface;
import jp.mosp.time.bean.TotalTimeEmployeeTransactionReferenceBeanInterface;
import jp.mosp.time.constant.TimeConst;
import jp.mosp.time.dto.settings.ApplicationDtoInterface;
import jp.mosp.time.dto.settings.CutoffDtoInterface;
import jp.mosp.time.dto.settings.TimeSettingDtoInterface;
import jp.mosp.time.utils.TimeUtility;

/**
 * 締日ユーティリティクラス。<br>
 *
 */
public class CutoffUtilBean extends TimeApplicationBean implements CutoffUtilBeanInterface {
	
	/**
	 * 人事情報検索クラス。
	 */
	HumanSearchBeanInterface							humanSearch;
	
	/**
	 * 社員勤怠集計管理参照クラス。
	 */
	TotalTimeEmployeeTransactionReferenceBeanInterface	totalTimeEmployeeRefer;
	

	/**
	 * {@link TimeBean#TimeBean()}を実行する。<br>
	 */
	public CutoffUtilBean() {
		super();
	}
	
	/**
	 * {@link TimeBean#TimeBean(MospParams, Connection)}を実行する。<br>
	 * @param mospParams MosP処理情報
	 * @param connection DBコネクション
	 */
	protected CutoffUtilBean(MospParams mospParams, Connection connection) {
		super(mospParams, connection);
	}
	
	@Override
	public void initBean() throws MospException {
		// 継承元のメソッドを実施
		super.initBean();
		// 各種クラスの取得
		humanSearch = (HumanSearchBeanInterface)createBean(HumanSearchBeanInterface.class);
		totalTimeEmployeeRefer = (TotalTimeEmployeeTransactionReferenceBeanInterface)createBean(TotalTimeEmployeeTransactionReferenceBeanInterface.class);
	}
	
	@Override
	public Set<String> getCutoffPersonalIdSet(String cutoffCode, int targetYear, int targetMonth) throws MospException {
		// 個人IDセットの準備
		Set<String> idSet = new HashSet<String>();
		// 年月を指定して締日情報を取得
		CutoffDtoInterface cutoffDto = getCutoff(cutoffCode, targetYear, targetMonth);
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return idSet;
		}
		// 対象年月における締期間の基準日及び初日、最終日取得
		Date cutoffTermTargetDate = TimeUtility.getCutoffTermTargetDate(cutoffDto.getCutoffDate(), targetYear,
				targetMonth);
		Date firstDate = TimeUtility.getCutoffFirstDate(cutoffDto.getCutoffDate(), targetYear, targetMonth);
		Date lastDate = TimeUtility.getCutoffLastDate(cutoffDto.getCutoffDate(), targetYear, targetMonth);
		// 有効な個人IDセット取得(対象日は締期間の基準日)
		Set<String> activateSet = getActivatePersonalIdSet(cutoffTermTargetDate, firstDate, lastDate);
		// 締日コード及び基準日で勤怠設定情報リスト取得
		List<String> workSettingCodeList = timeSettingRefer.getWorkSettingCode(cutoffCode, cutoffTermTargetDate);
		if (workSettingCodeList.isEmpty()) {
			// 勤怠設定コードが存在しないなら処理終了
			mospParams.addErrorMessage(PlatformMessageConst.MSG_NO_ITEM, mospParams.getName("menuTimeSettings"), null);
			return idSet;
		}
		// 有効な個人ID毎に処理
		for (String personalId : activateSet) {
			// 設定適用情報を取得(対象日は締期間の基準日)
			ApplicationDtoInterface applicationDto = applicationRefer.findForPerson(personalId, cutoffTermTargetDate);
			//  設定適用情報確認
			if (applicationDto == null) {
				continue;
			}
			// 勤怠設定コード確認
			if (workSettingCodeList.contains(applicationDto.getWorkSettingCode())) {
				idSet.add(personalId);
			}
		}
		// 個人IDセット確認
		if (idSet.isEmpty()) {
			// 登録失敗メッセージ設定
			mospParams.addErrorMessage(PlatformMessageConst.MSG_NO_ITEM, mospParams.getName("Employee"), null);
		}
		return idSet;
	}
	
	@Override
	public CutoffDtoInterface getCutoff(String cutoffCode, int targetYear, int targetMonth) throws MospException {
		// 年月指定時の基準日を取得
		Date yearMonthTargetDate = TimeUtility.getYearMonthTargetDate(targetYear, targetMonth, mospParams);
		// 締日コードと対象日から締日マスタを取得 
		CutoffDtoInterface cutoffDto = cutoffRefer.getCutoffInfo(cutoffCode, yearMonthTargetDate);
		// 確認
		cutoffRefer.chkExistCutoff(cutoffDto, yearMonthTargetDate);
		return cutoffDto;
	}
	
	@Override
	public CutoffDtoInterface getCutoff(String cutoffCode, Date targetDate) throws MospException {
		// 締日コードと対象日から締日マスタを取得 
		CutoffDtoInterface cutoffDto = cutoffRefer.getCutoffInfo(cutoffCode, targetDate);
		// 確認
		cutoffRefer.chkExistCutoff(cutoffDto, targetDate);
		return cutoffDto;
	}
	
	@Override
	public CutoffDtoInterface getCutoffForPersonalId(String personalId, int targetYear, int targetMonth)
			throws MospException {
		// 対象個人ID及び対象日付(年月指定時の基準日)で勤怠設定情報群を取得し設定
		setCutoffSettings(personalId, TimeUtility.getYearMonthTargetDate(targetYear, targetMonth, mospParams));
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return null;
		}
		return getCutoff(cutoffDto.getCutoffCode(), targetYear, targetMonth);
	}
	
	@Override
	public CutoffDtoInterface getCutoffForPersonalId(String personalId, Date targetDate) throws MospException {
		// 対象個人ID及び対象日付(年月指定時の基準日)で勤怠設定情報群を取得し設定
		setCutoffSettings(personalId, targetDate);
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return null;
		}
		return getCutoff(cutoffDto.getCutoffCode(), targetDate);
	}
	
	@Override
	public Date getCutoffCalculationDate(String cutoffCode, int targetYear, int targetMonth) throws MospException {
		// 締日コードと対象日から締日マスタを取得 
		CutoffDtoInterface cutoffDto = getCutoff(cutoffCode, targetYear, targetMonth);
		// 締日取得
		int cutoffDate = cutoffDto.getCutoffDate();
		// 対象日付及び締日から集計日を取得
		return TimeUtility.getCutoffCalculationDate(cutoffDate, targetYear, targetMonth);
	}
	
	@Override
	public Date getCutoffTermTargetDate(String cutoffCode, int targetYear, int targetMonth) throws MospException {
		// 締日コードと対象日から締日マスタを取得 
		CutoffDtoInterface cutoffDto = getCutoff(cutoffCode, targetYear, targetMonth);
		// 締日取得
		int cutoffDate = cutoffDto.getCutoffDate();
		// 対象日付及び締日から基準日を取得
		return TimeUtility.getCutoffTermTargetDate(cutoffDate, targetYear, targetMonth);
	}
	
	@Override
	public void checkTighten(String personalId, Date targetDate, String targetName) throws MospException {
		// 対象個人ID及び対象日付で勤怠設定情報群を取得し設定
		setCutoffSettings(personalId, targetDate);
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 対象日付及び締日から対象年月日が含まれる締月を取得
		Date cutoffMonth = TimeUtility.getCutoffMonth(cutoffDto.getCutoffDate(), targetDate);
		// 社員勤怠集計管理から締状態を取得
		Integer state = totalTimeEmployeeRefer.getCutoffState(personalId, DateUtility.getYear(cutoffMonth), DateUtility
			.getMonth(cutoffMonth));
		// 締状態確認
		if (state == null || state == TimeConst.CODE_CUTOFF_STATE_NOT_TIGHT) {
			return;
		}
		// 未締でない場合
		addMonthlyTreatmentErrorMessage(cutoffMonth, targetName);
	}
	
	@Override
	public void checkTighten(String personalId, int targetYear, int targetMonth, String targetName)
			throws MospException {
		// 対象個人ID及び対象日付(年月指定時の基準日)で勤怠設定情報群を取得し設定
		setCutoffSettings(personalId, TimeUtility.getYearMonthTargetDate(targetYear, targetMonth, mospParams));
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 社員勤怠集計管理から締状態を取得
		Integer state = totalTimeEmployeeRefer.getCutoffState(personalId, targetYear, targetMonth);
		// 締状態確認
		if (state == null || state == TimeConst.CODE_CUTOFF_STATE_NOT_TIGHT) {
			return;
		}
		// 未締でない場合
		addMonthlyTreatmentErrorMessage(DateUtility.getFirstDateOfMonth(targetYear, targetMonth), targetName);
	}
	
	@Override
	public boolean isNotTighten(String personalId, Date targetDate) throws MospException {
		// 対象個人ID及び対象日付で勤怠設定情報群を取得し設定
		if (hasCutoffSettings(personalId, targetDate) == false) {
			return false;
		}
		// 対象日付及び締日から対象年月日が含まれる締月を取得
		Date cutoffMonth = TimeUtility.getCutoffMonth(cutoffDto.getCutoffDate(), targetDate);
		// 社員勤怠集計管理から締状態を取得
		Integer state = totalTimeEmployeeRefer.getCutoffState(personalId, DateUtility.getYear(cutoffMonth), DateUtility
			.getMonth(cutoffMonth));
		// 締状態確認
		if (state == null || state == TimeConst.CODE_CUTOFF_STATE_NOT_TIGHT) {
			return true;
		}
		// 未締でない場合
		return false;
	}
	
	@Override
	public Date getCutoffFirstDate(String cutoffCode, int targetYear, int targetMonth) throws MospException {
		// 締日情報取得
		CutoffDtoInterface cutoffDto = getCutoff(cutoffCode, targetYear, targetMonth);
		return TimeUtility.getCutoffFirstDate(cutoffDto.getCutoffDate(), targetYear, targetMonth);
	}
	
	@Override
	public Date getCutoffLastDate(String cutoffCode, int targetYear, int targetMonth) throws MospException {
		// 締日情報取得
		CutoffDtoInterface cutoffDto = getCutoff(cutoffCode, targetYear, targetMonth);
		return TimeUtility.getCutoffLastDate(cutoffDto.getCutoffDate(), targetYear, targetMonth);
	}
	
	/**
	 * 有効な個人IDセットを取得する。<br>
	 * @param targetDate 対象日付
	 * @param staDate 期間開始日
	 * @param endDate 期間終了日
	 * @return 有効な個人IDセット
	 * @throws MospException 人事情報の取得に失敗した場合
	 */
	protected Set<String> getActivatePersonalIdSet(Date targetDate, Date staDate, Date endDate) throws MospException {
		// 条件の設定
		humanSearch.setTargetDate(targetDate);
		humanSearch.setStartDate(staDate);
		humanSearch.setEndDate(endDate);
		humanSearch.setStateType(PlatformConst.EMPLOYEE_STATE_PRESENCE);
		// 個人IDセット取得
		return humanSearch.getPersonalIdSet();
	}
	
	@Override
	public TimeSettingDtoInterface getTimeSetting(String personalId, Date targetDate) throws MospException {
		// 対象個人ID及び対象日付で勤怠設定情報を取得
		setTimeSettings(personalId, targetDate);
		return timeSettingDto;
	}
	
}
