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

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

import jp.mosp.framework.base.BaseVo;
import jp.mosp.framework.base.MospException;
import jp.mosp.framework.utils.DateUtility;
import jp.mosp.time.base.TimeAction;
import jp.mosp.time.bean.CutoffUtilBeanInterface;
import jp.mosp.time.bean.PaidHolidayInfoReferenceBeanInterface;
import jp.mosp.time.constant.TimeConst;
import jp.mosp.time.dto.settings.ApplicationDtoInterface;
import jp.mosp.time.dto.settings.CutoffDtoInterface;
import jp.mosp.time.dto.settings.PaidHolidayDataDtoInterface;
import jp.mosp.time.settings.vo.PaidHolidayReferenceVo;
import jp.mosp.time.utils.TimeUtility;

/**
 * 個別有給休暇確認画面。<br>
 * 従業員別に有給休暇に関する情報を確認する。<br>
 * 以下のコマンドを扱う。<br>
 * <ul><li>
 * {@link #CMD_SELECT_SHOW}
 * </li><li>
 * {@link #CMD_SEARCH}
 * </li><li>
 * {@link #CMD_RE_SHOW}
 * </li></ul>
 */
public class PaidHolidayReferenceAction extends TimeAction {
	
	/**
	 * 選択表示コマンド。<br>
	 * <br>
	 * 選択表示コマンド。有給休暇手動付与画面で選択した従業員のサーバ日付時点から1年間の有給休暇に関する詳細情報を表示する。<br>
	 */
	public static final String	CMD_SELECT_SHOW	= "TM4431";
	
	/**
	 * 検索コマンド。<br>
	 * <br>
	 * 検索コマンド。有効日入力欄に入力された日付を基にその日付から1年間分の有給休暇関連の詳細情報を表示する。<br>
	 */
	public static final String	CMD_SEARCH		= "TM4432";
	
	/**
	 * 再表示コマンド。<br>
	 * <br>
	 * 個別有給休暇確認画面の再表示を行う。<br>
	 */
	public static final String	CMD_RE_SHOW		= "TM4433";
	
	/**
	 * 一覧結果出力用領域。（残日数(前)）<br>
	 * <br>
	 * 一覧結果に出力する残日数(前)を保存する領域。<br>
	 */
	public static double		formerDate		= 0;
	
	/**
	 * 一覧結果出力用領域。（残時間(前)）<br>
	 * <br>
	 * 一覧結果に出力する残時間(前)を保存する領域。<br>
	 */
	public static int			formerTime		= 0;
	
	/**
	 * 一覧結果出力用領域。（残日数(今)）<br>
	 * <br>
	 * 一覧結果に出力する残日数(今)を保存する領域。<br>
	 */
	public static double		currentDate		= 0;
	
	/**
	 * 一覧結果出力用領域。（残時間(今)）<br>
	 * <br>
	 * 一覧結果に出力する残時間(今)を保存する領域。<br>
	 */
	public static int			currentTime		= 0;
	
	/**
	 * 一覧結果出力用領域。（支給日数）<br>
	 * <br>
	 * 一覧結果に出力する支給日数を保存する領域。<br>
	 */
	public static double		givingDate		= 0;
	
	/**
	 * 一覧結果出力用領域。（支給時間）<br>
	 * <br>
	 * 一覧結果に出力する支給時間を保存する領域。<br>
	 */
	public static int			givingTime		= 0;
	
	/**
	 * 一覧結果出力用領域。（廃棄日数）<br>
	 * <br>
	 * 一覧結果に出力する廃棄日数を保存する領域。<br>
	 */
	public static double		cancelDate		= 0;
	
	/**
	 * 一覧結果出力用領域。（廃棄時間）<br>
	 * <br>
	 * 一覧結果に出力する廃棄時間を保存する領域。<br>
	 */
	public static int			cancelTime		= 0;
	
	/**
	 * 一覧結果出力用領域。（利用日数）<br>
	 * <br>
	 * 一覧結果に出力する利用日数を保存する領域。<br>
	 */
	public static double		useDate			= 0;
	
	/**
	 * 一覧結果出力用領域。（利用時間）<br>
	 * <br>
	 * 一覧結果に出力する利用時間を保存する領域。<br>
	 */
	public static int			useTime			= 0;
	

	/**
	 * {@link TimeAction#TimeAction()}を実行する。<br>
	 */
	public PaidHolidayReferenceAction() {
		super();
		// パンくずリスト用コマンド設定
		topicPathCommand = CMD_RE_SHOW;
	}
	
	@Override
	protected BaseVo getSpecificVo() {
		return new PaidHolidayReferenceVo();
	}
	
	@Override
	public void action() throws MospException {
		// コマンド毎の処理
		if (mospParams.getCommand().equals(CMD_SELECT_SHOW)) {
			prepareVo(false, false);
			// 選択表示
			show();
		} else if (mospParams.getCommand().equals(CMD_SEARCH)) {
			prepareVo();
			// 検索
			search();
		} else if (mospParams.getCommand().equals(CMD_RE_SHOW)) {
			prepareVo(true, false);
			// 再表示
			show();
		}
	}
	
	/**
	 * 初期表示処理を行う。<br>
	 * @throws MospException 例外処理発生時
	 */
	protected void show() throws MospException {
		// 初期値設定
		setDefaultValues();
		// 有給休暇情報表示
		setDefaultList();
		// 年月別表示
		setList();
	}
	
	/**
	 * @throws MospException 例外処理が発生した場合 
	 */
	protected void search() throws MospException {
		// 年月別表示
		setList();
	}
	
	/**
	 * 初期値を設定する。<br>
	 * @throws MospException 例外処理発生時
	 */
	public void setDefaultValues() throws MospException {
		// VO準備
		PaidHolidayReferenceVo vo = (PaidHolidayReferenceVo)mospParams.getVo();
		// 個人ID取得
		String personalId = getTargetPersonalId();
		// システム日付取得
		Date systemDate = DateUtility.getSystemDate();
		// 社員情報の設定
		if (personalId != null && personalId.isEmpty() == false) {
			// 個人ID取得
			setEmployeeInfo(personalId, systemDate);
		} else {
			// 個人ID取得
			setEmployeeInfo(vo.getPersonalId(), systemDate);
		}
		// 対象年月をVOに設定
		vo.setPltSelectYear(String.valueOf(TimeUtility.getFiscalYear(systemDate, mospParams)));
		vo.setAryPltSelectYear(getYearArray(TimeUtility.getFiscalYear(systemDate, mospParams)));
		vo.setTxtLblActivateYear(DateUtility.getStringYear(systemDate));
		vo.setTxtLblActivateMonth(DateUtility.getStringMonth(systemDate));
		vo.setTxtLblActivateDay(DateUtility.getStringDay(systemDate));
		vo.setTxtActiveDate(DateUtility.getStringDate(systemDate));
	}
	
	/**
	 * 初期に表示される有給休暇情報を設定する。<br>
	 * @throws MospException 例外発生時
	 */
	public void setDefaultList() throws MospException {
		// VO準備
		PaidHolidayReferenceVo vo = (PaidHolidayReferenceVo)mospParams.getVo();
		// 有給休暇情報データ準備
		PaidHolidayInfoReferenceBeanInterface getInfo = timeReference().paidHolidayInfo();
		// マップ準備
		Map<String, Object> map = null;
		if (getTransferredCode() != null) {
			map = getInfo.getPaidHolidayInfo(vo.getPersonalId(), DateUtility.getSystemDate());
		} else {
			map = getInfo.getPaidHolidayInfo(vo.getPersonalId(), DateUtility.getSystemDate());
		}
		// 休暇情報設定
		// 情報表示欄の設定
		vo.setLblFormerDate(String.valueOf(map.get(TimeConst.CODE_FORMER_YEAR_DATE)));
		vo.setLblFormerTime(String.valueOf(map.get(TimeConst.CODE_FORMER_YEAR_TIME)));
		vo.setLblDate(String.valueOf(map.get(TimeConst.CODE_CURRENT_YEAR_DATE)));
		vo.setLblTime(String.valueOf(map.get(TimeConst.CODE_CURRENT_TIME)));
		vo.setLblGivingDate(String.valueOf(map.get(TimeConst.CODE_GIVING_DATE)));
		vo.setLblGivingTime(String.valueOf(map.get(TimeConst.CODE_GIVING_TIME)));
		vo.setLblCancelDate(String.valueOf(map.get(TimeConst.CODE_CANCEL_DATE)));
		vo.setLblCancelTime(String.valueOf(map.get(TimeConst.CODE_CANCEL_TIME)));
		vo.setLblUseDate(String.valueOf(map.get(TimeConst.CODE_USE_DATE)));
		vo.setLblUseTime(String.valueOf(map.get(TimeConst.CODE_USE_TIME)));
	}
	
	/**
	 * 設定された有効年から取得した年月別の有給休暇情報を設定する。<br>
	 * @param firstDate 対象年月における初日
	 * @param lastDate 対象年月における終日
	 * @throws MospException 例外発生時
	 */
	private void setLblDate(Date firstDate, Date lastDate) throws MospException {
		// VO準備
		PaidHolidayReferenceVo vo = (PaidHolidayReferenceVo)mospParams.getVo();
		List<PaidHolidayDataDtoInterface> list = timeReference().paidHolidayData().getPaidHolidayDataInfoList(
				vo.getPersonalId(), firstDate, lastDate);
		// 領域の初期化
		formerDate = 0;
		currentDate = 0;
		givingDate = 0;
		cancelDate = 0;
		useDate = 0;
		formerTime = 0;
		currentTime = 0;
		givingTime = 0;
		cancelTime = 0;
		useTime = 0;
		int i = 0;
		for (PaidHolidayDataDtoInterface dto : list) {
			if (i == 0) {
				// 前年度残日数
				formerDate = dto.getHoldDay();
				// 前年度残時間
				formerTime = dto.getHoldHour();
			} else {
				// 今年度残日数
				currentDate = dto.getHoldDay();
				// 今年度残時間
				currentTime = dto.getHoldHour();
			}
			givingDate = givingDate + dto.getGivingDay();
			givingTime = givingTime + dto.getGivingHour();
			cancelDate = cancelDate + dto.getCancelDay();
			cancelTime = cancelTime + dto.getCancelHour();
			useDate = useDate + dto.getUseDay();
			useTime = useTime + dto.getUseHour();
			i++;
		}
	}
	
	/**
	 * 年月から締期間の開始及び最終日を取得。
	 * @param timeConst 対象月
	 * @throws MospException 例外処理が発生した場合
	 */
	private void setLblDate(String timeConst) throws MospException {
		// VO準備
		PaidHolidayReferenceVo vo = (PaidHolidayReferenceVo)mospParams.getVo();
		// 選択年度取得
		int fiscalYear = getInt(vo.getPltSelectYear());
		// 年度及び月から年月を取得
		Date fiscalYearMonth = TimeUtility.getFiscalYearMonth(fiscalYear, getInt(timeConst), mospParams);
		int targetYear = DateUtility.getYear(fiscalYearMonth);
		int targetMonth = DateUtility.getMonth(fiscalYearMonth);
		// 年月指定時の基準日を取得
		Date yearMonthTargetDate = TimeUtility.getYearMonthTargetDate(targetYear, targetMonth, mospParams);
		// 設定適用情報取得
		ApplicationDtoInterface applicationDto = timeReference().application().findForPerson(vo.getPersonalId(),
				yearMonthTargetDate);
		// 設定適用情報確認
		if (applicationDto == null) {
			return;
		}
		// 締日ユーティリティー取得
		CutoffUtilBeanInterface cutoffUtil = timeReference().cutoffUtil();
		// 締日情報取得
		CutoffDtoInterface cutoffDto = cutoffUtil.getCutoffForPersonalId(vo.getPersonalId(), targetYear, targetMonth);
		// 処理結果確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 締期間の開始及び最終日
		Date firstDate = cutoffUtil.getCutoffFirstDate(cutoffDto.getCutoffCode(), targetYear, targetMonth);
		// 対象年月及び締日から締期間最終日を取得
		Date lastDate = cutoffUtil.getCutoffLastDate(cutoffDto.getCutoffCode(), targetYear, targetMonth);
		setLblDate(firstDate, lastDate);
	}
	
	/**
	 * 1月-3月以外ならば次年度に設定する。
	 * @param editActivateYear 対象年度
	 * @param timeConst 対象月
	 * @return 対象年度、対象月
	 */
	private String getViewYearMonth(int editActivateYear, String timeConst) {
		int month = Integer.parseInt(timeConst);
		if (Integer.parseInt(TimeConst.CODE_DISPLAY_JANUARY) <= month
				&& month <= Integer.parseInt(TimeConst.CODE_DISPLAY_MARCH)) {
			editActivateYear++;
		}
		return String.valueOf(editActivateYear) + mospParams.getName("Year") + timeConst + mospParams.getName("Month");
	}
	
	/**
	 * 設定された有効年から取得した年月別の有給休暇情報を設定する。<br>
	 * @throws MospException 例外発生時
	 */
	public void setList() throws MospException {
		// VO準備
		PaidHolidayReferenceVo vo = (PaidHolidayReferenceVo)mospParams.getVo();
		// 有効年度
		vo.setTxtLblPreviousYear(vo.getPltSelectYear());
		// 各月の休暇情報設定
		int viewPeriod = 0;
		int systemYear = DateUtility.getYear(DateUtility.getSystemDate());
		int editActivateYear = Integer.parseInt(vo.getPltSelectYear());
		int activateMonth = Integer.parseInt(vo.getTxtLblActivateMonth());
		// 加算値(1~3月は加算する)
		final int addValue = 8;
		// 表示範囲0個
		final int viewRangeMin = 0;
		// 表示範囲取得
		if (systemYear == editActivateYear) {
			if (Integer.parseInt(TimeConst.CODE_DISPLAY_JANUARY) <= activateMonth
					&& activateMonth <= Integer.parseInt(TimeConst.CODE_DISPLAY_MARCH)) {
				viewPeriod = TimeConst.CODE_DEFINITION_YEAR;
			} else {
				if (Integer.parseInt(TimeConst.CODE_DISPLAY_APRIL) <= activateMonth
						&& activateMonth <= Integer.parseInt(TimeConst.CODE_DISPLAY_DECEMBER)) {
					// 月から4引いた数がviewPeriod
					viewPeriod = activateMonth - TimeConst.CODE_DEFAULT_MONTH;
				} else {
					// 月に8足した数がviewPeriod
					viewPeriod = activateMonth + addValue;
				}
			}
		} else if (systemYear < editActivateYear) {
			if (Integer.parseInt(TimeConst.CODE_DISPLAY_JANUARY) <= activateMonth
					&& activateMonth <= Integer.parseInt(TimeConst.CODE_DISPLAY_MARCH)) {
				if (Integer.parseInt(TimeConst.CODE_DISPLAY_APRIL) <= activateMonth
						&& activateMonth <= Integer.parseInt(TimeConst.CODE_DISPLAY_DECEMBER)) {
					// 月から4引いた数がviewPeriod
					viewPeriod = activateMonth - TimeConst.CODE_DEFAULT_MONTH;
				} else {
					// 月に8足した数がviewPeriod
					viewPeriod = activateMonth + addValue;
				}
			} else {
				viewPeriod = viewRangeMin;
			}
		} else {
			viewPeriod = TimeConst.CODE_DEFINITION_YEAR;
		}
		// 入力された年度が今より下の場合、固定で12
		// 入力された年度が今より上の場合、固定で0
		String[] aryLblViewYearMonth = new String[viewPeriod];
		String[] aryLblFormerDate = new String[viewPeriod];
		String[] aryLblFormerTime = new String[viewPeriod];
		String[] aryLblCurrentDate = new String[viewPeriod];
		String[] aryLblCurrentTime = new String[viewPeriod];
		String[] aryLblGivingDate = new String[viewPeriod];
		String[] aryLblGivingTime = new String[viewPeriod];
		String[] aryLblCancelDate = new String[viewPeriod];
		String[] aryLblCancelTime = new String[viewPeriod];
		String[] aryLblUseDate = new String[viewPeriod];
		String[] aryLblUseTime = new String[viewPeriod];
		for (int i = 0; i < viewPeriod; i++) {
			if (Integer.parseInt(TimeConst.CODE_DISPLAY_APRIL) - TimeConst.CODE_DEFAULT_MONTH == i) {
				// 4月
				setLblDate(TimeConst.CODE_DISPLAY_APRIL);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_APRIL);
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_MAY) - TimeConst.CODE_DEFAULT_MONTH == i) {
				// 5月
				setLblDate(TimeConst.CODE_DISPLAY_MAY);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_MAY);
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_JUNE) - TimeConst.CODE_DEFAULT_MONTH == i) {
				// 6月
				setLblDate(TimeConst.CODE_DISPLAY_JUNE);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_JUNE);
				
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_JULY) - TimeConst.CODE_DEFAULT_MONTH == i) {
				// 7月
				setLblDate(TimeConst.CODE_DISPLAY_JULY);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_JULY);
				
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_AUGUST) - TimeConst.CODE_DEFAULT_MONTH == i) {
				// 8月
				setLblDate(TimeConst.CODE_DISPLAY_AUGUST);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_AUGUST);
				
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_SEPTEMBER) - TimeConst.CODE_DEFAULT_MONTH == i) {
				// 9月
				setLblDate(TimeConst.CODE_DISPLAY_SEPTEMBER);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_SEPTEMBER);
				
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_OCTOBER) - TimeConst.CODE_DEFAULT_MONTH == i) {
				// 10月
				setLblDate(TimeConst.CODE_DISPLAY_OCTOBER);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_OCTOBER);
				
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_NOVEMBER) - TimeConst.CODE_DEFAULT_MONTH == i) {
				// 11月
				setLblDate(TimeConst.CODE_DISPLAY_NOVEMBER);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_NOVEMBER);
				
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_DECEMBER) - TimeConst.CODE_DEFAULT_MONTH == i) {
				// 12月
				setLblDate(TimeConst.CODE_DISPLAY_DECEMBER);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_DECEMBER);
				
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_JANUARY) + addValue == i) {
				// 1月
				setLblDate(TimeConst.CODE_DISPLAY_JANUARY);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_JANUARY);
				
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_FEBRUARY) + addValue == i) {
				// 2月
				setLblDate(TimeConst.CODE_DISPLAY_FEBRUARY);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_FEBRUARY);
				
			} else if (Integer.parseInt(TimeConst.CODE_DISPLAY_MARCH) + addValue == i) {
				// 3月
				setLblDate(TimeConst.CODE_DISPLAY_MARCH);
				aryLblViewYearMonth[i] = getViewYearMonth(editActivateYear, TimeConst.CODE_DISPLAY_MARCH);
			}
			aryLblFormerDate[i] = String.valueOf(formerDate);
			aryLblFormerTime[i] = String.valueOf(formerTime);
			aryLblCurrentDate[i] = String.valueOf(currentDate);
			aryLblCurrentTime[i] = String.valueOf(currentTime);
			aryLblGivingDate[i] = String.valueOf(givingDate);
			aryLblGivingTime[i] = String.valueOf(givingTime);
			aryLblCancelDate[i] = String.valueOf(cancelDate);
			aryLblCancelTime[i] = String.valueOf(cancelTime);
			aryLblUseDate[i] = String.valueOf(useDate);
			aryLblUseTime[i] = String.valueOf(useTime);
		}
		vo.setAryLblViewYearMonth(aryLblViewYearMonth);
		vo.setAryLblFormerDate(aryLblFormerDate);
		vo.setAryLblFormerTime(aryLblFormerTime);
		vo.setAryLblDate(aryLblCurrentDate);
		vo.setAryLblTime(aryLblCurrentTime);
		vo.setAryLblGivingDate(aryLblGivingDate);
		vo.setAryLblGivingTime(aryLblGivingTime);
		vo.setAryLblCancelDate(aryLblCancelDate);
		vo.setAryLblCancelTime(aryLblCancelTime);
		vo.setAryLblUseDate(aryLblUseDate);
		vo.setAryLblUseTime(aryLblUseTime);
	}
}
