/*
 * 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 General Public License
 * as published by the Free Software Foundation; either version 2
 * 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package jp.mosp.kintai.kintai.action;

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

import jp.mosp.common.CommonConst;
import jp.mosp.common.common.BaseVo;
import jp.mosp.common.common.MospConst;
import jp.mosp.common.common.MospException;
import jp.mosp.common.common.MospUtility;
import jp.mosp.common.part.MosPCodePart;
import jp.mosp.common.utils.DateUtil;
import jp.mosp.common.utils.NumberUtil;
import jp.mosp.common.utils.VariousUtil;
import jp.mosp.kintai.common.action.AttendanceTotalAction;
import jp.mosp.kintai.common.part.HolidayRequestPart;
import jp.mosp.kintai.common.part.KintaiCommonPart;
import jp.mosp.kintai.common.part.LaborAgreementPart;
import jp.mosp.kintai.common.part.PaidHolidayPart;
import jp.mosp.kintai.kintai.dto.MSyukkinboDto;
import jp.mosp.kintai.kintai.vo.PaidHolidayConfirmCardVo;
import jp.mosp.kintai.payroll.dto.MYukyuDto;
import jp.mosp.kintai.workflow.dto.KtHolidayRequestDto;

/**
 * 有休確認画面(個人)の表示処理を行う。
 * <ul><li>
 * {@link #CMD_YUKYU_PERSONAL_SHOW}
 * </li></ul>
 */
public class PaidHolidayConfirmCardAction extends AttendanceTotalAction {
	
	/**
	 * 有休確認画面(個人)表示コマンド。<br><br>
	 * 有休確認画面(個人)を表示する。
	 */
	private static final String	CMD_YUKYU_PERSONAL_SHOW	= "K1300";	// 表示
																	
	
	/**
	 * コンストラクタ
	 */
	public PaidHolidayConfirmCardAction() {
		super();
	}
	
	/**
	 * アクション
	 */
	public void action() throws Exception {
		// VOの取得
		prepareVo(false);
		// 初期処理
		init();
		// コマンド毎の処理
		if (cmd.equals(CMD_YUKYU_PERSONAL_SHOW)) {
			// 表示
			show();
		} else {
			throw new MospException(MospConst.EX_CMD_INVALID);
		}
	}
	
	@Override
	protected BaseVo getSpecificVo() {
		return new PaidHolidayConfirmCardVo();
	}
	
	@Override
	protected void init() throws Exception {
		// ユーザー情報取得  社員コード摂取
		getInfo(user.getUserId());
	}
	
	@Override
	protected void show() throws Exception {
		PaidHolidayConfirmCardVo vo = (PaidHolidayConfirmCardVo)getVo();
		vo.setDefaultValues();
		// 対象年月を取得
		Date calcPayment = getCalcPayment();
		// 対象年月の承認・未承認件数作成
		double[] number = makeApprovalYukyuNumber(calcPayment);
		// 対象年月の追加・廃棄予定作成
		makeAddAndDispose(calcPayment, number[2], number[3]);
		// VOに情報を設定
		vo.setLblRemainApproved(String.valueOf(number[0]) + CommonConst.NAM_DAY);
		vo.setLblApproved(String.valueOf(number[2]) + CommonConst.NAM_DAY);
		if (MosPCodePart.afterLegalReformDate(calcPayment)) {
			vo.setLblRemainApprovedTime(NumberUtil.getNumberString(number[1], 2, 0) + CommonConst.NAM_COMMON_TIME);
			vo.setLblApprovedTime(NumberUtil.getNumberString(number[3], 2, 0) + CommonConst.NAM_COMMON_TIME);
		}
		// VOに情報を設定
		vo.setLblAttendanceCalcY(String.valueOf(MospUtility.getYear(calcPayment)));
		vo.setLblAttendanceCalcM(String.valueOf(MospUtility.getMonth(calcPayment)));
	}
	
	/**
	 * 有休承認・未承認件数作成。
	 * @param targetDate	対象年月日。
	 * @return [0]…未承認済み件数、[1]…未承認済み時間数 [2]…承認件数、[3]…承認時間数。
	 * @throws Exception 	例外処理が発生した場合。
	 */
	private double[] makeApprovalYukyuNumber(Date targetDate) throws Exception {
		// 勤怠集計対象月の出勤簿の取得
		getAttendanceList(userBasis.getKCode(), getCalcMonth());
		// 配列初期化
		double[] number = { 0.0, 0, 0.0, 0 };
		// 勤怠承認機能確認
		if (isAttendanceApprovalFunction()) {
			// 承認機能あり
			number = getApprovalNumber(targetDate);
		} else {
			// 承認機能なし
			// 出勤簿日集計データ
			for (MSyukkinboDto dto : attendanceList) {
				// 有休休暇
				if (KintaiCommonPart.isAllHoliday(dto)) {
					// 承認としてカウント
					number[0]++;
				} else if (KintaiCommonPart.isHalfHoliday(dto)) {
					// 半休
					// 承認、未承認数
					number[0] += CommonConst.NUM_HALF_DAY;
				}
			}
		}
		return number;
	}
	
	/**
	 * 承認・未承認の有給休暇申請件数取得。
	 * @param targetDate 対象年月日。
	 * @return 有休休暇(日時)の取得件数と時間数。
	 * @throws Exception 例外処理が発生した場合。
	 */
	private double[] getApprovalNumber(Date targetDate) throws Exception {
		List<KtHolidayRequestDto> list = part().holidayRequest().getKtHolidayRequestDao().findForCondition(
				userBasis.getKCode(), CommonConst.CODE_HOLIDAY_REASON_PAID, getStartDateForList(targetDate),
				getEndDateForList(targetDate), CommonConst.NUM_REQUEST_LAYER, "");
		// 配列初期化
		double[] approval = { 0.0, 0, 0.0, 0 };
		for (KtHolidayRequestDto dto : list) {
			if (part().workflow().isStatusApproved(dto.getWorkflow())) {
				// 承認済みの場合
				if (HolidayRequestPart.isPaidHolidayAll(dto)) {
					// 全休
					approval[2]++;
				} else if (HolidayRequestPart.isPaidHolidayHalf(dto)) {
					// 半休
					approval[2] += CommonConst.NUM_HALF_DAY;
				} else if (HolidayRequestPart.isPaidHolidayTime(dto)) {
					// 時間
					approval[3] += HolidayRequestPart.getHolidayTime(dto);
				}
			} else {
				// 未承認の場合
				if (HolidayRequestPart.isPaidHolidayAll(dto)) {
					// 全休
					approval[0]++;
				} else if (HolidayRequestPart.isPaidHolidayHalf(dto)) {
					// 半休
					approval[0] += CommonConst.NUM_HALF_DAY;
				} else if (HolidayRequestPart.isPaidHolidayTime(dto)) {
					// 時間
					approval[1] += HolidayRequestPart.getHolidayTime(dto);
				}
			}
		}
		return approval;
	}
	
	/**
	 * 有休追加・廃棄件数作成。
	 * @param calcPayment	給与支給日。
	 * @param useDays 対象年月の承認件数(日数)作成。
	 * @param useTime 対象年月の承認件数(時間)作成。
	 * @throws Exception	例外処理が発生した場合。
	 */
	private void makeAddAndDispose(Date calcPayment, double useDays, double useTime) throws Exception {
		if (MosPCodePart.afterLegalReformDate(calcPayment)) {
			// 改正労働基準法施行日より後日の場合
			makeAddAndDisposeNew(calcPayment, useDays, useTime);
		} else {
			// 改正労働基準法施行日より以前の場合
			makeAddAndDisposeOld(calcPayment, useDays);
		}
	}
	
	/**
	 * 有休取得(旧)。
	 * @param calcPayment 給与支給日。
	 * @param useDays 対象年月の承認件数(日数)作成。
	 * @throws Exception 例外処理が発生した場合。
	 */
	private void makeAddAndDisposeOld(Date calcPayment, double useDays) throws Exception {
		double supplyDays = 0;
		// 前月の有給情報検索
		MYukyuDto formerDto = part().paidHoliday().getYukyuInfo(userBasis.getKCode(),
				DateUtil.addMonth(calcPayment, -1));
		if (VariousUtil.isNull(formerDto)) {
			formerDto = new MYukyuDto();
		}
		// 繰越処理フラグ
		boolean isCarryForward = false;
		int carryForwardMonth = 0;
		if (part().mospcode().useProvideEmployMonth()) {
			// 入社月繰越
			carryForwardMonth = MospUtility.getMonth(part().human().getEmployDate(userBasis.getKCode()));
			if (MospUtility.getMonth(calcPayment) == carryForwardMonth) {
				isCarryForward = true;
			}
		} else {
			// 基準月繰越
			isCarryForward = part().mospcode().getCarriedForwardMonth() == MospUtility.getMonth(calcPayment);
		}
		// 支給日数
		int payment = 0;
		if (isCarryForward) {
			payment = part().paidHoliday().getCarryForwardSupplyDays(userBasis.getKCode());
		}
		// 手動支給日数分の取得
		payment += formerDto.getSyutoku();
		// 前月残日数（前年度分）
		double lastRemainDays = formerDto.getTZanZ();
		// 前月残日数（当年度分）
		double remainDays = formerDto.getTZanT();
		// 繰越処理結果取得
		Map<String, Double> map = part().paidHoliday().getOldCarryForwardInfo(lastRemainDays, remainDays, useDays,
				payment, isCarryForward);
		// 追加日数
		supplyDays += PaidHolidayPart.getMapSupplyDays(map);
		// 破棄日数
		double waste = PaidHolidayPart.getMapWasteDays(map);
		// 手動支破棄数分の取得
		waste += formerDto.getHaiki();
		// 来月有休予定数（当年度分）
		double remainThisThis = PaidHolidayPart.getMapRemainDays(map);
		// 来月有休予定数（前年度分）
		double remainThisPrev = PaidHolidayPart.getMapLastRemainDays(map);
		// VOに情報を設定
		PaidHolidayConfirmCardVo vo = (PaidHolidayConfirmCardVo)getVo();
		vo.setLblThisMGet(String.valueOf(supplyDays) + CommonConst.NAM_DAY);
		vo.setLblThisMDispose(String.valueOf(waste) + CommonConst.NAM_DAY);
		vo.setLblThisMRestLY(String.valueOf(remainThisPrev) + CommonConst.NAM_DAY);
		vo.setLblThisMRestTY(String.valueOf(remainThisThis) + CommonConst.NAM_DAY);
		vo.setLblPaidHolidayLY(String.valueOf(lastRemainDays) + CommonConst.NAM_DAY);
		vo.setLblPaidHolidayTY(String.valueOf(remainDays) + CommonConst.NAM_DAY);
	}
	
	/**
	 * 有休取得(新)。
	 * @param calcPayment 給与支給日。
	 * @param useDays 対象年月の承認件数(日数)作成。
	 * @param useTime 対象年月の承認件数(時間)作成。
	 * @throws Exception 例外処理が発生した場合。
	 */
	private void makeAddAndDisposeNew(Date calcPayment, double useDays, double useTime) throws Exception {
		double lastRemainDays = 0;
		int lastRemainTime = 0;
		double remainDays = 0;
		int remainTime = 0;
		double possibleTime = 0;
		double wasteDays = 0;
		int wasteTime = 0;
		double remainThisThisDays = 0;
		double remainThisPrevDays = 0;
		int remainThisThisTime = 0;
		int remainThisPrevTime = 0;
		double possibleThisTime = 0;
		double supplyDays = 0;
		// 繰越処理フラグ
		boolean isCarryForward = false;
		int carryForwardMonth = 0;
		if (part().mospcode().useProvideEmployMonth()) {
			// 入社月繰越
			carryForwardMonth = MospUtility.getMonth(part().human().getEmployDate(userBasis.getKCode()));
			if (MospUtility.getMonth(calcPayment) == carryForwardMonth) {
				isCarryForward = true;
			}
		} else {
			// 基準月繰越
			isCarryForward = part().mospcode().getCarriedForwardMonth() == MospUtility.getMonth(calcPayment);
		}
		// 支給日数
		int paymentDays = 0;
		int paymentTime = 0;
		if (isCarryForward) {
			paymentDays = part().paidHoliday().getCarryForwardSupplyDays(userBasis.getKCode());
		}
		// 対象期間の残日数、残時間情報(前月残数の取得)
		Map<String, Double> map3 = part().paidHoliday().getPeriodRemainInfoMap(userBasis.getKCode(),
				DateUtil.getFirstDateOfMonth(calcPayment), DateUtil.getLastDateOfMonth(calcPayment));
		lastRemainDays = PaidHolidayPart.getMapLastRemainDays(map3);
		lastRemainTime = PaidHolidayPart.getMapLastRemainHour(map3);
		remainDays = PaidHolidayPart.getMapRemainDays(map3);
		remainTime = PaidHolidayPart.getMapRemainHour(map3);
		if (part().mospcode().useHourPaidHolidayFunction()) {
			possibleTime = PaidHolidayPart.getMapPossible(map3);
		}
		// 支給日数
		if (isCarryForward) {
			// 労使協定情報
			setLaborAgreementInfo(userBasis.getKCode(), calcPayment);
			// 繰越処理結果取得
			Map<String, Double> map2 = part().paidHoliday().carryForward(lastRemainDays, lastRemainTime, remainDays,
					remainTime, paymentDays, LaborAgreementPart.getPrescribedTime(agreement));
			// 繰越月の処理(繰越による残数を取得)
			supplyDays += PaidHolidayPart.getMapSupplyDays(map2);
			paymentTime += PaidHolidayPart.getMapSupplyHour(map2);
			// 廃棄取得
			wasteDays += PaidHolidayPart.getMapWasteDays(map2);
			wasteTime += PaidHolidayPart.getMapWasteHour(map2);
			// 来月有休予定数（当年度分）
			remainThisThisDays = PaidHolidayPart.getMapRemainDays(map2);
			remainThisThisTime = PaidHolidayPart.getMapRemainHour(map2);
			if (part().mospcode().useHourPaidHolidayFunction()) {
				possibleThisTime = PaidHolidayPart.getMapPossible(map2);
			}
			// 来月有休予定数（前年度分）
			remainThisPrevDays = PaidHolidayPart.getMapLastRemainDays(map2);
			remainThisPrevTime = PaidHolidayPart.getMapLastRemainHour(map2);
		} else {
			// 対象年月の残日数、残時間情報取得(承認済みデータの控除算出済み)
			Map<String, Double> map = part().paidHoliday().getAvairablePaidHolidayMap(userBasis.getKCode(),
					MospUtility.getYear(calcPayment), MospUtility.getMonth(calcPayment));
			// 繰越月以外の処理(当月の残数を取得)
			supplyDays += PaidHolidayPart.getMapSupplyDays(map);
			paymentTime += PaidHolidayPart.getMapSupplyHour(map);
			// 廃棄取得
			wasteDays += PaidHolidayPart.getMapWasteDays(map);
			wasteTime += PaidHolidayPart.getMapWasteHour(map);
			// 来月有休予定数（前年度分）
			remainThisPrevDays = PaidHolidayPart.getMapLastRemainDays(map);
			remainThisPrevTime = PaidHolidayPart.getMapLastRemainHour(map);
			// 来月有休予定数（当年度分）
			remainThisThisDays = PaidHolidayPart.getMapRemainDays(map);
			remainThisThisTime = PaidHolidayPart.getMapRemainHour(map);
			if (part().mospcode().useHourPaidHolidayFunction()) {
				possibleThisTime = PaidHolidayPart.getMapPossible(map);
			}
		}
		PaidHolidayConfirmCardVo vo = (PaidHolidayConfirmCardVo)getVo();
		// VOに情報を設定
		vo.setLblThisMGet(String.valueOf(supplyDays) + CommonConst.NAM_DAY);
		vo.setLblThisMGetTime(String.valueOf(paymentTime) + CommonConst.NAM_COMMON_TIME);
		vo.setLblThisMDispose(String.valueOf(wasteDays) + CommonConst.NAM_DAY);
		vo.setLblThisMDisposeTime(String.valueOf(wasteTime) + CommonConst.NAM_COMMON_TIME);
		vo.setLblThisMRestLY(String.valueOf(remainThisPrevDays) + CommonConst.NAM_DAY);
		vo.setLblThisMRestTimeLY(String.valueOf(remainThisPrevTime) + CommonConst.NAM_COMMON_TIME);
		vo.setLblThisMRestTY(String.valueOf(remainThisThisDays) + CommonConst.NAM_DAY);
		vo.setLblThisMRestTimeTY(String.valueOf(remainThisThisTime) + CommonConst.NAM_COMMON_TIME);
		vo.setLblPaidHolidayLY(String.valueOf(lastRemainDays) + CommonConst.NAM_DAY);
		vo.setLblPaidHolidayTimeLY(String.valueOf(lastRemainTime) + CommonConst.NAM_COMMON_TIME);
		vo.setLblPaidHolidayTY(String.valueOf(remainDays) + CommonConst.NAM_DAY);
		vo.setLblPaidHolidayTimeTY(String.valueOf(remainTime) + CommonConst.NAM_COMMON_TIME);
		vo.setLblPaidHolidayPossibleTime(NumberUtil.getNumberString(possibleTime, 2, 0) + CommonConst.NAM_COMMON_TIME);
		vo.setLblPaidHolidayPossibleThisTime(NumberUtil.getNumberString(possibleThisTime, 2, 0)
				+ CommonConst.NAM_COMMON_TIME);
	}
	
}
