/*
 * 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.common.part;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import jp.mosp.common.CommonConst;
import jp.mosp.common.part.BasePart;
import jp.mosp.common.part.PartInfo;
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.legal.LegalConst;
import jp.mosp.mospcommon.system.AgreementBaseInfo;
import jp.mosp.mospcommon.system.LaborAgreementManager;

/**
 * 労使協定に関するPartクラス
 * @author yoshida
 *	@version 0.0.1
 */
public class LaborAgreementPart extends BasePart {
	
	/**
	 * コンストラクタ
	 */
	public LaborAgreementPart() {
		super();
	}
	
	/**
	 * @param partInfo	Partを利用する際に必要な情報
	 */
	public LaborAgreementPart(PartInfo partInfo) {
		super(partInfo);
	}
	

	private LaborAgreementManager	manager;
	

	/**
	 * 労使協定管理クラス取得。
	 * @return agreement 労使協定管理クラスインスタンス
	 */
	public LaborAgreementManager getManager() {
		if (VariousUtil.isNull(manager)) {
			manager = new LaborAgreementManager(cfg, cmd, aspUser, user, conn);
		}
		return manager;
	}
	
	/**
	 * 労使協定情報取得。
	 * @param targetCode 対象コード
	 * @param targetDate 	対象年月日
	 * @return 労使協定情報
	 * @throws SQLException 	SQL例外が発生した場合
	 * @throws IllegalAccessException 	メソッドにアクセスできない場合
	 * @throws NoSuchFieldException 	フィールドが見つからなかった場合
	 */
	public AgreementBaseInfo getUserLaborAgreement(String targetCode, Date targetDate) throws SQLException,
			IllegalAccessException, NoSuchFieldException {
		return getManager().getAgreementInfo(targetCode, targetDate);
	}
	
	/**
	 * 法定休日曜日取得。
	 * @param info 労使協定情報
	 * @return 法定休日曜日
	 */
	public static int getOfficialHoliday(AgreementBaseInfo info) {
		if (VariousUtil.isNotNull(info)) {
			return NumberUtil.getIntParam(info.getOfficialHoliday());
		}
		return 0;
	}
	
	/**
	 * 所定休日曜日取得。
	 * @param info 労使協定情報
	 * @return 所定休日曜日
	 */
	public static int[] getWeekHolidayArray(AgreementBaseInfo info) {
		int[] aryWeekHoliday = new int[0];
		if (VariousUtil.isNotNull(info)) {
			String[] array = StringUtil.divideByComma(info.getStandardWeekHoliday());
			aryWeekHoliday = new int[array.length];
			for (int i = 0; i < aryWeekHoliday.length; i++) {
				aryWeekHoliday[i] = 0;
				if (array[i].length() != 0) {
					aryWeekHoliday[i] = Integer.parseInt(array[i]);
				}
			}
		}
		return aryWeekHoliday;
	}
	
	/**
	 * 期間設定情報取得。
	 * @param info 労使協定情報
	 * @return 
	 * <p>
	 * [0]…数、[1]…期間種類
	 * </p>
	 * @throws Exception  例外処理が発生した場合
	 */
	public String[] getTermTypeInfo(AgreementBaseInfo info) throws Exception {
		String code = "";
		if (VariousUtil.isNotNull(info)) {
			code = part().mospcode().findTchange(CommonConst.TID_LIMIT_STANDARD_TERM, info.getTermType());
		}
		return StringUtil.divideByComma(code);
	}
	
	/**
	 * 期間内開始年月日リスト取得。
	 * @param termStartDate 期間開始年月日
	 * @param info 労使協定情報
	 * @return 期間開始年月日リスト
	 * <p>
	 * [0]…開始日、[1]…終了日の配列のリスト
	 * </p>
	 * @throws Exception  例外処理が発生した場合
	 */
	public List<Date[]> getUserTermList(Date termStartDate, AgreementBaseInfo info) throws Exception {
		List<Date[]> list = new ArrayList<Date[]>();
		String[] aryCode = getTermTypeInfo(info);
		Date startDate = termStartDate;
		Date endDate = null;
		Date termEndDate = DateUtil.addDay(DateUtil.addYear(termStartDate, 1), -1);
		int round = 0;
		if (aryCode.length == 2) {
			int amount = NumberUtil.getIntParam(aryCode[0]);
			// 週単位
			if (CommonConst.TCHANGE_TERM_WEEK.equals(aryCode[1])) {
				round = Double
					.valueOf(Math.ceil(DateUtil.getDateRemainder(termEndDate, termStartDate) / (7d * amount)))
					.intValue();
				for (int i = 0; i < round; i++) {
					endDate = getTermEndDate(startDate, CommonConst.TCHANGE_TERM_WEEK, amount);
					if (i == round - 1) {
						endDate = termEndDate;
					}
					list.add(new Date[]{ startDate, endDate });
					startDate = DateUtil.addDay(endDate, 1);
				}
			}
			// 月単位
			if (CommonConst.TCHANGE_TERM_MONTH.equals(aryCode[1])) {
				round = Double.valueOf(12d / amount).intValue();
				for (int i = 0; i < round; i++) {
					endDate = getTermEndDate(startDate, CommonConst.TCHANGE_TERM_MONTH, amount);
					list.add(new Date[]{ startDate, endDate });
					startDate = DateUtil.addDay(endDate, 1);
				}
			}
		}
		return list;
	}
	
	/**
	 * 期間終了日取得。
	 * @param startDate 期間開始日
	 * @param termType 期間種類
	 * @param amount 加算数
	 * @return 期間終了日
	 * @throws Exception 例外処理が発生した場合
	 */
	public static Date getTermEndDate(Date startDate, String termType, int amount) throws Exception {
		Date endDate = null;
		// 週単位
		if (CommonConst.TCHANGE_TERM_WEEK.equals(termType)) {
			endDate = DateUtil.addWeek(startDate, amount);
		}
		// 月単位
		if (CommonConst.TCHANGE_TERM_MONTH.equals(termType)) {
			endDate = DateUtil.addMonth(startDate, amount);
		}
		return DateUtil.addDay(endDate, -1);
	}
	
	/**
	 * 国民の祝日利用フラグ
	 * @param info 労使協定情報
	 * @return
	 * <p>
	 * 国民の祝日を利用する場合true、そうでない場合false
	 * </p>
	 */
	public static boolean useJapaneseHoliday(AgreementBaseInfo info) {
		if (VariousUtil.isNotNull(info)) {
			return StringUtil.isFlagOff(info.getJapaneseHolidayFlag());
		}
		return false;
	}
	
	/**
	 * 祝祭日マスタ利用フラグ
	 * @param info 労使協定情報
	 * @return
	 * <p>
	 * 祝祭日マスタを利用する場合true、そうでない場合false
	 * </p>
	 */
	public static boolean userHolidayMaster(AgreementBaseInfo info) {
		if (VariousUtil.isNotNull(info)) {
			return StringUtil.isFlagOff(info.getHolidayMasterFlag());
		}
		return false;
	}
	
	/**
	 * @param targetDate 対象年月日
	 * @param info 労使協定情報
	 * @return
	 * <p>
	 * 対象年月日が所定休日の場合true、そうでない場合false。
	 * </p>
	 * @throws Exception 	例外処理が発生した場合
	 */
	public boolean isStandardHoliday(Date targetDate, AgreementBaseInfo info) throws Exception {
		int dayOfWeek = DateUtil.getDayOfWeek(targetDate);
		int[] aryStandard = getWeekHolidayArray(info);
		for (int i : aryStandard) {
			if (i == dayOfWeek) {
				return true;
			}
		}
		return part().jpholiday().isStandardHoliday(targetDate, useJapaneseHoliday(info), userHolidayMaster(info));
	}
	
	/**
	 * @param targetDate 対象年月日
	 * @param info 労使協定情報
	 * @return
	 * <p>
	 * 対象年月日が法定休日の場合true、そうでない場合false。
	 * </p>
	 */
	public static boolean isOfficialHoliday(Date targetDate, AgreementBaseInfo info) {
		return getOfficialHoliday(info) == DateUtil.getDayOfWeek(targetDate);
	}
	
	/**
	 * 所定労働時間取得
	 * @param info 労使協定情報
	 * @return 所定労働時間（分）
	 */
	public static int getPrescribedTime(AgreementBaseInfo info) {
		// 法定労働時間
		int prescribedTime = LegalConst.LEGAL_HOURS_PER_DAY * CommonConst.NUM_1HOUR_MIN;
		if (VariousUtil.isNotNull(info)) {
			prescribedTime = info.getPrescribedTime();
		}
		return prescribedTime;
	}
	
	/**
	 * 所定労働時間取得
	 * @param targetCode 対象コード
	 * @param targetDate 対象年月日
	 * @return 所定労働時間（分）
	 * @throws NoSuchFieldException フィールドが見つからなかった場合
	 * @throws IllegalAccessException メソッドにアクセスできない場合
	 * @throws SQLException SQL例外が発生した場合
	 */
	public int getPrescribedTime(String targetCode, Date targetDate) throws SQLException, IllegalAccessException,
			NoSuchFieldException {
		return getPrescribedTime(getUserLaborAgreement(targetCode, targetDate));
	}
	
}
