/*
 * 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.payroll.action;

import java.util.Date;
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.StringUtil;
import jp.mosp.common.utils.VariousUtil;
import jp.mosp.kintai.common.action.AttendanceTotalAction;
import jp.mosp.kintai.common.part.CalculatePart;
import jp.mosp.kintai.common.part.KintaiCompilePart;
import jp.mosp.kintai.common.part.LaborAgreementPart;
import jp.mosp.kintai.common.part.PaidHolidayPart;
import jp.mosp.kintai.dao.MYukyuDao;
import jp.mosp.kintai.dto.MYukyuDto;
import jp.mosp.kintai.payroll.dao.KdPaidHolidayDao;
import jp.mosp.kintai.payroll.dto.KdPaidHolidayDto;
import jp.mosp.payroll.dao.MKintaiKeisanDao;
import jp.mosp.payroll.dto.MKintaiDto;
import jp.mosp.payroll.dto.MKintaiKeisanDto;
import jp.mosp.payroll.vo.AttendanceCalculateEndCardVo;

/**
 * @author yoshida
 *
 */
public class AttendanceCalculateEndCardAction extends AttendanceTotalAction {
	
	// コマンド
	private static final String	CMD_CARD_SHOW	= "P1060";
	private static final String	CMD_CARD_UPDATE	= "P1061";
	

	/**
	 * コンストラクタ
	 */
	public AttendanceCalculateEndCardAction() {
		super();
	}
	
	/**
	 * アクション
	 */
	public void action() throws Exception {
		// VOの取得
		prepareVo();
		// 初期処理
		init();
		// コマンド毎の処理
		if (cmd.equals(CMD_CARD_SHOW)) {
			// 表示
			show();
		} else if (cmd.equals(CMD_CARD_UPDATE)) {
			// 更新
			update();
		} else {
			throw new MospException(MospConst.EX_CMD_INVALID);
		}
	}
	
	@Override
	protected BaseVo getSpecificVo() {
		return new AttendanceCalculateEndCardVo();
	}
	
	@Override
	protected void init() throws Exception {
		// DBコネクション取得
		getConnection();
		// PAYROLL権限確認
		confirmPayrollAuth();
	}
	
	@Override
	protected void show() throws Exception {
		AttendanceCalculateEndCardVo vo = (AttendanceCalculateEndCardVo)getVo();
		vo.setDefaultValues();
		// DTOの準備
		MKintaiKeisanDto dto = part().calculate().findForCalc();
		if (chkExistDto(dto)) {
			//	dtoがあったら、dtoをVoにセットする。
			vo.setFields(dto);
			// 計算完了の場合
			if (CalculatePart.isCalculateFinish(dto)) {
				// メッセージ用計算年月
				addErrMessage(getMessage(CommonConst.MSG_ALREADY_CALCULATE, StringUtil.combineByComma(dto.getKTNen(),
						dto.getKTTuki())));
				// モード設定
				vo.setMode(AttendanceCalculateEndCardVo.MODE_IMPOSSIBLE);
			} else {
				// モード設定
				vo.setMode(AttendanceCalculateEndCardVo.MODE_UPDATE);
			}
		} else {
			// 選択年月をセット
			vo.setLblKTnen(String.valueOf(MospUtility.getYear(DateUtil.getSystemDate())));
			vo.setLblKTtuki(String.valueOf(MospUtility.getMonth(DateUtil.getSystemDate())));
			// 計算情報無し
			addErrMessage(getMessage(MospConst.MSG_NO_DATA, ""));
			// モード設定
			vo.setMode(AttendanceCalculateEndCardVo.MODE_IMPOSSIBLE);
		}
	}
	
	@Override
	protected void update() throws Exception {
		AttendanceCalculateEndCardVo vo = (AttendanceCalculateEndCardVo)getVo();
		// DAOの準備
		MKintaiKeisanDao dao = part().calculate().getKeisanDao();
		// DTOの準備
		// 更新する前にdtoが存在するかどうかをチェック
		MKintaiKeisanDto dto = dao.findForUpdate();
		if (chkExistDto(dto)) {
			dto.setKKanryou(CommonConst.NUM_ATTENDANCE_CALCULATE_FLAG_ON);
			// 更新
			dao.update(dto);
			// DTOの再取得
			MKintaiKeisanDto retDto = dao.findForKey(dto.getKTNen());
			chkUpdate(retDto);
			// VOにセット
			vo.setFields(retDto);
			// 全所属一覧取得
			String[][] arySections = getSectionArrayAll();
			// コミットフラグ
			boolean[] flagArraySection = new boolean[arySections.length];
			for (int i = 0; i < arySections.length; i++) {
				// 所属在籍社員一覧
				String[] aryAllusers = part().human().getBasisArray(arySections[i][0], getCalcAttendance());
				boolean[] flagArrayUsers = new boolean[aryAllusers.length];
				for (int j = 0; j < aryAllusers.length; j++) {
					// 有給繰越処理
					flagArrayUsers[j] = registPaidHolidayCarryForward(aryAllusers[j], retDto);
				}
				// 繰越処理フラグ
				boolean isCarryForward = true;
				for (int j = 0; j < flagArrayUsers.length; j++) {
					if (!flagArrayUsers[j]) {
						isCarryForward = false;
						break;
					}
				}
				if (isCarryForward) {
					flagArraySection[i] = true;
				} else {
					flagArraySection[i] = false;
				}
			}
			// 繰越処理終了フラグ
			boolean isAllCarryForward = true;
			for (int k = 0; k < flagArraySection.length; k++) {
				if (!flagArraySection[k]) {
					isAllCarryForward = false;
					break;
				}
			}
			if (isAllCarryForward) {
				// メッセージ設定
				setMessage(getMessage(MospConst.MSG_UPDATE, ""));
				// コミット
				commit();
			} else {
				// 計算完了失敗メッセージ
				setMessage(MospConst.LOG_MSG_1022);
			}
		} else {
			// 計算情報無し
			addErrMessage(getMessage(MospConst.MSG_NO_DATA, ""));
		}
		// モード設定
		vo.setMode(AttendanceCalculateEndCardVo.MODE_IMPOSSIBLE);
	}
	
	/**
	 * 有給繰越処理
	 * @param kCode 社員コード
	 * @param dto 対象DTO
	 * @return 有給繰り越し処理が完了した場合true、そうでない場合false
	 * @throws Exception 	例外処理が発生した場合
	 */
	private boolean registPaidHolidayCarryForward(String kCode, MKintaiKeisanDto dto) throws Exception {
		// 処理月
		Date processMonth = DateUtil.getYearMonth(dto.getKTNen(), dto.getKTTuki());
		// 集計済みフラグ
		boolean isCompiledFlag = false;
		// 勤怠集計検索
		if (MosPCodePart.afterLegalReformDate(getEndDate(processMonth))) {
			// 改正労働基準法施行日より後日の場合
			isCompiledFlag = VariousUtil.isNotNull(compile().getKdWorkInfo(kCode, processMonth));
		} else {
			isCompiledFlag = VariousUtil.isNotNull(compile().getKintaiInfo(kCode, processMonth));
		}
		if (isCompiledFlag) {
			// 勤怠承認機能有効無効確認
			if (isAttendanceApprovalFunction()) {
				// 未承認有無検索
				if (!KintaiCompilePart.checkApproval(getAttendanceList(kCode, getCalcMonth()))) {
					// 未承認データが存在場合
					addErrMessage(getMessage(CommonConst.MSG_EXIST_NOT_APPROVED, getKName(kCode)));
					return false;
				}
			}
			// 繰越処理
			if (MosPCodePart.afterLegalReformDate(processMonth)) {
				// 改正労働基準法施行日より後日の場合
				return carryForwardAfterReform(kCode, processMonth);
			} else {
				return carryForwardBeforeReform(kCode, processMonth);
			}
		} else {
			// 勤怠集計データがない場合
			addErrMessage(getMessage(CommonConst.MSG_NO_ATTENDANCE_COMPILED, getKName(kCode)));
		}
		return false;
	}
	
	/**
	 * 改正労働基準法施行日以前の有休繰越処理
	 * @param kCode 対象社員コード
	 * @param processMonth 対象処理年月
	 * @return 有休情報が正常な場合ture、そうでない場合false
	 * @throws Exception 	例外処理が発生した場合
	 */
	private boolean carryForwardBeforeReform(String kCode, Date processMonth) throws Exception {
		// 繰越日
		Date carryDate = getCalcPayment(processMonth);
		// 処理日
		int iCarryDate = DateUtil.convDateToInteger(carryDate);
		// DAOの準備
		MYukyuDao dao = part().paidHoliday().getMYukyuDao();
		// 当月の有休情報取得
		MYukyuDto currentDto = dao.findForKey(kCode, iCarryDate);
		if (VariousUtil.isNull(currentDto)) {
			currentDto = new MYukyuDto();
			currentDto.setKCode(kCode);
			currentDto.setKyuyoYMD(iCarryDate);
		}
		// 前月の有給情報検索
		MYukyuDto formerDto = dao.findForKey(kCode, DateUtil.convDateToInteger(DateUtil.addMonth(carryDate, -1)));
		if (VariousUtil.isNull(formerDto)) {
			formerDto = new MYukyuDto();
		}
		// 有給休暇支給月
		int carryForwardMonth = 0;
		if (part().mospcode().useProvideEmployMonth()) {
			// 対象社員の入社月をセット。
			carryForwardMonth = MospUtility.getMonth(part().human().getEmployDate(kCode));
		} else {
			// 繰越月をセット。
			carryForwardMonth = part().mospcode().getCarriedForwardMonth();
		}
		// 繰越処理フラグ
		boolean isCarryForward = carryForwardMonth == MospUtility.getMonth(processMonth);
		// 支給日数
		int payment = 0;
		if (isCarryForward) {
			payment = part().paidHoliday().getCarryForwardSupplyDays(kCode);
		}
		// 前月残日数（前年度分）
		double formerLastRemain = formerDto.getTZanZ();
		// 前月残日数（当年度分）
		double formerThisRemain = formerDto.getTZanT();
		// 勤怠集計
		MKintaiDto mKintaiDto = compile().getKintaiInfo(kCode, processMonth);
		// 利用日数
		double useDays = mKintaiDto.getYukyu();
		// 繰越処理結果取得
		Map<String, Double> map = part().paidHoliday().getOldCarryForwardInfo(formerLastRemain, formerThisRemain,
				useDays, payment, isCarryForward);
		// 破棄日数
		double waste = PaidHolidayPart.getMapWasteDays(map);
		// 来月有休予定数（当年度分）
		double thisRemain = PaidHolidayPart.getMapRemainDays(map);
		// 来月有休予定数（前年度分）
		double lastRemain = PaidHolidayPart.getMapLastRemainDays(map);
		// 残日数のチェックを行う。
		if (PaidHolidayPart.checkRemainInfoMap(map)) {
			// DTOにセット
			currentDto.setZZanT(formerThisRemain);
			currentDto.setZZanZ(formerLastRemain);
			currentDto.setSyoka(useDays);
			currentDto.setSyutoku(payment);
			currentDto.setHaiki(waste);
			currentDto.setTZanT(thisRemain);
			currentDto.setTZanZ(lastRemain);
			// 登録
			if (VariousUtil.isNull(dao.findForUpdate(kCode, iCarryDate))) {
				// 登録
				dao.insert(currentDto);
			} else {
				// 更新
				dao.update(currentDto);
			}
			// 更新チェック
			chkUpdate(dao.findForKey(kCode, iCarryDate));
			// 2010年3月の場合
			if (processMonth.compareTo(DateUtil.addMonth(DateUtil.getLegalReformDate(), -1)) == 0) {
				Date nextProcess = DateUtil.addMonth(processMonth, 1);
				Date nextStart = part().calculate().getStartDate(nextProcess);
				Date nextEnd = part().calculate().getEndDate(nextProcess);
				// 翌月が2010年4月以降を含む場合
				if (PaidHolidayPart.checkAfterReformDate(nextStart, nextEnd)) {
					// 新テーブルに2010年4月から利用できる日数を発行する。
					carryForwardAfterReform(kCode, processMonth);
				}
			}
			return true;
		}
		// エラーメッセージ
		addErrMessage(getMessage("WC2056", StringUtil.combineByComma(getKName(kCode), DateUtil
			.convDateToFormatDateJPShort(carryDate))));
		return false;
	}
	
	/**
	 * 改正労働基準法施行日以降の有休繰越処理
	 * @param kCode 対象社員コード
	 * @param processMonth 対象処理年月
	 * @return 有休情報が正常な場合ture、そうでない場合false
	 * @throws Exception 	例外処理が発生した場合
	 */
	private boolean carryForwardAfterReform(String kCode, Date processMonth) throws Exception {
		// 有給休暇支給月
		int carryForwardMonth = 0;
		if (part().mospcode().useProvideEmployMonth()) {
			// 対象社員の入社月をセット。
			carryForwardMonth = MospUtility.getMonth(part().human().getEmployDate(kCode));
		} else {
			// 繰越月をセット。
			carryForwardMonth = part().mospcode().getCarriedForwardMonth();
		}
		// 繰越処理フラグ
		boolean isCarryForward = carryForwardMonth == MospUtility.getMonth(processMonth);
		// 支給日数
		int supplyDays = 0;
		// 勤怠集計月の残日数・残時間情報
		Map<String, Double> map = part().paidHoliday().getPaidHolidayInfoMap(kCode, processMonth);
		// 労使協定情報
		setLaborAgreementInfo(kCode, getEndDate(getCalcMonth()));
		if (isCarryForward) {
			supplyDays = part().paidHoliday().getCarryForwardSupplyDays(kCode);
			map = part().paidHoliday().carryForward(PaidHolidayPart.getMapLastRemainDays(map),
					PaidHolidayPart.getMapLastRemainHour(map), PaidHolidayPart.getMapRemainDays(map),
					PaidHolidayPart.getMapRemainHour(map), supplyDays, LaborAgreementPart.getPrescribedTime(agreement));
		}
		// 残日数・残時間のチェック
		if (PaidHolidayPart.checkRemainInfoMap(map)) {
			// 繰越日は処理月の翌月起算日
			Date carryDate = getStartDate(DateUtil.addMonth(processMonth, 1));
			// 月次処理のDTOの生成
			KdPaidHolidayDto monthlyDto = PaidHolidayPart.createMonthlyDto(kCode, carryDate, map);
			// DAOの準備
			KdPaidHolidayDao dao = part().paidHoliday().getPaidHolidayDao();
			// 以前の情報を論理削除する。
			KdPaidHolidayDto currentDto = dao.findForProcess(kCode, CommonConst.CODE_PROCESS_MONTHLY, carryDate);
			if (VariousUtil.isNotNull(currentDto)) {
				currentDto = dao.findForUpdate(currentDto.getPaidId(), currentDto.getKCode());
				currentDto.setDeleteFlag(MospConst.DELETE_FLAG_ON);
				dao.update(currentDto);
			}
			String maxPaidId = dao.findForMax(kCode);
			if (StringUtil.isNull(maxPaidId)) {
				maxPaidId = "0";
			}
			dao.findForUpdate(Long.parseLong(maxPaidId), kCode);
			monthlyDto.setPaidId(Long.parseLong(maxPaidId) + 1);
			// 登録
			dao.insert(monthlyDto);
			chkInsert(dao.findForKey(monthlyDto.getPaidId(), monthlyDto.getKCode()));
			return true;
		}
		// エラーメッセージ
		addErrMessage(getMessage("WC2056", StringUtil.combineByComma(getKName(kCode), DateUtil
			.convDateToFormatDateJPShort(processMonth))));
		return false;
	}
	
}
