package jp.mosp.payroll.payment.action;

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

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.payroll.base.Employee;
import jp.mosp.payroll.base.Payment;
import jp.mosp.payroll.base.PayrollAction;
import jp.mosp.payroll.base.PayrollConst;
import jp.mosp.payroll.dao.PdPayAllowanceDao;
import jp.mosp.payroll.dao.PdPayBreakdownDao;
import jp.mosp.payroll.dao.PdPayDeductionDao;
import jp.mosp.payroll.dao.PdPaySumDao;
import jp.mosp.payroll.dao.PdPayTimeDao;
import jp.mosp.payroll.dao.PhPaymentDao;
import jp.mosp.payroll.payment.vo.PaymentCardVo;

/**
 * 給与明細画面における処理を行う。<br><br>
 * 以下のコマンドを扱う。
 * <ul><li>
 * {@link #CMD_SHOW}
 * </li><li>
 * {@link #CMD_SOC_INS}
 * </li><li>
 * {@link #CMD_INCOME_TAX}
 * </li><li>
 * {@link #CMD_REGIST}
 * </li><li>
 * {@link #CMD_CALC}
 * </li></ul>
 */
public class PaymentCardAction extends PayrollAction {
	
	/**
	 * 画面表示コマンド。<br><br>
	 * 社員コード、計算年月をキーとし、給与明細を取得、表示する。<br>
	 */
	public static final String	CMD_SHOW		= "P1250";
	
	/**
	 * 社会保険計算コマンド。<br><br>
	 * 編集中の社員コード、計算年月の給与データに対し、社会保険計算を行う。<br>
	 * 但し、計算するのみで登録はしない。<br>
	 * 給与明細を編集し支給額が変わった場合等、
	 * 社会保険料を自動計算するために用いる。<br>
	 */
	public static final String	CMD_SOC_INS		= "P1253";
	
	/**
	 * 所得税計算コマンド。<br><br>
	 * 編集中の社員コード、計算年月の給与データに対し、所得税計算を行う。<br>
	 * 但し、計算するのみで登録はしない。<br>
	 * 給与明細を編集し支給額が変わった場合等、
	 * 所得税を自動計算するために用いる。<br>
	 */
	public static final String	CMD_INCOME_TAX	= "P1254";
	
	/**
	 * 登録コマンド。<br><br>
	 * 編集中の社員コード、計算年月の給与データに対し、登録を行う。<br>
	 * この際、各種合計を行う。<br>
	 * 給与明細の編集、法定控除計算を行った場合等、
	 * 編集内容を登録する際に用いる。<br>
	 */
	public static final String	CMD_REGIST		= "P1255";
	
	/**
	 * 個別給与計算コマンド。<br><br>
	 * 編集中の社員コード、計算年月の給与データに対し、個別に再度給与計算を行う。<br>
	 * 編集中の給与データは上書かれてしまうため、注意が必要。<br>
	 * 誤って登録してしまったものを元に戻したい場合等に、用いる。<br>
	 */
	public static final String	CMD_CALC		= "P1256";
	

	/**
	 * Actionの初期化を行う。<br><br>
	 * 以下の処理を行う。
	 * <ul><li>
	 * {@link PayrollAction#PayrollAction()}
	 * </li></ul>
	 */
	public PaymentCardAction() {
		super();
	}
	
	/* (non-Javadoc)
	 * @see jp.mosp.common.common.BaseAction#getSpecificVo()
	 */
	@Override
	protected BaseVo getSpecificVo() {
		return new PaymentCardVo();
	}
	
	/**
	 * アクション。<br>
	 * 詳細は、クラス説明を参照。<br>
	 */
	public void action() throws Exception {
		// VO取得及び設定
		prepareVo();
		if (cmd.equals(CMD_SHOW)) {
			// 画面表示
			show();
		} else if (cmd.equals(CMD_SOC_INS)) {
			// 社会保険計算
			calcSocIns();
		} else if (cmd.equals(CMD_INCOME_TAX)) {
			// 所得税計算
			calcIncomeTax();
		} else if (cmd.equals(CMD_REGIST)) {
			// 登録
			regist();
		} else if (cmd.equals(CMD_CALC)) {
			// 登録
			calculate();
		} else {
			throw new MospException(MospConst.EX_CMD_INVALID);
		}
	}
	
	/**
	 * 画面表示処理を行う。<br><br>
	 * @throws Exception 例外処理が発生した場合
	 */
	@Override
	public void show() throws Exception {
		// コネクション取得
		getConnection();
		// 画面表示処理
		show(key1, MospUtility.getDate(key2));
	}
	
	/**
	 * 登録処理を行う。<br><br>
	 * @throws Exception 例外処理が発生した場合
	 */
	private void regist() throws Exception {
		// コネクション取得
		getConnection();
		// VO取得
		PaymentCardVo vo = (PaymentCardVo)getVo();
		// 対象年月取得
		Date targetMonth = vo.getCalcMonth();
		// 計算月確認
		if (!isCurrent(targetMonth, PayrollConst.OFFICE_ALL, PayrollConst.CALC_PAYMENT)) {
			// メッセージ設定
			addErrMessage(MospUtility.getMessage(msg, "WP1211", ""));
			return;
		}
		// パラメータ取得
		vo.setParams(request);
		// 給与情報取得
		Payment payment = getPayment(vo.getKCode(), vo.getCalcMonth());
		// パラメータ設定
		vo.setDtoFields(payment);
		// 合計計算
		calcTotal(getEmployee(vo.getKCode()), payment);
		// 登録
		registPayment(payment);
		// コミット
		commit();
		// メッセージ設定
		setMessage(MospUtility.getMessage(msg, "IC0001", ""));
		// 画面表示処理
		show(vo.getKCode(), targetMonth);
	}
	
	/**
	 * 計算処理を行う。<br><br>
	 * @throws Exception 例外処理が発生した場合
	 */
	private void calculate() throws Exception {
		// コネクション取得
		getConnection();
		// VO取得
		PaymentCardVo vo = (PaymentCardVo)getVo();
		// 対象年月取得
		Date targetMonth = vo.getCalcMonth();
		// 計算月確認
		if (!isCurrent(targetMonth, PayrollConst.OFFICE_ALL, PayrollConst.CALC_PAYMENT)) {
			// メッセージ設定
			addErrMessage(MospUtility.getMessage(msg, "WP1211", ""));
			return;
		}
		// 給与計算
		calcPayment(vo.getKCode(), targetMonth);
		// コミット
		commit();
		// メッセージ設定
		setMessage(MospUtility.getMessage(msg, "IP1230", MospUtility.getDateString(targetMonth,
				PayrollConst.FORMAT_YEAR_MONTH)));
		// 画面表示処理
		show(vo.getKCode(), targetMonth);
	}
	
	/**
	 * 社会保険計算処理を行う。<br><br>
	 * @throws Exception 例外処理が発生した場合
	 */
	private void calcSocIns() throws Exception {
		// コネクション取得
		getConnection();
		// VO取得
		PaymentCardVo vo = (PaymentCardVo)getVo();
		// 給与情報取得
		Payment payment = getPayment(vo.getKCode(), vo.getCalcMonth());
		// パラメータ取得
		vo.setParams(request);
		// パラメータ設定
		vo.setDtoFields(payment);
		// 人事情報取得
		Employee employee = getEmployee(vo.getKCode());
		// 社会保険計算
		calcSocialInsurance(employee, payment);
		// 合計計算
		calcTotal(employee, payment);
		// VOフィールド設定
		vo.setFields(employee, payment);
		// メッセージ設定
		setMessage(MospUtility.getMessage(msg, "IP1253", ""));
	}
	
	/**
	 * 所得税計算処理を行う。<br><br>
	 * @throws Exception 例外処理が発生した場合
	 */
	private void calcIncomeTax() throws Exception {
		// コネクション取得
		getConnection();
		// VO取得
		PaymentCardVo vo = (PaymentCardVo)getVo();
		// 給与情報取得
		Payment payment = getPayment(vo.getKCode(), vo.getCalcMonth());
		// パラメータ取得
		vo.setParams(request);
		// パラメータ設定
		vo.setDtoFields(payment);
		// 人事情報取得
		Employee employee = getEmployee(vo.getKCode());
		// 所得税計算
		calcIncomeTax(employee, payment);
		// 合計計算
		calcTotal(employee, payment);
		// VOフィールド設定
		vo.setFields(employee, payment);
		// メッセージ設定
		setMessage(MospUtility.getMessage(msg, "IP1253", ""));
	}
	
	/**
	 * 画面表示処理を行う。<br><br>
	 * @param kCode 対象社員コード
	 * @param targetMonth 対象年月
	 * @throws Exception 例外処理が発生した場合
	 */
	private void show(String kCode, Date targetMonth) throws Exception {
		// VO取得
		PaymentCardVo vo = (PaymentCardVo)getVo();
		// 人事情報取得
		Employee employee = getEmployee(kCode);
		// 給与情報取得
		Payment payment = getPayment(kCode, targetMonth);
		// VOフィールド設定
		vo.setFields(employee, payment);
		// 画面モード設定
		Date current = getCurrent(PayrollConst.OFFICE_ALL, PayrollConst.CALC_PAYMENT);
		if (current == null) {
			vo.setMode(1);
		} else {
			vo.setMode(targetMonth.compareTo(current) == 0 ? 0 : 1);
		}
	}
	
	/**
	 * 給与情報を登録する。<br><br>
	 * @param payment 給与情報
	 * @throws IllegalAccessException 
	 * @throws NoSuchFieldException 
	 * @throws SQLException 
	 * @throws MospException 
	 */
	private void registPayment(Payment payment) throws SQLException, NoSuchFieldException, IllegalAccessException,
			MospException {
		// DAO準備
		PhPaymentDao phPaymentDao = new PhPaymentDao(cfg, cmd, aspUser, user, conn);
		PdPayTimeDao pdPayTimeDao = new PdPayTimeDao(cfg, cmd, aspUser, user, conn);
		PdPayAllowanceDao pdPayAllowanceDao = new PdPayAllowanceDao(cfg, cmd, aspUser, user, conn);
		PdPayDeductionDao pdPayDeductionDao = new PdPayDeductionDao(cfg, cmd, aspUser, user, conn);
		PdPayBreakdownDao pdPayBreakdownDao = new PdPayBreakdownDao(cfg, cmd, aspUser, user, conn);
		PdPaySumDao pdPayTotalDao = new PdPaySumDao(cfg, cmd, aspUser, user, conn);
		// 給与ヘッダー更新
		phPaymentDao.update(payment.getHeader(), true);
		// 給与明細削除
		pdPayTimeDao.delete(payment.getKCode(), payment.getCalcMonth());
		pdPayAllowanceDao.delete(payment.getKCode(), payment.getCalcMonth());
		pdPayDeductionDao.delete(payment.getKCode(), payment.getCalcMonth());
		pdPayBreakdownDao.delete(payment.getKCode(), payment.getCalcMonth());
		pdPayTotalDao.delete(payment.getKCode(), payment.getCalcMonth());
		// 給与明細登録
		pdPayTimeDao.insert(payment.getTimeList());
		pdPayAllowanceDao.insert(payment.getAllowanceList());
		pdPayDeductionDao.insert(payment.getDeductionList());
		pdPayBreakdownDao.insert(payment.getBreakdownList());
		pdPayTotalDao.insert(payment.getSumList());
	}
	
}
