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

import jp.mosp.framework.base.MospException;
import jp.mosp.framework.base.MospParams;
import jp.mosp.framework.constant.MospConst;
import jp.mosp.framework.utils.DateUtility;
import jp.mosp.platform.base.PlatformBean;
import jp.mosp.platform.bean.human.EntranceReferenceBeanInterface;
import jp.mosp.platform.constant.PlatformMessageConst;
import jp.mosp.time.base.TimeApplicationBean;
import jp.mosp.time.bean.HolidayRequestReferenceBeanInterface;
import jp.mosp.time.bean.PaidHolidayInfoReferenceBeanInterface;
import jp.mosp.time.bean.TimeSettingReferenceBeanInterface;
import jp.mosp.time.constant.TimeConst;
import jp.mosp.time.dao.settings.PaidHolidayDataDaoInterface;
import jp.mosp.time.dao.settings.PaidHolidayFirstYearDaoInterface;
import jp.mosp.time.dao.settings.PaidHolidayPointDateDaoInterface;
import jp.mosp.time.dao.settings.PaidHolidayTransactionDaoInterface;
import jp.mosp.time.dao.settings.TotalTimeDataDaoInterface;
import jp.mosp.time.dto.settings.PaidHolidayDataDtoInterface;
import jp.mosp.time.dto.settings.PaidHolidayFirstYearDtoInterface;
import jp.mosp.time.dto.settings.PaidHolidayPointDateDtoInterface;
import jp.mosp.time.dto.settings.PaidHolidayTransactionDtoInterface;
import jp.mosp.time.dto.settings.TotalTimeDataDtoInterface;
import jp.mosp.time.dto.settings.impl.TmdPaidHolidayDataDto;

/**
 * 有給休暇情報参照クラス。
 */
public class PaidHolidayInfoReferenceBean extends TimeApplicationBean implements PaidHolidayInfoReferenceBeanInterface {
	
	/**
	 * 有給休暇データDAO。
	 */
	private PaidHolidayDataDaoInterface				paidHolidayDataDao;
	
	/**
	 * 有給休暇トランザクションDAO。
	 */
	private PaidHolidayTransactionDaoInterface		paidHolidayTransactionDao;
	
	/**
	 * 休暇申請参照。
	 */
	private HolidayRequestReferenceBeanInterface	holidayRequest;
	
	/**
	 * 有給休暇基準日管理DAO。
	 */
	private PaidHolidayPointDateDaoInterface		paidHolidayPointDao;
	
	/**
	 * 勤怠集計データDAO。
	 */
	private TotalTimeDataDaoInterface				totalTimeDataDao;
	
	/**
	 * 有給休暇初年度DAO。
	 */
	private PaidHolidayFirstYearDaoInterface		firstYearDao;
	
	/**
	 * 人事入社情報参照クラス。
	 */
	protected EntranceReferenceBeanInterface		entranceRefer;
	
	/**
	 * 勤怠設定参照クラス。
	 */
	protected TimeSettingReferenceBeanInterface		timeSettingRefer;
	

	/**
	 * {@link PlatformBean#PlatformBean()}を実行する。<br>
	 */
	public PaidHolidayInfoReferenceBean() {
		super();
	}
	
	/**
	 * {@link PlatformBean#PlatformBean(MospParams, Connection)}を実行する。<br>
	 * @param mospParams MosPパラメータクラス
	 * @param connection DBコネクション
	 */
	public PaidHolidayInfoReferenceBean(MospParams mospParams, Connection connection) {
		super(mospParams, connection);
	}
	
	@Override
	public void initBean() throws MospException {
		// 継承元のBean初期化処理を実施
		super.initBean();
		// 有給休暇データDAO取得
		paidHolidayDataDao = (PaidHolidayDataDaoInterface)createDao(PaidHolidayDataDaoInterface.class);
		// 有給休暇トランザクションDAO取得
		paidHolidayTransactionDao = (PaidHolidayTransactionDaoInterface)createDao(PaidHolidayTransactionDaoInterface.class);
		// 休暇申請参照クラス取得
		holidayRequest = (HolidayRequestReferenceBeanInterface)createBean(HolidayRequestReferenceBeanInterface.class);
		// 有給休暇基準日管理DAO
		paidHolidayPointDao = (PaidHolidayPointDateDaoInterface)createDao(PaidHolidayPointDateDaoInterface.class);
		// 勤怠集計データDAO
		totalTimeDataDao = (TotalTimeDataDaoInterface)createDao(TotalTimeDataDaoInterface.class);
		// 有給休暇初年度DAO
		firstYearDao = (PaidHolidayFirstYearDaoInterface)createDao(PaidHolidayFirstYearDaoInterface.class);
		// 各種Bean準備
		entranceRefer = (EntranceReferenceBeanInterface)createBean(EntranceReferenceBeanInterface.class);
		timeSettingRefer = (TimeSettingReferenceBeanInterface)createBean(TimeSettingReferenceBeanInterface.class);
	}
	
	@Override
	public List<PaidHolidayDataDtoInterface> getPaidHolidayCalcInfo(String personalId, Date targetDate)
			throws MospException {
		List<PaidHolidayDataDtoInterface> list = new ArrayList<PaidHolidayDataDtoInterface>();
//		Date oneYearBeforeActivateDate = DateUtility.addYear(targetDate, -1);
		List<PaidHolidayDataDtoInterface> paidHolidayDataDtoList = paidHolidayDataDao.findForInfoList(personalId,
				targetDate);
		for (PaidHolidayDataDtoInterface paidHolidayDataDto : paidHolidayDataDtoList) {
			Date acquisitionDate = paidHolidayDataDto.getAcquisitionDate();
//			if (acquisitionDate.compareTo(oneYearBeforeActivateDate) >= 0) {
			// 手動付与・破棄
			List<PaidHolidayTransactionDtoInterface> paidHolidayTransactionDtoList = paidHolidayTransactionDao
				.findForList(personalId, acquisitionDate, paidHolidayDataDto.getActivateDate(), targetDate);
			for (PaidHolidayTransactionDtoInterface paidHolidayTransactionDto : paidHolidayTransactionDtoList) {
				paidHolidayDataDto.setGivingDay(paidHolidayDataDto.getGivingDay()
						+ paidHolidayTransactionDto.getGivingDay());
				paidHolidayDataDto.setGivingHour(paidHolidayDataDto.getGivingHour()
						+ paidHolidayTransactionDto.getGivingHour());
				paidHolidayDataDto.setCancelDay(paidHolidayDataDto.getCancelDay()
						+ paidHolidayTransactionDto.getCancelDay());
				paidHolidayDataDto.setCancelHour(paidHolidayDataDto.getCancelHour()
						+ paidHolidayTransactionDto.getCancelHour());
			}
			// 申請
			Map<String, Object> approvedMap = holidayRequest.getApprovedDayHour(personalId, acquisitionDate, Integer
				.parseInt(mospParams.getProperties().getCodeArray(TimeConst.CODE_HOLIDAY_TYPE, false)[0][0]),
					mospParams.getProperties().getCodeArray(TimeConst.CODE_HOLIDAY_TYPE2_WITHPAY, false)[0][0],
					paidHolidayDataDto.getActivateDate(), targetDate);
			paidHolidayDataDto.setUseDay(((Double)approvedMap.get(TimeConst.CODE_APPROVED_DAY)).doubleValue());
			paidHolidayDataDto.setUseHour(((Integer)approvedMap.get(TimeConst.CODE_APPROVED_HOUR)).intValue());
			paidHolidayDataDto.setActivateDate(targetDate);
			list.add(paidHolidayDataDto);
//			}
//			if (acquisitionDate.before(oneYearBeforeActivateDate)
//					&& acquisitionDate.compareTo(DateUtility.addYear(targetDate, -2)) >= 0) {
			// 手動付与・破棄
//				List<PaidHolidayTransactionDtoInterface> paidHolidayTransactionDtoList = paidHolidayTransactionDao
//					.findForList(personalId, acquisitionDate, paidHolidayDataDto.getActivateDate(), targetDate);
//				for (PaidHolidayTransactionDtoInterface paidHolidayTransactionDto : paidHolidayTransactionDtoList) {
//					paidHolidayDataDto.setGivingDay(paidHolidayDataDto.getGivingDay()
//							+ paidHolidayTransactionDto.getGivingDay());
//					paidHolidayDataDto.setGivingHour(paidHolidayDataDto.getGivingHour()
//							+ paidHolidayTransactionDto.getGivingHour());
//					paidHolidayDataDto.setCancelDay(paidHolidayDataDto.getCancelDay()
//							+ paidHolidayTransactionDto.getCancelDay());
//					paidHolidayDataDto.setCancelHour(paidHolidayDataDto.getCancelHour()
//							+ paidHolidayTransactionDto.getCancelHour());
//				}
			// 申請
//				Map<String, Object> approvedMap = holidayRequest
//					.getApprovedDayHour(personalId, acquisitionDate, Integer.parseInt(mospParams.getProperties()
//						.getCodeArray(TimeConst.CODE_HOLIDAY_TYPE, false)[0][0]), mospParams.getProperties()
//						.getCodeArray(TimeConst.CODE_HOLIDAY_TYPE2_WITHPAY, false)[0][0], paidHolidayDataDto
//						.getActivateDate(), targetDate);
//				paidHolidayDataDto.setUseDay(((Double)approvedMap.get(TimeConst.CODE_APPROVED_DAY)).doubleValue());
//				paidHolidayDataDto.setUseHour(((Integer)approvedMap.get(TimeConst.CODE_APPROVED_HOUR)).intValue());
//				list.add(paidHolidayDataDto);
//			}
		}
		return list;
	}
	
	@Override
	public Map<String, Object> getPaidHolidayInfo(String personalId, Date targetDate) throws MospException {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(TimeConst.CODE_ACTIVATE_DATE, targetDate);
		map.put(TimeConst.CODE_CURRENT_YEAR_DATE, 0.0);
		map.put(TimeConst.CODE_CURRENT_TIME, 0);
		map.put(TimeConst.CODE_FORMER_YEAR_DATE, 0.0);
		map.put(TimeConst.CODE_FORMER_YEAR_TIME, 0);
		map.put(TimeConst.CODE_GIVING_DATE, 0.0);
		map.put(TimeConst.CODE_GIVING_TIME, 0);
		map.put(TimeConst.CODE_CANCEL_DATE, 0.0);
		map.put(TimeConst.CODE_CANCEL_TIME, 0);
		map.put(TimeConst.CODE_USE_DATE, 0.0);
		map.put(TimeConst.CODE_USE_TIME, 0);
		// 今年度残日数
		double currentDate = 0;
		// 今年度残時間
		int currentTime = 0;
		// 前年度残日数
		double formerDate = 0;
		// 前年度残時間
		int formerTime = 0;
		// 今年度支給日数
		double currentGivingDate = 0;
		// 今年度支給時間
		int currentGivingTime = 0;
		// 前年度支給日数
		double formerGivingDate = 0;
		// 前年度支給時間
		int formerGivingTime = 0;
		// 今年度廃棄日数
		double currentCancelDate = 0;
		// 今年度廃棄時間
		int currentCancelTime = 0;
		// 前年度廃棄日数
		double formerCancelDate = 0;
		// 前年度廃棄時間
		int formerCancelTime = 0;
		// 今年度利用日数
		double currentUseDate = 0;
		// 今年度利用時間
		int currentUseTime = 0;
		// 前年度利用日数
		double formerUseDate = 0;
		// 前年度利用時間
		int formerUseTime = 0;
		Date oneYearBeforeActivateDate = DateUtility.addYear(targetDate, -1);
		List<PaidHolidayDataDtoInterface> paidHolidayDataDtoList = paidHolidayDataDao.findForInfoList(personalId,
				targetDate);
		for (PaidHolidayDataDtoInterface paidHolidayDataDto : paidHolidayDataDtoList) {
			map.put(TimeConst.CODE_ACTIVATE_DATE, paidHolidayDataDto.getActivateDate());
			Date acquisitionDate = paidHolidayDataDto.getAcquisitionDate();
			double holdDay = paidHolidayDataDto.getHoldDay();
			int holdHour = paidHolidayDataDto.getHoldHour();
			// 対象個人ID及び対象日付で勤怠設定情報群を取得し設定
			setApplicationSettings(personalId, targetDate);
			// 処理結果確認
			if (mospParams.hasErrorMessage()) {
				return map;
			}
			
			int generalWorkHour = timeSettingRefer.getGeneralWorkHour(applicationDto.getWorkSettingCode(),
					paidHolidayDataDto.getActivateDate());
			if (acquisitionDate.compareTo(oneYearBeforeActivateDate) >= 0) {
				currentGivingDate = paidHolidayDataDto.getGivingDay();
				currentGivingTime = paidHolidayDataDto.getGivingHour();
				currentCancelDate = paidHolidayDataDto.getCancelDay();
				currentCancelTime = paidHolidayDataDto.getCancelHour();
				// 手動付与・破棄
				List<PaidHolidayTransactionDtoInterface> paidHolidayTransactionDtoList = paidHolidayTransactionDao
					.findForList(personalId, acquisitionDate, paidHolidayDataDto.getActivateDate(), targetDate);
				for (PaidHolidayTransactionDtoInterface paidHolidayTransactionDto : paidHolidayTransactionDtoList) {
					currentGivingDate += paidHolidayTransactionDto.getGivingDay();
					currentGivingTime += paidHolidayTransactionDto.getGivingHour();
					currentCancelDate += paidHolidayTransactionDto.getCancelDay();
					currentCancelTime += paidHolidayTransactionDto.getCancelHour();
				}
				// 申請
				Map<String, Object> requestMap = holidayRequest.getRequestDayHour(personalId, acquisitionDate, Integer
					.parseInt(mospParams.getProperties().getCodeArray(TimeConst.CODE_HOLIDAY_TYPE, false)[0][0]),
						mospParams.getProperties().getCodeArray(TimeConst.CODE_HOLIDAY_TYPE2_WITHPAY, false)[0][0],
						paidHolidayDataDto.getActivateDate(), paidHolidayDataDto.getLimitDate());
				currentUseDate = ((Double)requestMap.get(TimeConst.CODE_REQUEST_DAY)).doubleValue();
				currentUseTime = ((Integer)requestMap.get(TimeConst.CODE_REQUEST_HOUR)).intValue();
				currentDate = holdDay + currentGivingDate - currentCancelDate - currentUseDate;
				currentTime = holdHour + currentGivingTime - currentCancelTime - currentUseTime;
				while (currentTime < 0) {
					currentDate--;
					currentTime += generalWorkHour;
				}
			}
			if (acquisitionDate.before(oneYearBeforeActivateDate)
					&& acquisitionDate.compareTo(DateUtility.addYear(targetDate, TimeConst.PAID_HOLIDAY_CALCULATE_DAY)) >= 0) {
				formerGivingDate = paidHolidayDataDto.getGivingDay();
				formerGivingTime = paidHolidayDataDto.getGivingHour();
				formerCancelDate = paidHolidayDataDto.getCancelDay();
				formerCancelTime = paidHolidayDataDto.getCancelHour();
				// 手動付与・破棄
				List<PaidHolidayTransactionDtoInterface> paidHolidayTransactionDtoList = paidHolidayTransactionDao
					.findForList(personalId, acquisitionDate, paidHolidayDataDto.getActivateDate(), targetDate);
				for (PaidHolidayTransactionDtoInterface paidHolidayTransactionDto : paidHolidayTransactionDtoList) {
					formerGivingDate += paidHolidayTransactionDto.getGivingDay();
					formerGivingTime += paidHolidayTransactionDto.getGivingHour();
					formerCancelDate += paidHolidayTransactionDto.getCancelDay();
					formerCancelTime += paidHolidayTransactionDto.getCancelHour();
				}
				// 申請
				Map<String, Object> requestMap = holidayRequest.getRequestDayHour(personalId, acquisitionDate, Integer
					.parseInt(mospParams.getProperties().getCodeArray(TimeConst.CODE_HOLIDAY_TYPE, false)[0][0]),
						mospParams.getProperties().getCodeArray(TimeConst.CODE_HOLIDAY_TYPE2_WITHPAY, false)[0][0],
						paidHolidayDataDto.getActivateDate(), paidHolidayDataDto.getLimitDate());
				formerUseDate = ((Double)requestMap.get(TimeConst.CODE_REQUEST_DAY)).doubleValue();
				formerUseTime = ((Integer)requestMap.get(TimeConst.CODE_REQUEST_HOUR)).intValue();
				formerDate = holdDay + formerGivingDate - formerCancelDate - formerUseDate;
				formerTime = holdHour + formerGivingTime - formerCancelTime - formerUseTime;
				while (formerTime < 0) {
					formerDate--;
					formerTime += generalWorkHour;
				}
			}
		}
		map.put(TimeConst.CODE_CURRENT_YEAR_DATE, currentDate);
		map.put(TimeConst.CODE_CURRENT_TIME, currentTime);
		map.put(TimeConst.CODE_FORMER_YEAR_DATE, formerDate);
		map.put(TimeConst.CODE_FORMER_YEAR_TIME, formerTime);
		map.put(TimeConst.CODE_GIVING_DATE, currentGivingDate + formerGivingDate);
		map.put(TimeConst.CODE_GIVING_TIME, currentGivingTime + formerGivingTime);
		map.put(TimeConst.CODE_CANCEL_DATE, currentCancelDate + formerCancelDate);
		map.put(TimeConst.CODE_CANCEL_TIME, currentCancelTime + formerCancelTime);
		map.put(TimeConst.CODE_USE_DATE, currentUseDate + formerUseDate);
		map.put(TimeConst.CODE_USE_TIME, currentUseTime + formerUseTime);
		return map;
	}
	
	@Override
	public Map<String, Object> getPaidHolidayPossibleRequest(String personalId, Date targetDate) throws MospException {
		Map<String, Object> map = new HashMap<String, Object>();
		// 今年度残日数
		double currentDate = 0;
		// 今年度残時間
		int currentTime = 0;
		// 前年度残日数
		double formerDate = 0;
		// 前年度残時間
		int formerTime = 0;
		// 今年度支給日数
		double currentGivingDate = 0;
		// 今年度支給時間
		int currentGivingTime = 0;
		// 前年度支給日数
		double formerGivingDate = 0;
		// 前年度支給時間
		int formerGivingTime = 0;
		// 今年度廃棄日数
		double currentCancelDate = 0;
		// 今年度廃棄時間
		int currentCancelTime = 0;
		// 前年度廃棄日数
		double formerCancelDate = 0;
		// 前年度廃棄時間
		int formerCancelTime = 0;
		// 今年度利用日数
		double currentUseDate = 0;
		// 今年度利用時間
		int currentUseTime = 0;
		// 前年度利用日数
		double formerRequestDate = 0;
		// 前年度利用時間
		int formerRequestTime = 0;
		Date oneYearBeforeActivateDate = DateUtility.addYear(targetDate, -1);
		List<PaidHolidayDataDtoInterface> paidHolidayDataDtoList = paidHolidayDataDao.findForInfoList(personalId,
				targetDate);
		for (PaidHolidayDataDtoInterface paidHolidayDataDto : paidHolidayDataDtoList) {
			Date acquisitionDate = paidHolidayDataDto.getAcquisitionDate();
			double holdDay = paidHolidayDataDto.getHoldDay();
			int holdHour = paidHolidayDataDto.getHoldHour();
			int generalWorkHour = 8;
			// 対象日付における取得対象個人IDの設定適用情報を取得し設定
			if (hasApplicationSettings(personalId, targetDate)) {
				// 所定労働時間取得(設定適用情報が存在する場合)
				generalWorkHour = timeSettingRefer.getGeneralWorkHour(applicationDto.getWorkSettingCode(),
						paidHolidayDataDto.getActivateDate());
			}
			if (acquisitionDate.compareTo(oneYearBeforeActivateDate) >= 0) {
				currentGivingDate = paidHolidayDataDto.getGivingDay();
				currentGivingTime = paidHolidayDataDto.getGivingHour();
				currentCancelDate = paidHolidayDataDto.getCancelDay();
				currentCancelTime = paidHolidayDataDto.getCancelHour();
				// 手動付与・破棄
				List<PaidHolidayTransactionDtoInterface> paidHolidayTransactionDtoList = paidHolidayTransactionDao
					.findForList(personalId, acquisitionDate, paidHolidayDataDto.getActivateDate(), targetDate);
				for (PaidHolidayTransactionDtoInterface paidHolidayTransactionDto : paidHolidayTransactionDtoList) {
					currentGivingDate += paidHolidayTransactionDto.getGivingDay();
					currentGivingTime += paidHolidayTransactionDto.getGivingHour();
					currentCancelDate += paidHolidayTransactionDto.getCancelDay();
					currentCancelTime += paidHolidayTransactionDto.getCancelHour();
				}
				// 申請
				Map<String, Object> requestMap = holidayRequest.getRequestDayHour(personalId, acquisitionDate, 1,
						Integer.toString(1), paidHolidayDataDto.getActivateDate(), paidHolidayDataDto.getLimitDate());
				currentUseDate = ((Double)requestMap.get(TimeConst.CODE_REQUEST_DAY)).doubleValue();
				currentUseTime = ((Integer)requestMap.get(TimeConst.CODE_REQUEST_HOUR)).intValue();
				currentDate = holdDay + currentGivingDate - currentCancelDate - currentUseDate;
				currentTime = holdHour + currentGivingTime - currentCancelTime - currentUseTime;
				while (currentTime < 0) {
					currentDate--;
					currentTime += generalWorkHour;
				}
				map.put(TimeConst.CODE_CURRENT_ACQUISITION_DATE_DATE, acquisitionDate);
			} else if (acquisitionDate.before(oneYearBeforeActivateDate)
					&& acquisitionDate.compareTo(DateUtility.addYear(targetDate, TimeConst.PAID_HOLIDAY_CALCULATE_DAY)) >= 0) {
				formerGivingDate = paidHolidayDataDto.getGivingDay();
				formerGivingTime = paidHolidayDataDto.getGivingHour();
				formerCancelDate = paidHolidayDataDto.getCancelDay();
				formerCancelTime = paidHolidayDataDto.getCancelHour();
				// 手動付与・破棄
				List<PaidHolidayTransactionDtoInterface> paidHolidayTransactionDtoList = paidHolidayTransactionDao
					.findForList(personalId, acquisitionDate, paidHolidayDataDto.getActivateDate(), targetDate);
				for (PaidHolidayTransactionDtoInterface paidHolidayTransactionDto : paidHolidayTransactionDtoList) {
					formerGivingDate += paidHolidayTransactionDto.getGivingDay();
					formerGivingTime += paidHolidayTransactionDto.getGivingHour();
					formerCancelDate += paidHolidayTransactionDto.getCancelDay();
					formerCancelTime += paidHolidayTransactionDto.getCancelHour();
				}
				// 申請
				Map<String, Object> requestMap = holidayRequest.getRequestDayHour(personalId, acquisitionDate, Integer
					.parseInt(mospParams.getProperties().getCodeArray(TimeConst.CODE_HOLIDAY_TYPE, false)[0][0]),
						mospParams.getProperties().getCodeArray(TimeConst.CODE_HOLIDAY_TYPE2_WITHPAY, false)[0][0],
						paidHolidayDataDto.getActivateDate(), paidHolidayDataDto.getLimitDate());
				formerRequestDate = ((Double)requestMap.get(TimeConst.CODE_REQUEST_DAY)).doubleValue();
				formerRequestTime = ((Integer)requestMap.get(TimeConst.CODE_REQUEST_HOUR)).intValue();
				formerDate = holdDay + formerGivingDate - formerCancelDate - formerRequestDate;
				formerTime = holdHour + formerGivingTime - formerCancelTime - formerRequestTime;
				while (formerTime < 0) {
					formerDate--;
					formerTime += generalWorkHour;
				}
				map.put(TimeConst.CODE_FORMER_ACQUISITION_DATE_DATE, acquisitionDate);
			}
		}
		map.put(TimeConst.CODE_CURRENT_YEAR_DATE, currentDate);
		map.put(TimeConst.CODE_CURRENT_TIME, currentTime);
		map.put(TimeConst.CODE_FORMER_YEAR_DATE, formerDate);
		map.put(TimeConst.CODE_FORMER_YEAR_TIME, formerTime);
		map.put(TimeConst.CODE_GIVING_DATE, currentGivingDate + formerGivingDate);
		map.put(TimeConst.CODE_GIVING_TIME, currentGivingTime + formerGivingTime);
		map.put(TimeConst.CODE_CANCEL_DATE, currentCancelDate + formerCancelDate);
		map.put(TimeConst.CODE_CANCEL_TIME, currentCancelTime + formerCancelTime);
//		map.put(TimeConst.CODE_USE_DATE, currentUseDate + formerRequestDate);
//		map.put(TimeConst.CODE_USE_TIME, currentUseTime + formerRequestTime);
		return map;
	}
	
	@Override
	public Date getNextGivingDate(String personalId) throws MospException {
		// システム日付準備
		Date systemDate = DateUtility.getSystemDate();
		// 対象個人ID及び対象日付で有給休暇設定情報を取得し設定
		if (hasPaidHolidaySettings(personalId, systemDate) == false) {
			// 有給休暇情報が取得できない場合
			return null;
		}
		// 入社日の取得
		Date entranceDate = entranceRefer.getEntranceDate(personalId);
		if (entranceDate == null) {
			// 該当する入社日が存在しない
			String errorMes = mospParams.getName("Joined");
			mospParams.addErrorMessage(PlatformMessageConst.MSG_EMPLOYEE_IS_NOT, errorMes, null);
			return null;
		}
		int entranceYear = DateUtility.getYear(entranceDate);
		int entranceMonth = DateUtility.getMonth(entranceDate);
		int paidHolidayType = paidHolidayDto.getPaidHolidayType();
		if (paidHolidayType == TimeConst.CODE_PAID_HOLIDAY_TYPE_STANDARDSDAY) {
			// 基準日
			int pointMonth = paidHolidayDto.getPointDateMonth();
			int pointDay = paidHolidayDto.getPointDateDay();
			PaidHolidayFirstYearDtoInterface paidHolidayFirstYearDto = firstYearDao.findForKey(paidHolidayDto
				.getPaidHolidayCode(), paidHolidayDto.getActivateDate(), entranceMonth);
			if (paidHolidayFirstYearDto != null) {
				// 初年度付与マスタが存在する場合
				Date givingDate = DateUtility.addMonth(DateUtility.getDate(entranceYear, entranceMonth, pointDay),
						paidHolidayFirstYearDto.getGivingMonth());
				if (systemDate.before(givingDate)) {
					return givingDate;
				}
			}
			Date pointDate = DateUtility.getDate(entranceYear, pointMonth, pointDay);
			if (!entranceDate.before(pointDate)) {
				pointDate = DateUtility.getDate(entranceYear + 1, pointMonth, pointDay);
			}
			while (!pointDate.after(systemDate)) {
				pointDate = DateUtility.addYear(pointDate, 1);
			}
			return pointDate;
		} else if (paidHolidayType == 1) {
			// TODO 入社月
			return null;
		} else if (paidHolidayType == 2) {
			// TODO 入社日
			return null;
		}
		return null;
	}
	
	@Override
	public int getNextGivingDay(String personalId) throws MospException {
		// システム日付準備
		Date systemDate = DateUtility.getSystemDate();
		// 対象個人ID及び対象日付で有給休暇設定情報を取得し設定
		if (hasPaidHolidaySettings(personalId, systemDate) == false) {
			// 有給休暇情報が取得できない場合
			return 0;
		}
		// 入社日の取得
		Date entranceDate = entranceRefer.getEntranceDate(personalId);
		if (entranceDate == null) {
			// 該当する入社日が存在しない
			String errorMes = mospParams.getName("Joined");
			mospParams.addErrorMessage(PlatformMessageConst.MSG_EMPLOYEE_IS_NOT, errorMes, null);
			return 0;
		}
		// 入社年月取得
		int entranceYear = DateUtility.getYear(entranceDate);
		int entranceMonth = DateUtility.getMonth(entranceDate);
		// 付与区分取得(有給休暇設定)
		int paidHolidayType = paidHolidayDto.getPaidHolidayType();
		if (paidHolidayType == TimeConst.CODE_PAID_HOLIDAY_TYPE_STANDARDSDAY) {
			// 基準日
			int pointMonth = paidHolidayDto.getPointDateMonth();
			int pointDay = paidHolidayDto.getPointDateDay();
			// 初年度付与日準備
			Date firstYearGivingDate = null;
			// 初年度付与情報取得
			PaidHolidayFirstYearDtoInterface paidHolidayFirstYearDto = firstYearDao.findForKey(paidHolidayDto
				.getPaidHolidayCode(), paidHolidayDto.getActivateDate(), entranceMonth);
			// 初年度付与情報確認			
			if (paidHolidayFirstYearDto != null) {
				// 初年度付与日設定
				firstYearGivingDate = DateUtility.addMonth(DateUtility.getDate(entranceYear, entranceMonth, pointDay),
						paidHolidayFirstYearDto.getGivingMonth());
				// 初年度付与日確認
				if (systemDate.before(firstYearGivingDate)) {
					// 初年度付与日数取得
					return paidHolidayFirstYearDto.getGivingAmount();
				}
			}
			// 基準日経過回数準備
			int count = 2;
			// 基準日準備
			Date pointDate = DateUtility.getDate(entranceYear, pointMonth, pointDay);
			if (!entranceDate.before(pointDate)) {
				pointDate = DateUtility.getDate(entranceYear + 1, pointMonth, pointDay);
			}
			// 初年度付与日確認
			if (firstYearGivingDate != null && firstYearGivingDate.compareTo(pointDate) == 0) {
				// 1年加算(初年度付与日と基準日が同じ場合)
				pointDate = DateUtility.addYear(pointDate, 1);
			}
			// 基準日経過回数設定
			while (!pointDate.after(systemDate)) {
				pointDate = DateUtility.addYear(pointDate, 1);
				count++;
			}
			// 基準日経過回数から有給休暇基準日管理情報を取得
			PaidHolidayPointDateDtoInterface paidHolidayPointDateDto = paidHolidayPointDao.findForKey(paidHolidayDto
				.getPaidHolidayCode(), paidHolidayDto.getActivateDate(), count);
			if (paidHolidayPointDateDto == null) {
				// 登録情報超過後
				return paidHolidayDto.getGeneralPointAmount();
			} else {
				// 基準日経過回数
				return paidHolidayPointDateDto.getPointDateAmount();
			}
		} else if (paidHolidayType == 1) {
			// TODO 入社月
			return 0;
		} else if (paidHolidayType == 2) {
			// TODO 入社日
			return 0;
		}
		return 0;
	}
	
	@Override
	public Date getNextManualGivingDate(String personalId) throws MospException {
		// 個人ID及びシステム日付で有給休暇トランザクション情報リストを取得
		List<PaidHolidayTransactionDtoInterface> list = paidHolidayTransactionDao.findForNextGiving(personalId,
				getSystemDate());
		// リスト確認
		if (list.isEmpty()) {
			return null;
		}
		// 直近の有給休暇トランザクション情報から付与日を取得
		return list.get(0).getActivateDate();
	}
	
	@Override
	public String getNextManualGivingDaysAndHours(String personalId) throws MospException {
		// 次回付与予定日を取得
		Date activateDate = getNextManualGivingDate(personalId);
		if (activateDate == null) {
			return null;
		}
		// 直近の有給休暇トランザクション情報を取得
		List<PaidHolidayTransactionDtoInterface> list = paidHolidayTransactionDao.findForList(personalId, activateDate);
		// 日数及び時間を準備
		double givingDays = 0D;
		int givingHours = 0;
		// 日数及び時間を加算
		for (PaidHolidayTransactionDtoInterface dto : list) {
			givingDays += dto.getGivingDay();
			givingDays -= dto.getCancelDay();
			givingHours += dto.getGivingHour();
			givingHours -= dto.getCancelHour();
		}
		// 日数及び時間を文字列に変換
		StringBuffer sb = new StringBuffer();
		sb.append(getStringDays(givingDays));
		sb.append(getDayNaming());
		if (givingHours != 0) {
			sb.append(givingHours);
			sb.append(getTimeNaming());
		}
		return sb.toString();
	}
	
	@Override
	public List<PaidHolidayDataDtoInterface> getPaidHolidayNextMonthInfo(String personalId, Date cutoffDate,
			int calculationYear, int calculationMonth, List<PaidHolidayDataDtoInterface> list) throws MospException {
		List<PaidHolidayDataDtoInterface> paidHolidayDataList = new ArrayList<PaidHolidayDataDtoInterface>();
		for (PaidHolidayDataDtoInterface dto : list) {
			if (dto.getLimitDate().after(cutoffDate)) {
				Date acquisitionDate = dto.getAcquisitionDate();
				if (dto.getTemporaryFlag() == 0 && cutoffDate.before(acquisitionDate)
						&& DateUtility.addMonth(cutoffDate, 1).compareTo(acquisitionDate) >= 0) {
					// 仮付与フラグが有効の場合
					if (!isOverRatio(personalId, cutoffDate, calculationYear, calculationMonth)) {
						// 出勤率が下回っていたら保有日数を0とする
						dto.setHoldDay(0);
					}
					// 仮付与フラグを無効とする
					dto.setTemporaryFlag(1);
				}
				// 有効日に締日の翌日をセットする
				dto.setActivateDate(DateUtility.addDay(cutoffDate, 1));
				dto.setHoldDay(dto.getHoldDay() + dto.getGivingDay() - dto.getCancelDay() - dto.getUseDay());
				dto.setHoldHour(dto.getHoldHour() + dto.getGivingHour() - dto.getCancelHour() - dto.getUseHour());
				dto.setGivingDay(0);
				dto.setGivingHour(0);
				dto.setCancelDay(0);
				dto.setCancelHour(0);
				dto.setUseDay(0);
				dto.setUseHour(0);
				paidHolidayDataList.add(dto);
			}
		}
		return paidHolidayDataList;
	}
	
	@Override
	public double getExpirationDay(List<PaidHolidayDataDtoInterface> list, Date cutoffDate) {
		for (PaidHolidayDataDtoInterface dto : list) {
			if (dto.getLimitDate().compareTo(cutoffDate) <= 0) {
				return dto.getHoldDay() + dto.getGivingDay() - dto.getCancelDay() - dto.getUseDay();
			}
		}
		return 0;
	}
	
	@Override
	public PaidHolidayDataDtoInterface getNewPaidHolidayInfo(String personalId, Date cutoffLastDate,
			int calculationYear, int calculationMonth) throws MospException {
		// 対象個人ID及び対象日付で有給休暇設定情報を取得し設定
		if (hasPaidHolidaySettings(personalId, cutoffLastDate) == false) {
			// 有給休暇情報が取得できない場合
			return null;
		}
		// 入社日取得及び確認
		Date entranceDate = entranceRefer.getEntranceDate(personalId);
		if (entranceDate == null) {
			return null;
		}
		// 入社年月取得
		int entranceYear = DateUtility.getYear(entranceDate);
		int entranceMonth = DateUtility.getMonth(entranceDate);
		// 有給休暇データ準備
		PaidHolidayDataDtoInterface dto = new TmdPaidHolidayDataDto();
		// 有給休暇データ初期設定
		dto.setPersonalId(personalId);
		dto.setHoldDay(0);
		dto.setHoldHour(0);
		dto.setGivingDay(0);
		dto.setGivingHour(0);
		dto.setCancelDay(0);
		dto.setCancelHour(0);
		dto.setUseDay(0);
		dto.setUseHour(0);
		dto.setTemporaryFlag(1);
		// 仮付与日確認
		if (paidHolidayDto.getScheduleGiving() != 0) {
			// 仮付与日が0でない場合は仮付与フラグを有効にする
			dto.setTemporaryFlag(0);
		}
		// 付与区分取得
		int paidHolidayType = paidHolidayDto.getPaidHolidayType();
		// 付与区分確認
		if (paidHolidayType == TimeConst.CODE_PAID_HOLIDAY_TYPE_STANDARDSDAY) {
			// 基準日
			int pointMonth = paidHolidayDto.getPointDateMonth();
			int pointDay = paidHolidayDto.getPointDateDay();
			// 初年度付与日準備
			Date firstYearGivingDate = null;
			// 有給休暇初年度情報取得
			PaidHolidayFirstYearDtoInterface paidHolidayFirstYearDto = firstYearDao.findForKey(paidHolidayDto
				.getPaidHolidayCode(), paidHolidayDto.getActivateDate(), entranceMonth);
			// 有給休暇初年度情報確認
			if (paidHolidayFirstYearDto != null && paidHolidayFirstYearDto.getGivingAmount() != 0) {
				// 初年度付与マスタが存在し且つ付与日数が0でない場合
				// 初年度付与日取得(入社月の基準日から付与月を加算)
				firstYearGivingDate = DateUtility.addMonth(DateUtility.getDate(entranceYear, entranceMonth, pointDay),
						paidHolidayFirstYearDto.getGivingMonth());
				// 仮付与日準備
				Date temporaryDate = DateUtility.addMonth(firstYearGivingDate, -paidHolidayDto.getScheduleGiving());
				// 締期間最終日及び仮付与日確認
				if (cutoffLastDate.before(temporaryDate)
						&& !DateUtility.addMonth(cutoffLastDate, 1).before(temporaryDate)) {
					dto.setActivateDate(firstYearGivingDate);
					dto.setAcquisitionDate(firstYearGivingDate);
					dto.setLimitDate(DateUtility.addDay(DateUtility.addMonth(firstYearGivingDate,
							paidHolidayFirstYearDto.getGivingLimit()), -1));
					dto.setHoldDay(paidHolidayFirstYearDto.getGivingAmount());
					dto.setHoldHour(0);
					if (dto.getTemporaryFlag() == 1
							&& !isOverRatio(personalId, cutoffLastDate, calculationYear, calculationMonth)) {
						// 仮付与フラグが無効で且つ出勤率が下回っている場合は保有数に0をセットする
						dto.setHoldDay(0);
						dto.setHoldHour(0);
					}
					return dto;
				}
			}
			// 基準日経過回数準備
			int count = 2;
			// 基準日準備
			Date pointDate = DateUtility.getDate(entranceYear, pointMonth, pointDay);
			if (!entranceDate.before(pointDate)) {
				pointDate = DateUtility.addYear(pointDate, 1);
			}
			// 初年度付与日確認
			if (firstYearGivingDate != null && firstYearGivingDate.compareTo(pointDate) == 0) {
				// 1年加算(初年度付与日と基準日が同じ場合)
				pointDate = DateUtility.addYear(pointDate, 1);
			}
			// 基準日回数設定
			while (!pointDate.after(cutoffLastDate)) {
				pointDate = DateUtility.addYear(pointDate, 1);
				count++;
			}
			Date temporaryDate = DateUtility.addMonth(pointDate, -paidHolidayDto.getScheduleGiving());
			if (cutoffLastDate.before(temporaryDate) && !DateUtility.addMonth(cutoffLastDate, 1).before(temporaryDate)) {
				dto.setActivateDate(pointDate);
				dto.setAcquisitionDate(pointDate);
				int limit = 1;
				if (paidHolidayDto.getMaxCarryOverYear() == MospConst.DELETE_FLAG_ON) {
					// 有休繰越が無効の場合は期限は1年
					limit = 1;
				} else if (paidHolidayDto.getMaxCarryOverYear() == MospConst.DELETE_FLAG_OFF) {
					// 有休繰越が有効の場合は期限は2年
					limit = 2;
				}
				dto.setLimitDate(DateUtility.addDay(DateUtility.addYear(pointDate, limit), -1));
				PaidHolidayPointDateDtoInterface paidHolidayPointDateDto = paidHolidayPointDao.findForKey(
						paidHolidayDto.getPaidHolidayCode(), paidHolidayDto.getActivateDate(), count);
				if (paidHolidayPointDateDto == null) {
					// 登録情報超過後
					dto.setHoldDay(paidHolidayDto.getGeneralPointAmount());
				} else {
					// 基準日経過回数
					dto.setHoldDay(paidHolidayPointDateDto.getPointDateAmount());
				}
				dto.setHoldHour(0);
				if (dto.getTemporaryFlag() == 1
						&& !isOverRatio(personalId, cutoffLastDate, calculationYear, calculationMonth)) {
					// 仮付与フラグが無効で且つ出勤率が下回っている場合は保有数に0をセットする
					dto.setHoldDay(0);
					dto.setHoldHour(0);
				}
				return dto;
			} else {
				return null;
			}
		} else if (paidHolidayType == 1) {
			// TODO 入社月
			return null;
		} else if (paidHolidayType == 2) {
			// TODO 入社日
			return null;
		}
		return null;
	}
	
	/**
	 * 設定した出勤率以上かどうか判断。
	 * @param personalId 個人ID
	 * @param activateDate 有効日
	 * @param calculationYear 集計年
	 * @param calculationMonth 集計月
	 * @return 出勤率以上の場合はtrue、そうでない場合はfalse
	 * @throws MospException  インスタンスの取得或いはSQL実行に失敗した場合
	 */
	protected boolean isOverRatio(String personalId, Date activateDate, int calculationYear, int calculationMonth)
			throws MospException {
		// 対象個人ID及び対象日付で有給休暇設定情報を取得し設定
		if (hasPaidHolidaySettings(personalId, activateDate) == false) {
			// 有給休暇情報が取得できない場合
			return false;
		}
		int achievement = 0;
		int totalWorkDate = 0;
		int year = calculationYear - 1;
		int month = calculationMonth + 1;
		while (year * 12 + month <= calculationYear * 12 + calculationMonth) {
			TotalTimeDataDtoInterface totalTimeDataDto = totalTimeDataDao.findForKey(personalId, year, month);
			if (totalTimeDataDto != null) {
				achievement += totalTimeDataDto.getTimesAchievement();
				totalWorkDate += totalTimeDataDto.getTimesTotalWorkDate();
			}
			month++;
			if (month == 13) {
				year++;
				month = 1;
			}
		}
		if (totalWorkDate == 0) {
			// 出勤対象日数が0の場合
			return false;
		}
		if (paidHolidayDto.getWorkRatio() == 0) {
			// 出勤率が0%の場合
			return true;
		}
		// 出勤率が0%でなく且つ出勤対象日数が0日でない場合
		double rate = (achievement * 100) / totalWorkDate;
		return rate >= paidHolidayDto.getWorkRatio();
	}
	
	/**
	 * 日数文字列を取得する。<br>
	 * 日数を文字列(小数点以下1桁)で表す。<br>
	 * @param days 対象日数
	 * @return 日数文字列
	 */
	protected String getStringDays(double days) {
		DecimalFormat df = new DecimalFormat("0.#");
		// 日付文字列取得
		return df.format(days);
	}
	
	/**
	 * 日名称を取得する。<br>
	 * @return 日名称
	 */
	protected String getDayNaming() {
		return mospParams.getName("Day");
	}
	
	/**
	 * 時間名称を取得する。<br>
	 * @return 時間名称
	 */
	protected String getTimeNaming() {
		return mospParams.getName("Time");
	}
	
}
