/*
 * MosP - Mind Open Source Project         http://www.mosp.jp/
 * Copyright (C) 1987-2009 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.common.part;

/**
 * 勤怠項目計算機
 * @author yoshida
 *	@version	0.0.1
 */
public class KintaiCalcPart {

	/**
	 * 規定出勤時刻
	 */
	protected int regStartTime		= 0;
	/**
	 * 規定退勤時刻
	 */
	protected int regQuitTime 		= 0;
	/**
	 * 規定勤務時間
	 */
	protected int regWorkTime 		= 0;
	/**
	 * 規定休憩時間
	 */
	protected int regBreakTime 	= 0;
	/**
	 * 規定残業開始時刻
	 */
	protected int regOverStart		= 0;
	/**
	 * 規定残業休憩時間
	 */
	protected int regOverBreak		= 0;

	/**
	 * 遅刻時間
	 */
	protected int lateTime 		= 0;
	/**
	 * 勤務時間
	 */
	protected int workTime 		= 0;
	/**
	 * 早退時間
	 */
	protected int leaveTime 		= 0;
	/**
	 * 残業時間
	 */
	protected int overTime 		= 0;
	/**
	 * 休憩時間
	 */
	protected int intervalTime 	= 0;
	/**
	 * 深夜時間
	 */
	protected int lateNightTime 	= 0;
	/**
	 * 休出時間
	 */
	protected int holidayWorkTime 	= 0;

	/**
	 * 深夜時間開始時刻
	 */
	protected int lateNightStart 	= 0;
	/**
	 * 深夜時間終了時刻
	 */
	protected int lateNightEnd 	= 0;
	/**
	 * 半休時間
	 */
	protected int halfHoliday		= 0;
	/**
	 * 入力単位（分）
	 */
	protected int inputUnit 		= 1;

	/**
	 * コンストラクタ
	 */
	public KintaiCalcPart() {

	}

	/**
	 * コンストラクタ
	 * @param regStartTime		規定出勤時刻
	 * @param regQuitTime		規定退勤時刻
	 * @param regWorkTime		規定勤務時間
	 * @param regBreakTime		規定休憩時間
	 * @param regOverStart		規定残業開始時刻
	 * @param regOverBreak		規定残業休憩時間
	 * @param lateNightStart	深夜時間開始時刻（分）（48時間制）
	 * @param lateNightEnd		深夜時間終了時刻（分）（48時間制）
	 * @param halfHoliday		半休時間（分）	
	 * @param inputUnit			単位時間（分）
	 */
	public KintaiCalcPart(
			int regStartTime,
			int regQuitTime,
			int regWorkTime,
			int regBreakTime,
			int regOverStart,
			int regOverBreak,
			int lateNightStart,
			int lateNightEnd,
			int halfHoliday,
			int inputUnit
	) {
		// 各種規定時間設定
		setWorkTypeInfo(regStartTime, regQuitTime, regWorkTime, regBreakTime, regOverStart, regOverBreak);
		// 時間設定
		setHours(lateNightStart, lateNightEnd, halfHoliday, inputUnit);
	}

	/**
	 * 時間設定
	 * @param lateNightStart	深夜時間開始時刻（分）（48時間制）
	 * @param lateNightEnd		深夜時間終了時刻（分）（48時間制）
	 * @param halfHoliday		半休時間（分）	
	 * @param inputUnit			単位時間（分）
	 */
	public void setHours(
			int lateNightStart,
			int lateNightEnd,
			int halfHoliday,
			int inputUnit
	) {
		setLateNightInfo(lateNightStart, lateNightEnd);
		this.halfHoliday = halfHoliday;
		if (inputUnit > 1) {
			this.inputUnit = inputUnit;
		}
	}

	/**
	 * 深夜時間設定
	 * @param lateNightStart	深夜時間開始時刻（分）（48時間制）
	 * @param lateNightEnd		深夜時間終了時刻（分）（48時間制）
	 */
	public void setLateNightInfo(int lateNightStart, int lateNightEnd) {
		this.lateNightStart = lateNightStart;
		this.lateNightEnd = lateNightEnd;
	}

	/**
	 * 各規定時間設定
	 * @param regStartTime		規定出勤時刻
	 * @param regQuitTime		規定退勤時刻
	 * @param regWorkTime		規定勤務時間
	 * @param regBreakTime		規定休憩時間
	 * @param regOverStart		規定残業開始時刻
	 * @param regOverBreak		規定残業休憩時間
	 */
	public void setWorkTypeInfo(
			int regStartTime,
			int regQuitTime,
			int regWorkTime,
			int regBreakTime,
			int regOverStart,
			int regOverBreak
	) {
		this.regStartTime = regStartTime;
		this.regQuitTime = regQuitTime;
		this.regWorkTime = regWorkTime;
		this.regBreakTime = regBreakTime;
		this.regOverStart = regOverStart;
		this.regOverBreak = regOverBreak;
	}

	/**
	 * 勤怠計算
	 * @param inputStart		出勤時刻
	 * @param inputQuit			退勤時刻
	 * @param isStartHalf		出勤半休区分
	 * @param isQuitHalf		退勤半休区分
	 * @param isWorkOnHoliday	休出判断
	 */
	public void runCalculate(
			int inputStart,
			int inputQuit,
			boolean isStartHalf,
			boolean isQuitHalf,
			boolean isWorkOnHoliday
	) {
		runCalcStartTime(inputStart, isStartHalf, isWorkOnHoliday);
		runCalcQuitTime(inputStart, inputQuit, (isStartHalf || isQuitHalf), isWorkOnHoliday);
	}

	/**
	 * 出勤区分時間計算
	 * @param inputStart		出勤時刻
	 * @param isStartHalf		出勤半休区分
	 * @param isWorkOnHoliday	休出判断
	 */
	public void runCalcStartTime(int inputStart, boolean isStartHalf, boolean isWorkOnHoliday) {
		if (isStartHalf | isWorkOnHoliday) {
			lateTime = 0;
		} else {
			lateTime = getLateTimes(inputStart);
		}
	}

	/**
	 * 退勤区分時間計算
	 * @param inputStart		出勤時刻
	 * @param inputQuit			退勤時刻
	 * @param isHalf			半休区分
	 * @param isWorkOnHoliday	休出判断
	 */
	public void runCalcQuitTime(
			int inputStart,
			int inputQuit,
			boolean isHalf,
			boolean isWorkOnHoliday
	) {
		// 退勤時刻は0になることは無い
		if (inputQuit == 0) {
			inputQuit = regQuitTime;
		}
		// 勤務時間
		workTime 			= getWorkTimes(inputStart, inputQuit);
		leaveTime 			= 0;
		if (!isHalf) {
			leaveTime 		= getLeaveEarlyTimes(inputQuit);
		}
		overTime 			= getOverTimes(isHalf);
		intervalTime 		= getIntervalTimes(inputQuit);
		lateNightTime		= getLateNightTimes(inputStart, inputQuit);
		holidayWorkTime		= getHolidayWork(isWorkOnHoliday);
	}

	/**
	 * 遅刻時間計算
	 * @param inputStart		出勤時刻
	 * @return	遅刻時間
	 */
	protected int getLateTimes(int inputStart) {
		return getLateTimes(inputStart, regStartTime, inputUnit);
	}

	/**
	 * 遅刻時間計算
	 * @param inputStart		出勤時刻
	 * @param regStartTime		規定出勤時刻
	 * @param inputUnit			単位時間
	 * @return	遅刻時間
	 */
	public static int getLateTimes(int inputStart, int regStartTime, int inputUnit) {
		// 遅刻時間 = 出勤時刻 - 標準出勤時刻
		int latemin = inputStart - regStartTime;
		if (latemin > 0) {
			if (latemin % inputUnit > 0) {
				// 遅刻時間を単位時間で割った余りが0より大きい場合は遅刻時間に単位時間を足す
				latemin += inputUnit;
			}
			// 丸め
			latemin -= latemin%inputUnit;
		}
		if (latemin < 0) {
			latemin = 0;
		}
		return latemin;
	}

	/**
	 * 勤務時間計算
	 * @param inputStart	出勤時刻
	 * @param inputQuit		退勤時刻
	 * @return	勤務時間
	 */
	protected int getWorkTimes(int inputStart, int inputQuit) {
		return getWorkTimes(inputStart, inputQuit, inputUnit);
	}

	/**
	 * 勤務時間計算
	 * @param inputStart		出勤時刻
	 * @param inputQuit			退勤時刻
	 * @param inputUnit			単位時間
	 * @return	勤務時間
	 */
	public static int getWorkTimes(int inputStart, int inputQuit, int inputUnit) {
		// 単位時間未満の出勤時間
		int remainderStart = inputStart % inputUnit;
		// 丸めた出勤時刻
		int roundStart = inputStart - remainderStart;
		if (remainderStart > 0) {
			// 単位時間未満の出勤時間が0より大きい場合は丸めた出勤時刻に単位時間を足す
			roundStart += inputUnit;
		}
		// 単位時間未満の退勤時間
		int remainderQuit = inputQuit % inputUnit;
		// 丸めた退勤時刻
		int roundQuit = inputQuit - remainderQuit;
		// 退勤時刻 - 出勤時刻
		int workmin = roundQuit - roundStart;
		// 勤務時間がマイナスの場合、0とする
		if (workmin < 0){
			workmin = 0;
		}
		return workmin;
	}

	/**
	 * 早退時間計算
	 * @param inputQuit		退勤時刻
	 * @return 早退時間
	 */
	protected int getLeaveEarlyTimes(int inputQuit) {
		return getLeaveEarlyTimes(inputQuit, regQuitTime, workTime, regWorkTime, inputUnit);
	}

	/**
	 * 早退時間計算
	 * @param inputQuit			退勤時刻
	 * @param regQuitTime		規定退勤時刻
	 * @param workTime			勤務時間
	 * @param regWorkTime		規定勤務時間
	 * @param inputUnit			単位時間
	 * @return	早退時間
	 */
	public static int getLeaveEarlyTimes(
			int inputQuit,
			int regQuitTime,
			int workTime,
			int regWorkTime,
			int inputUnit
	) {
		// 早退時間 = 標準退社時刻 - 退社時刻
		int leavemin = regQuitTime - inputQuit;
		if (leavemin % inputUnit > 0) {
			// 早退時間を単位時間で割った余りが0より大きい場合は早退時間に単位時間を足す
			leavemin += inputUnit;
			// 丸め
			leavemin -= leavemin%inputUnit;
		}
		if (leavemin < 0) {
			leavemin = 0;
		}
		return leavemin;
	}

	/**
	 * 休出時間計算
	 * @param isWorkOnHoliday	休出判断
	 * @return	休出時間
	 */
	protected int getHolidayWork(boolean isWorkOnHoliday) {
		return getHolidayWork(workTime, intervalTime, isWorkOnHoliday);
	}

	/**
	 * 休出時間計算
	 * @param workTime			勤務時間
	 * @param intervalTime		休憩時間
	 * @param isWorkOnHoliday	休出判断
	 * @return
	 */
	public static int getHolidayWork(int workTime, int intervalTime, boolean isWorkOnHoliday) {
		if (isWorkOnHoliday) {
			return workTime - intervalTime;
		}
		return 0;
	}

	/**
	 * 深夜時間計算
 	 * @param inputStart	出勤時刻
	 * @param inputQuit		退勤時刻
	 * @return	深夜時間
	 */
	protected int getLateNightTimes(int inputStart, int inputQuit) {
		return getLateNightTimes(inputQuit, lateNightStart, lateNightEnd, inputUnit, inputStart);
	}

	/**
	 * 深夜時間計算
	 * @param inputQuit			退勤時刻
	 * @param lateNightStart	深夜時間開始時刻
	 * @param lateNightEnd		深夜時間終了時刻
	 * @param inputUnit			単位時間
	 * @param inputStart		出勤時刻
	 * @return	深夜時間計算
	 */
	public static int getLateNightTimes(
			int inputQuit,
			int lateNightStart,
			int lateNightEnd,
			int inputUnit,
			int inputStart
	) {
		// 深夜時間計算
		int latenightmin = 0;
		// 出勤時刻が深夜時刻開始時間以上の場合
		if (inputStart >= lateNightStart) {
			// 退勤時刻 - 出勤時刻
			latenightmin = inputQuit - inputStart;
		} else {
			// 退勤時刻 - 深夜時間開始時刻
			latenightmin = inputQuit - lateNightStart;
		}
		// 丸め
		latenightmin -= latenightmin%inputUnit;
		// 限度調整
		// 深夜時間開始時刻が出勤時刻以上の場合
		if (inputStart >= lateNightStart) {
			// 深夜時間計算が深夜時間開始時刻 - 出勤時刻よりも大きい場合
			if (latenightmin > (lateNightEnd - inputStart)) {
				latenightmin = lateNightEnd - inputStart;
			}
		} else {
			// 深夜時間計算が深夜時間開始時刻 - 深夜時間終了時刻よりも大きい場合
			if (latenightmin > (lateNightEnd - lateNightStart)) {
				latenightmin = lateNightEnd - lateNightStart;
			}
		}
		// 深夜時間がマイナスの場合、0とする
		if (latenightmin < 0) {
			latenightmin = 0;
		}
		return latenightmin;
	}

	/**
	 * 休憩時間計算
	 * @return	休憩時間
	 */
	protected int getIntervalTimes(int inputQuit) {
		return getIntervalTimes(workTime, regBreakTime, overTime, regOverBreak, inputUnit,inputQuit,regQuitTime);
	}

	/**
	 * 休憩時間計算
	 * @param inputStart		出勤時刻
	 * @param inputQuit			退勤時刻
	 * @param inputUnit			単位時間
	 * @param halfHoliday		半休時間
	 * @param isHalf			半休区分
	 * @param regStartTime		規定出勤時刻
	 * @param regOverStart		規定残業開始時刻
	 * @param regWorkTime		規定勤務時間
	 * @param regBreakTime		規定休憩時間
	 * @param regOverBreak		規定残業休憩時間
	 * @param regQuitTime		規定退勤時刻
	 * @return
	 */
	public static int getIntervalTimes(
			int inputStart,
			int inputQuit,
			int inputUnit,
			int halfHoliday,
			boolean isHalf,
			int regStartTime,
			int regOverStart,
			int regWorkTime,
			int regBreakTime,
			int regOverBreak,
			int regQuitTime
	) {
		return getIntervalTimes(
				getWorkTimes(inputStart, inputQuit, inputUnit),
				regBreakTime,
				getOverTimes(
						inputStart,
						inputQuit,
						inputUnit,
						halfHoliday,
						isHalf,
						regStartTime,
						regOverStart,
						regWorkTime,
						regOverBreak
				),
				regOverBreak,inputUnit,inputQuit,regQuitTime
			);
	}

	/**
	 * 休憩時間計算
	 * @param workTime			勤務時間
	 * @param regBreakTime		規定休憩時間
	 * @param overTime			残業時間
	 * @param regOverBreak		規定残業休憩時間
	 * @param inputUnit			入力単位（分）
	 * @param inputQuit			退勤時刻
	 * @param regQuitTime		規定退勤時刻
	 * @return	休憩時間
	 */
	
	public static int getIntervalTimes(
			int workTime,
			int regBreakTime,
			int overTime,
			int regOverBreak,
			int inputUnit,
			int inputQuit,
			int regQuitTime
	) {
		// 退勤時刻 + 規定退勤時刻
		int difQuit = inputQuit - regQuitTime;
		// 残業休憩時間
		int overIntervalTime = 0;
		// 休憩時間
		int intervalmin = 0;
		// 標準休憩  5時間以上
		if (workTime > 300) {
			intervalmin = regBreakTime;
		}
		// 退勤時刻 > 規定退勤時刻
		if (inputQuit > regQuitTime) {
			overIntervalTime = difQuit;
			overIntervalTime -= overIntervalTime%inputUnit;
		}
		// 残業時間が１以上 又 規定残業休憩時間よりも退勤時刻の差が大きい場合
		if (overTime > 0 || difQuit > regOverBreak) {
			overIntervalTime = regOverBreak;
		}
		// 休憩時間 += 残業休憩時間
		intervalmin += overIntervalTime;
		return intervalmin;
	}

	/**
	 * 残業時間計算
	 * @param isHalf	半休区分
	 * @return	残業時間
	 */
	protected int getOverTimes(boolean isHalf) {
		return getOverTimes(lateTime, workTime, halfHoliday, regOverStart, regWorkTime, regOverBreak, isHalf);
	}

	/**
	 * 残業時間計算
	 * @param inputStart		出勤時刻
	 * @param inputQuit			退勤時刻
	 * @param inputUnit			単位時間
	 * @param halfHoliday		半休時間
	 * @param isHalf			半休区分
	 * @param regStartTime		規定出勤時刻
	 * @param regOverStart		規定残業時間開始時刻
	 * @param regWorkTime		規定勤務時間
	 * @param regOverBreak		規定残業休憩時間
	 * @return	残業時間
	 */
	public static int getOverTimes(
			int inputStart,
			int inputQuit,
			int inputUnit,
			int halfHoliday,
			boolean isHalf,
			int regStartTime,
			int regOverStart,
			int regWorkTime,
			int regOverBreak
	) {
		return getOverTimes(
				getLateTimes(inputStart, regStartTime, inputUnit),
				getWorkTimes(inputStart, inputQuit, inputUnit),
				halfHoliday,
				regOverStart,
				regWorkTime,
				regOverBreak,
				isHalf
		);
	}

	/**
	 * 残業時間計算
	 * @param lateTime			遅刻時間
	 * @param workTime			勤務時間
	 * @param halfHoliday		半休時間
	 * @param regOverStart		規定残業開始時刻
	 * @param regWorkTime		規定勤務時間
	 * @param regOverBreak		規定残業休憩時間
	 * @param isHalf			半休区分
	 * @return
	 */
	public static int getOverTimes(
			int lateTime,
			int workTime,
			int halfHoliday,
			int regOverStart,
			int regWorkTime,
			int regOverBreak,
			boolean isHalf
	) {
		// 遅刻時間 + 勤務時間
		int worktimes = lateTime + workTime;
		// 残業時間
		int overmin = 0;
		// 半休調整
		if (isHalf) {
			worktimes -= halfHoliday;
		}
		// 勤務対象時間 > 標準残業計算開始時間
		if (worktimes > regOverStart) {
			// 勤務対象時間 - 標準勤務時間 - 残業休憩
			overmin = worktimes - regWorkTime - regOverBreak;
			if (overmin < 0) {
				overmin = 0;
			}
		}
		return overmin;
	}

	/**
	 * 勤務時間
	 * @return	勤務時間計算値
	 */
	public int getWorkTime() 			{ return workTime			; }

	/**
	 * 休憩時間
	 * @return	休憩時間計算値
	 */
	public int getIntervalTime() 		{ return intervalTime		; }

	/**
	 * 遅刻時間
	 * @return	遅刻時間計算値
	 */
	public int getLateTime() 			{ return lateTime			; }

	/**
	 * 早退時間
	 * @return	早退時間計算値
	 */
	public int getLeaveTime() 			{ return leaveTime			; }

	/**
	 * 残業時間
	 * @return	残業時間計算値
	 */
	public int getOverTime() 			{ return overTime			; }

	/**
	 * 深夜時間
	 * @return	深夜時間計算値
	 */
	public int getLateNightTime() 		{ return lateNightTime		; }

	/**
	 * 休出時間
	 * @return	休出時間計算値
	 */
	public int getHolidayWorkTime() 	{ return holidayWorkTime	; }

}
