/*
 * 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.constant.PlatformMessageConst;
import jp.mosp.platform.dao.human.EntranceDaoInterface;
import jp.mosp.platform.dto.human.EntranceDtoInterface;
import jp.mosp.time.bean.ApplicationReferenceBeanInterface;
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.constant.TimeMessageConst;
import jp.mosp.time.dao.settings.PaidHolidayDaoInterface;
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.ApplicationDtoInterface;
import jp.mosp.time.dto.settings.PaidHolidayDataDtoInterface;
import jp.mosp.time.dto.settings.PaidHolidayDtoInterface;
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 PlatformBean implements PaidHolidayInfoReferenceBeanInterface {
	
	/**
	 * 有給休暇データDAO。
	 */
	private PaidHolidayDataDaoInterface				paidHolidayDataDao;
	
	/**
	 * 有給休暇トランザクションDAO。
	 */
	private PaidHolidayTransactionDaoInterface		paidHolidayTransactionDao;
	
	/**
	 * 休暇申請参照。
	 */
	private HolidayRequestReferenceBeanInterface	holidayRequest;
	
	/**
	 * 設定適用管理参照。
	 */
	private ApplicationReferenceBeanInterface		application;
	
	/**
	 * 勤怠設定参照。
	 */
	private TimeSettingReferenceBeanInterface		timeSetting;
	
	/**
	 * 有給休暇設定DAO。
	 */
	private PaidHolidayDaoInterface					paidHolidayDao;
	
	/**
	 * 有給休暇基準日管理DAO。
	 */
	private PaidHolidayPointDateDaoInterface		paidHolidayPointDao;
	
	/**
	 * 人事入社情報DAO。
	 */
	private EntranceDaoInterface					entranceDao;
	
	/**
	 * 勤怠集計データDAO。
	 */
	private TotalTimeDataDaoInterface				totalTimeDataDao;
	
	/**
	 * 有給休暇初年度DAO。
	 */
	private PaidHolidayFirstYearDaoInterface		firstYearDao;
	

	/**
	 * {@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 {
		// 有給休暇データDAO取得
		paidHolidayDataDao = (PaidHolidayDataDaoInterface)createDao(PaidHolidayDataDaoInterface.class);
		// 有給休暇トランザクションDAO取得
		paidHolidayTransactionDao = (PaidHolidayTransactionDaoInterface)createDao(PaidHolidayTransactionDaoInterface.class);
		// 休暇申請参照クラス取得
		holidayRequest = (HolidayRequestReferenceBeanInterface)createBean(HolidayRequestReferenceBeanInterface.class);
		// 設定適用管理参照クラス取得
		application = (ApplicationReferenceBeanInterface)createBean(ApplicationReferenceBeanInterface.class);
		// 勤怠設定参照クラス取得
		timeSetting = (TimeSettingReferenceBeanInterface)createBean(TimeSettingReferenceBeanInterface.class);
		// 有給休暇設定DAO
		paidHolidayDao = (PaidHolidayDaoInterface)createDao(PaidHolidayDaoInterface.class);
		// 有給休暇基準日管理DAO
		paidHolidayPointDao = (PaidHolidayPointDateDaoInterface)createDao(PaidHolidayPointDateDaoInterface.class);
		// 人事入社情報DAO
		entranceDao = (EntranceDaoInterface)createDao(EntranceDaoInterface.class);
		// 勤怠集計データDAO
		totalTimeDataDao = (TotalTimeDataDaoInterface)createDao(TotalTimeDataDaoInterface.class);
		// 有給休暇初年度DAO
		firstYearDao = (PaidHolidayFirstYearDaoInterface)createDao(PaidHolidayFirstYearDaoInterface.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) {
			paidHolidayDataDto.setActivateDate(targetDate);
			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());
			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();
			ApplicationDtoInterface applicationDto = application.findForPerson(personalId, targetDate);
			if (applicationDto == null) {
				String errorMes1 = DateUtility.getStringYear(targetDate) + mospParams.getName("Year")
						+ DateUtility.getStringMonth(targetDate) + mospParams.getName("Month")
						+ DateUtility.getStringDay(targetDate) + mospParams.getName("Day");
				String errorMes2 = mospParams.getName("Set") + mospParams.getName("Apply")
						+ mospParams.getName("Information");
				mospParams.addErrorMessage(TimeMessageConst.MSG_SETTING_APPLICATION_DEFECT, errorMes1, errorMes2);
				return map;
			}
			int generalWorkHour = timeSetting.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, -2)) >= 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;
			ApplicationDtoInterface applicationDto = application.findForPerson(personalId, targetDate);
			if (applicationDto != null) {
				generalWorkHour = timeSetting.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, -2)) >= 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;
	}
	
	// TODO
	@Override
	public Date getNextGivingDate(String personalId) throws MospException {
		// DTOの準備
		Date systemDate = DateUtility.getSystemDate();
		// 入社日の取得
		EntranceDtoInterface entranceDto = entranceDao.findForInfo(personalId);
		if (entranceDto == null) {
			// 該当する入社日が存在しない
			String errorMes = mospParams.getName("Joined");
			mospParams.addErrorMessage(PlatformMessageConst.MSG_EMPLOYEE_IS_NOT, errorMes, null);
			return null;
		}
		
		// 設定適用を取得
		ApplicationDtoInterface applicationDto = application.findForPerson(personalId, systemDate);
		if (applicationDto == null) {
			return null;
		}
		String paidHolidayCode = applicationDto.getPaidHolidayCode();
		// 有給休暇マスタDTO
		PaidHolidayDtoInterface paidHolidayDto = paidHolidayDao.findForInfo(paidHolidayCode, systemDate);
		if (paidHolidayDto == null) {
			return null;
		}
		Date entranceDate = entranceDto.getEntranceDate();
		int entranceYear = DateUtility.getYear(entranceDate);
		int entranceMonth = DateUtility.getMonth(entranceDate);
		int paidHolidayType = paidHolidayDto.getPaidHolidayType();
		if (paidHolidayType == 0) {
			// 基準日
			int pointMonth = paidHolidayDto.getPointDateMonth();
			int pointDay = paidHolidayDto.getPointDateDay();
			PaidHolidayFirstYearDtoInterface paidHolidayFirstYearDto = firstYearDao.findForKey(paidHolidayCode,
					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 {
		// DTOの準備
		Date systemDate = DateUtility.getSystemDate();
		// 入社日の取得
		EntranceDtoInterface entranceDto = entranceDao.findForInfo(personalId);
		if (entranceDto == null) {
			// 該当する入社日が存在しない
			String errorMes = mospParams.getName("Joined");
			mospParams.addErrorMessage(PlatformMessageConst.MSG_EMPLOYEE_IS_NOT, errorMes, null);
			return 0;
		}
		// 設定適用を取得
		ApplicationDtoInterface applicationDto = application.findForPerson(personalId, systemDate);
		if (applicationDto == null) {
			return 0;
		}
		String paidHolidayCode = applicationDto.getPaidHolidayCode();
		PaidHolidayDtoInterface paidHolidayDto = paidHolidayDao.findForInfo(paidHolidayCode, systemDate);
		if (paidHolidayDto == null) {
			return 0;
		}
		Date entranceDate = entranceDto.getEntranceDate();
		int entranceYear = DateUtility.getYear(entranceDate);
		int entranceMonth = DateUtility.getMonth(entranceDate);
		int paidHolidayType = paidHolidayDto.getPaidHolidayType();
		if (paidHolidayType == 0) {
			// 基準日
			int pointMonth = paidHolidayDto.getPointDateMonth();
			int pointDay = paidHolidayDto.getPointDateDay();
			PaidHolidayFirstYearDtoInterface paidHolidayFirstYearDto = firstYearDao.findForKey(paidHolidayCode,
					paidHolidayDto.getActivateDate(), entranceMonth);
			if (paidHolidayFirstYearDto != null) {
				// 初年度付与マスタが存在する場合
				Date givingDate = DateUtility.addMonth(DateUtility.getDate(entranceYear, entranceMonth, pointDay),
						paidHolidayFirstYearDto.getGivingMonth());
				if (systemDate.before(givingDate)) {
					return paidHolidayFirstYearDto.getGivingAmount();
				}
			}
			int count = 2;
			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);
				count++;
			}
			PaidHolidayPointDateDtoInterface paidHolidayPointDateDto = paidHolidayPointDao.findForKey(paidHolidayCode,
					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 cutoffDate, int calculationYear,
			int calculationMonth) throws MospException {
		EntranceDtoInterface entranceDto = entranceDao.findForInfo(personalId);
		if (entranceDto == null) {
			return null;
		}
		ApplicationDtoInterface applicationDto = application.findForPerson(personalId, cutoffDate);
		if (applicationDto == null) {
			return null;
		}
		String paidHolidayCode = applicationDto.getPaidHolidayCode();
		PaidHolidayDtoInterface paidHolidayDto = paidHolidayDao.findForInfo(paidHolidayCode, cutoffDate);
		if (paidHolidayDto == null) {
			return null;
		}
		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);
		}
		Date entranceDate = entranceDto.getEntranceDate();
		int entranceYear = DateUtility.getYear(entranceDate);
		int entranceMonth = DateUtility.getMonth(entranceDate);
		int paidHolidayType = paidHolidayDto.getPaidHolidayType();
		if (paidHolidayType == 0) {
			// 基準日
			int pointMonth = paidHolidayDto.getPointDateMonth();
			int pointDay = paidHolidayDto.getPointDateDay();
			PaidHolidayFirstYearDtoInterface paidHolidayFirstYearDto = firstYearDao.findForKey(paidHolidayCode,
					paidHolidayDto.getActivateDate(), entranceMonth);
			if (paidHolidayFirstYearDto != null) {
				// 初年度付与マスタが存在する場合
				Date acquisitionDate = DateUtility.addMonth(DateUtility.getDate(entranceYear, entranceMonth, pointDay),
						paidHolidayFirstYearDto.getGivingMonth());
				Date temporaryDate = DateUtility.addMonth(acquisitionDate, -paidHolidayDto.getScheduleGiving());
				if (!cutoffDate.before(temporaryDate)) {
					// 締日が仮付与日より前でない場合
					return null;
				} else if (!DateUtility.addMonth(cutoffDate, 1).before(temporaryDate)) {
					dto.setActivateDate(acquisitionDate);
					dto.setAcquisitionDate(acquisitionDate);
					dto.setLimitDate(DateUtility.addDay(DateUtility.addMonth(acquisitionDate, paidHolidayFirstYearDto
						.getGivingLimit()), -1));
					dto.setHoldDay(paidHolidayFirstYearDto.getGivingAmount());
					dto.setHoldHour(0);
					if (dto.getTemporaryFlag() == 1
							&& !isOverRatio(personalId, cutoffDate, 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.getDate(entranceYear + 1, pointMonth, pointDay);
			}
			while (!pointDate.after(cutoffDate)) {
				pointDate = DateUtility.addYear(pointDate, 1);
				count++;
			}
			Date temporaryDate = DateUtility.addMonth(pointDate, -paidHolidayDto.getScheduleGiving());
			if (cutoffDate.before(temporaryDate) && !DateUtility.addMonth(cutoffDate, 1).before(temporaryDate)) {
				dto.setActivateDate(pointDate);
				dto.setAcquisitionDate(pointDate);
				if (paidHolidayDto.getMaxCarryOverYear() == MospConst.DELETE_FLAG_OFF) {
					// 有休繰越が有効の場合は期限は2年
					dto.setLimitDate(DateUtility.addYear(pointDate, 2));
				}
				if (paidHolidayDto.getMaxCarryOverYear() == MospConst.DELETE_FLAG_ON) {
					// 有休繰越が無効の場合は期限は1年
					dto.setLimitDate(DateUtility.addYear(pointDate, 1));
				}
				PaidHolidayPointDateDtoInterface paidHolidayPointDateDto = paidHolidayPointDao.findForKey(
						paidHolidayCode, paidHolidayDto.getActivateDate(), count);
				if (paidHolidayPointDateDto == null) {
					// 登録情報超過後
					dto.setHoldDay(paidHolidayDto.getGeneralPointAmount());
				} else {
					// 基準日経過回数
					dto.setHoldDay(paidHolidayPointDateDto.getPointDateAmount());
				}
				dto.setHoldHour(0);
				if (dto.getTemporaryFlag() == 1
						&& !isOverRatio(personalId, cutoffDate, 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 {
		ApplicationDtoInterface applicationDto = application.findForPerson(personalId, activateDate);
		if (applicationDto == null) {
			return true;
		}
		PaidHolidayDtoInterface paidHolidayDto = paidHolidayDao.findForInfo(applicationDto.getPaidHolidayCode(),
				activateDate);
		if (paidHolidayDto == null) {
			return true;
		}
		if (paidHolidayDto.getWorkRatio() == 0) {
			return true;
		}
		int achievement = 0;
		int totalWorkDate = 0;
		int year = calculationYear - 1;
		int month = calculationMonth + 1;
		while (year != calculationYear && month != 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) {
			return true;
		}
		// 出勤率が0%でなく且つ出勤対象日数が0日でない場合
		return ((achievement * 100) / totalWorkDate) >= 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");
	}
	
}
