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

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

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.utils.DateUtil;
import jp.mosp.common.utils.NumberUtil;
import jp.mosp.common.utils.StringUtil;
import jp.mosp.common.utils.VariousUtil;
import jp.mosp.kintai.common.action.KintaiCommonAction;
import jp.mosp.kintai.common.part.KintaiCompilePart;
import jp.mosp.kintai.common.part.SubstituteHolidayPart;
import jp.mosp.kintai.payroll.dao.KdSubstituteHolidayDao;
import jp.mosp.kintai.payroll.dto.KdSubstituteHolidayDto;
import jp.mosp.kintai.payroll.dto.KdWorkDto;
import jp.mosp.kintai.payroll.vo.PreparatoryOperationCardVo;

/**
 * @author matsusita
 *
 */
public class PreparatoryOperationCardAction extends KintaiCommonAction {
	
	// コマンド
	private static final String	CMD_OPERATION_CARD_SHOW		= "P1320";
	private static final String	CMD_OPERATION_CARD_REGIST	= "P1321";
	

	/**
	 * コンストラクタ
	 */
	public PreparatoryOperationCardAction() {
		super();
	}
	
	public void action() throws Exception {
		// VOの取得
		prepareVo();
		// 初期処理
		init();
		// コマンド毎の処理
		if (cmd.equals(CMD_OPERATION_CARD_SHOW)) {
			// 表示
			show();
		} else if (cmd.equals(CMD_OPERATION_CARD_REGIST)) {
			// 処理開始
			regist();
		} else {
			throw new MospException(MospConst.EX_CMD_INVALID);
		}
	}
	
	@Override
	protected BaseVo getSpecificVo() {
		return new PreparatoryOperationCardVo();
	}
	
	@Override
	protected void init() throws Exception {
		// PAYROLL権限確認
		confirmPayrollAuth();
		PreparatoryOperationCardVo vo = (PreparatoryOperationCardVo)getVo();
		vo.aryPltYear = StringUtil.getYearArray(MospUtility.getYear(DateUtil.getSystemDate()), 0, 1);
		vo.aryPltMonth = StringUtil.getMonthArray();
		vo.aryPltDay = StringUtil.getDayArray();
	}
	
	@Override
	protected void show() throws Exception {
		PreparatoryOperationCardVo vo = (PreparatoryOperationCardVo)getVo();
		// 初期値設定
		Date calcMonth = getCalcMonth();
		// 発生年
		vo.setHidOccurYear(String.valueOf(MospUtility.getYear(calcMonth)));
		// 発生月
		vo.setHidOccurMonth(String.valueOf(MospUtility.getMonth(calcMonth)));
		Date endDate = getEndDate(calcMonth);
		// 集計開始日
		vo.setLblStartDate(DateUtil.convDateFormatted(getStartDate(calcMonth)));
		// 集計終了日
		vo.setLblEndDate(DateUtil.convDateFormatted(endDate));
		Date nextWeek = DateUtil.addWeek(endDate, 1);
		// 締切日
		vo.setPltCloseYear(String.valueOf(MospUtility.getYear(nextWeek)));
		vo.setPltCloseMonth(String.valueOf(MospUtility.getMonth(nextWeek)));
		vo.setPltCloseDay(String.valueOf(MospUtility.getDay(nextWeek)));
		// 期限開始日
		vo.setHidLimitStartDate(DateUtil.convDateFormatted(DateUtil.addDay(endDate, 1)));
		// 有効期間
		int addMonth = 0;
		if (part().subHoliday().isPeriodOneMonth()) {
			addMonth = 1;
		} else if (part().subHoliday().isPeriodTwoMonths()) {
			addMonth = 2;
		}
		// 期限終了日
		vo.setHidLimitEndDate(DateUtil.convDateFormatted(getEndDate(DateUtil.addMonth(calcMonth, addMonth))));
	}
	
	private void regist() throws Exception {
		PreparatoryOperationCardVo vo = (PreparatoryOperationCardVo)getVo();
		vo.setParams(request);
		// パラメータの妥当性確認
		vo.validate();
		// 対象勤務集計リスト
		List<KdWorkDto> list = part().compile().getKdWorkList(vo.getHidOccurYear(), vo.getHidOccurMonth());
		// 平日優先判断
		boolean isPriorityWeekDay = part().subHoliday().isPriorityWeekDay();
		// 有効期間
		int addMonth = 0;
		if (part().subHoliday().isPeriodOneMonth()) {
			addMonth = 1;
		} else if (part().subHoliday().isPeriodTwoMonths()) {
			addMonth = 2;
		}
		Date paymentMonth = DateUtil.addMonth(DateUtil.getYearMonth(vo.getHidOccurYear(), vo.getHidOccurMonth()),
				-addMonth);
		// 決済処理対象期限開始日
		Date limitStart = DateUtil.addDay(getEndDate(paymentMonth), 1);
		// 決済処理対象期限終了日
		Date limitEnd = getEndDate(DateUtil.addMonth(paymentMonth, addMonth));
		// テーブルロックの準備
		prepareTableLock();
		// 対象テーブルの追加
		addTargetTable(KdSubstituteHolidayDao.TABLE, true);
		// テーブルロック
		lockTables();
		// 初期処理
		int initNumber = issue(list);
		// 決済処理
		int paymentNumber = liquidation(limitStart, limitEnd, isPriorityWeekDay);
		// コミット
		commit();
		// テーブルロック解除
		unLockTables();
		// メッセージ設定
		StringBuffer sb = new StringBuffer();
		sb.append("初期処理");
		sb.append(initNumber);
		sb.append("件");
		sb.append("、");
		sb.append("決済処理");
		sb.append(paymentNumber);
		sb.append("件");
		sb.append("更新");
		setMessage(getMessage(CommonConst.MSG_DONE, sb.toString()));
	}
	
	/**
	 * 初期処理
	 * @param list 対象勤怠集計リスト
	 * @return 登録件数
	 * @throws Exception 	例外処理が発生した場合
	 */
	private int issue(List<KdWorkDto> list) throws Exception {
		PreparatoryOperationCardVo vo = (PreparatoryOperationCardVo)getVo();
		int occurYear = NumberUtil.getIntParam(vo.getHidOccurYear());
		int occurMonth = NumberUtil.getIntParam(vo.getHidOccurMonth());
		Date closeDate = DateUtil.getDate(vo.getPltCloseYear(), vo.getPltCloseMonth(), vo.getPltCloseDay());
		Date limitStartDate = DateUtil.convStringDateToDate(vo.getHidLimitStartDate());
		Date limitEndDate = DateUtil.convStringDateToDate(vo.getHidLimitEndDate());
		// DAOの準備
		KdSubstituteHolidayDao dao = part().subHoliday().getKdSubstituteHolidayDao();
		// 最大値を取得
		String max = dao.findForMax();
		if (StringUtil.isNull(max)) {
			max = "-1";
		}
		long maxId = Long.parseLong(max);
		// 登録件数
		int initNumber = 0;
		for (KdWorkDto workDto : list) {
			if (KintaiCompilePart.getOver60HourOverTime(workDto) > 0) {
				// DTOの準備
				KdSubstituteHolidayDto dto = SubstituteHolidayPart.createInitalDto(workDto.getKCode(), occurYear,
						occurMonth, closeDate, limitStartDate, limitEndDate);
				// 発生年月の情報
				KdSubstituteHolidayDto currentDto = part().subHoliday().getOccurSubstituteInfo(dto.getKCode(),
						dto.getOccurYear(), dto.getOccurMonth());
				boolean insertFlag = false;
				if (VariousUtil.isNull(currentDto)) {
					// ない場合。
					insertFlag = true;
				} else if (SubstituteHolidayPart.isAttitudeInit(currentDto)) {
					// 初期状態の場合
					currentDto.setDeleteFlag(MospConst.DELETE_FLAG_ON);
					// 排他確認
					chkExclusive(currentDto, dao.findForUpdate(currentDto.getSubstituteId()));
					// データの更新
					dao.update(currentDto);
					// DTOの再取得
					chkUpdate(dao.findForKey(currentDto.getSubstituteId()));
					insertFlag = true;
				}
				if (insertFlag) {
					maxId++;
					dto.setSubstituteId(maxId);
					// 重複チェック
					chkDuplicate(dao.findForKey(dto.getSubstituteId()));
					// データの挿入
					dao.insert(dto);
					// DTOの再取得
					chkInsert(dao.findForKey(dto.getSubstituteId()));
					initNumber++;
				}
			}
		}
		return initNumber;
	}
	
	/**
	 * 決済処理
	 * @param limitStart 対象開始日
	 * @param limitEnd 対象終了日
	 * @param isPriorityWeekDay 平日優先判断
	 * @return 更新件数
	 * @throws Exception 	例外処理が発生した場合
	 */
	private int liquidation(Date limitStart, Date limitEnd, boolean isPriorityWeekDay) throws Exception {
		// 更新件数
		int paymentNumber = 0;
		// DAOの準備
		KdSubstituteHolidayDao dao = part().subHoliday().getKdSubstituteHolidayDao();
		List<KdSubstituteHolidayDto> list = dao.findForCondition(limitStart, limitEnd,
				CommonConst.CODE_DECISION_STATUS_FIXED);
		for (KdSubstituteHolidayDto dto : list) {
			int acquireTime = dto.getPaymentAcquireTime();
			int acquireHoliday = dto.getPaymentAcquireHoliday();
			int useHolidayTime = dto.getUseHolidayTime();
			int liquidationOver = 0;
			int liquidationWeek = 0;
			if (isPriorityWeekDay) {
				// 平日優先の場合
				liquidationOver = acquireTime - useHolidayTime;
				liquidationWeek = acquireHoliday;
				if (acquireTime - useHolidayTime < 0) {
					liquidationOver = 0;
					liquidationWeek = acquireHoliday + acquireTime - useHolidayTime;
				}
			} else {
				// 所定休日優先の場合
				liquidationOver = acquireTime;
				liquidationWeek = acquireHoliday - useHolidayTime;
				if (acquireHoliday - useHolidayTime < 0) {
					liquidationOver = acquireTime + acquireHoliday - useHolidayTime;
					liquidationWeek = 0;
				}
			}
			dto.setLiquidationOverTime(liquidationOver);
			dto.setLiquidationWeekHoliday(liquidationWeek);
			dto.setAcquisitionStatus(CommonConst.CODE_ACQUISITION_STATUS_FINISH);
			dto.setDecisionStatus(CommonConst.CODE_DECISION_STATUS_PAYMENT);
			// 排他確認
			chkExclusive(dto, dao.findForUpdate(dto.getSubstituteId()));
			// データの更新
			dao.update(dto);
			// DTOの再取得
			chkUpdate(dao.findForKey(dto.getSubstituteId()));
			paymentNumber++;
		}
		return paymentNumber;
	}
	
}
