package jp.mosp.workflow.action;

import java.util.Date;

import jp.mosp.common.CommonConst;
import jp.mosp.common.action.MosPWorkflowAction;
import jp.mosp.common.common.MospConst;
import jp.mosp.common.common.MospException;
import jp.mosp.common.common.MospUtility;
import jp.mosp.common.dto.CtWorkflowDto;
import jp.mosp.common.part.DatePart;
import jp.mosp.common.part.KintaiApprovalPart;
import jp.mosp.common.part.StringPart;
import jp.mosp.common.part.WorkflowPart;

import jp.mosp.workflow.dto.CtOvertimeRequestDto;
import jp.mosp.workflow.vo.OverTimeRequestCardVo;

public class OverTimeRequestCardAction extends MosPWorkflowAction {

	// コマンド
	private static final String CMD_CARD_SHOW 	= "K1415";
	private static final String CMD_CARD_SELECT 	= "K1416";
	private static final String CMD_CARD_INSERT 	= "K1417";
	private static final String CMD_CARD_UPDATE 	= "K1418";
	private static final String CMD_CARD_CANCEL 	= "K1419";

	/**
	 * コンストラクタ
	 */
	public OverTimeRequestCardAction() {
		super();
	}

	public void action() throws Exception {
		// VOの初期化
		OverTimeRequestCardVo vo = new OverTimeRequestCardVo(cfg, msg, nam, cmd, aspUser, user);
		// VO及びフォワード先URLの設定
		setVo(vo);
		setUrl(vo.getRetUrl());
		vo.setParams(request);
		// DTOの取得
		CtOvertimeRequestDto dto;
		Object obj = session.getAttribute(MospConst.ATT_DTO);
		dto = obj instanceof CtOvertimeRequestDto ? (CtOvertimeRequestDto)obj : null;
		// ユーザ情報の取得
		getInfo(user.getUserId());
		// 表示項目の設定
		setLabelInfo(vo);
		// プルダウンのセット
		setPulldownList(vo);
		// コマンド毎の処理
		if (cmd.equals(CMD_CARD_SHOW)) {
			// 初期値の設定
			vo.setDefaultValues();
			Date todayDate = DatePart.getSystemDate();
			vo.setPltRequestYear(String.valueOf(MospUtility.getYear(todayDate)));
			vo.setPltRequestMonth(String.valueOf(MospUtility.getMonth(todayDate)));
			vo.setPltRequestDay(String.valueOf(MospUtility.getDay(todayDate)));
			// モード設定
			vo.setMode(OverTimeRequestCardVo.MODE_INSERT);
		} else if (cmd.equals(CMD_CARD_SELECT)) {
			// 表示(キーで情報を検索)
			// データの取得
			dto = getOverTimeRequest(vo.getIntParam(key1));
			chkExist(dto);
			// VOに情報をセット
			vo.setFields(dto);
			// 承認状況の設定
			setApprovalStatus(vo, dto);
			// セッションにDTOをセット
			session.setAttribute(MospConst.ATT_DTO, dto);
		} else if (cmd.equals(CMD_CARD_INSERT)) {
			// 新規登録
			dto = insert(vo);
			// 承認状況の設定
			setApprovalStatus(vo, dto);
			// セッションにDTOをセット
			session.setAttribute(MospConst.ATT_DTO, dto);
		} else if (cmd.equals(CMD_CARD_UPDATE)) {
			// 更新
			dto = update(vo, dto);
			// 承認状況の設定
			setApprovalStatus(vo, dto);
			// セッションにDTOをセット
			session.setAttribute(MospConst.ATT_DTO, dto);
		} else if (cmd.equals(CMD_CARD_CANCEL)) {
			// 取り下げ
			cancel(vo, dto);
		} else {
			throw new MospException(MospConst.EX_CMD_INVALID);
		}
	}

	/**
	 * 表示項目の設定
	 * @param vo			対象VO
	 * @throws Exception
	 */
	private void setLabelInfo(OverTimeRequestCardVo vo) throws Exception {
		vo.setLblKCode(mKihon.getKCode());
		vo.setLblKName(mKihon.getSimei());
		vo.setLblSection(getSectionName(mKihon.getSCode()));
	}

	/**
	 * プルダウンの設定
	 * @param vo			対象VO
	 * @throws Exception
	 */
	private void setPulldownList(OverTimeRequestCardVo vo) throws Exception {
		vo.aryPltYear = StringPart.getYearArray(MospUtility.getYear(DatePart.getSystemDate()));
		vo.aryPltMonth = StringPart.getMonthArray();
		vo.aryPltDay = StringPart.getDayArray();
		vo.aryPltHour = StringPart.getCountArray(0, 24, 1);
		// 入力単位時間設定
		setInputUnit();
		vo.aryPltMin = StringPart.getCountArray(0, 59, inputUnit);
	}

	/**
	 * 新規登録
	 * @param vo	対象VO
	 * @return 		データ挿入対象DTO
	 * @throws Exception
	 */
	private CtOvertimeRequestDto insert(OverTimeRequestCardVo vo) throws Exception {
		// パラメーターの妥当性確認
		vo.validate();
		// DTOの準備
		CtOvertimeRequestDto dto = new CtOvertimeRequestDto();
		vo.setDtoFields(dto);
		dto.setKCode(mKihon.getKCode());
		dto.setRequestDate(DatePart.getSystemDate());
		// 重複確認
		chkDuplicate(getTargetOverTimeRequest(dto.getKCode(), dto.getWorkDate()), vo);
		// テーブルロック準備
		prepareTableLock();
		// 対象テーブル追加
		addTargetTable(overRequestDao(), true);
		// ワークフロー登録
		long workflow = requestRegist(mKihon.getKCode(), WorkflowPart.isDraft(key1));
		if (workflow != 0) {
			dto.setWorkflow(workflow);
			// 残業申請
			String maxVaoucher = overRequestDao().findForMax();
			if (maxVaoucher == null || maxVaoucher.equals("")) {
				maxVaoucher = "-1";
			} else {
				overRequestDao().findForUpdate(Integer.parseInt(maxVaoucher));
			}
			// 最大値をセット
			dto.setVoucher(Integer.parseInt(maxVaoucher) + 1);
			overRequestDao().insert(dto);
			chkInsert(getOverTimeRequest(dto.getVoucher()));
			//コミット
			commit();
			// DTOの再取得
			dto = getOverTimeRequest(dto.getVoucher());
			vo.setHidVoucher(String.valueOf(dto.getVoucher()));
			// メッセージ設定
			vo.setMessage(MospUtility.getMessage(msg, CommonConst.MSG_CODE_REQUEST_INSERT, ""));
		} else {
			StringBuffer sb = new StringBuffer();
			sb.append(DatePart.convDateToFormatDateJP(dto.getWorkDate()));
			sb.append(CommonConst.MSG_OF);
			sb.append(CommonConst.NAM_OVER_TIME_REQUEST);
			// エラーメッセージ設定
			vo.addErrMessage(MospUtility.getMessage(msg,
					CommonConst.MSG_CODE_SELECT_CANNOT_INSERT,
					sb.toString()
			));
		}
		// テーブルロック解除
		unLockTables();
		// DTOの表示
		vo.setFields(dto);
		return dto;
	}

	/**
	 * 更新処理
	 * @param vo			対象VO
	 * @param dto			対象DTO
	 * @return
	 * @throws Exception
	 */
	private CtOvertimeRequestDto update(OverTimeRequestCardVo vo, CtOvertimeRequestDto dto) throws Exception {
		vo.setPltRequestYear(String.valueOf(MospUtility.getYear(dto.getWorkDate())));
		vo.setPltRequestMonth(String.valueOf(MospUtility.getMonth(dto.getWorkDate())));
		vo.setPltRequestDay(String.valueOf(MospUtility.getDay(dto.getWorkDate())));
		// パラメーターの妥当性確認
		vo.validate();
		// DTOの準備
		vo.setDtoFields(dto);
		dto.setKCode(mKihon.getKCode());
		dto.setRequestDate(DatePart.getSystemDate());
		// 排他確認
		chkExclusive(dto, overRequestDao().findForUpdate(dto.getVoucher()), vo);
		// 更新
		overRequestDao().update(dto);
		// 更新確認
		chkUpdate(getOverTimeRequest(dto.getVoucher()));
		boolean canCommit = true;
		// 申請更新の場合
		if (!WorkflowPart.isDraft(key1)) {
			// ワークフロー取得
			CtWorkflowDto workflowDto = getWorkflowDto(dto.getWorkflow());
			// 承認状況の変更
			workflowDto.setCurrentStatus(WorkflowPart.getStatusCodeArray()[0]);
			// 勤怠承認コード
			String statusCode = toKintaiApprovalStatus(dto.getWorkflow());
			// 差戻→申請中の場合
			if (KintaiApprovalPart.is1stReturned(statusCode)
					|| KintaiApprovalPart.is2ndReturned(statusCode)
			) {
				// 申請中へ移行
				workflowDto.setLayerNumber(0);
			}
			// ワークフローの更新
			canCommit = workflowRegist(workflowDto, vo);
		}
		if (canCommit) {
			// コミット
			commit();
			// メッセージ設定
			vo.setMessage(MospUtility.getMessage(msg, MospConst.MSG_UPDATE, ""));
		}
		// DTOの再取得
		CtOvertimeRequestDto retDto = getOverTimeRequest(dto.getVoucher());
		chkExist(retDto);
		return retDto;
	}

	/**
	 * 取り下げ処理
	 * @param vo		対象VO
	 * @throws Exception
	 */
	private void cancel(OverTimeRequestCardVo vo, CtOvertimeRequestDto dto) throws Exception {
		// 承認済みの場合、取り下げ不可
		if (!isStatusApproved(dto.getWorkflow())) {
			// 論理削除
			dto.setDeleteFlag(MospConst.DELETE_FLAG_ON);
			overRequestDao().update(dto);
			// ワークフロー
			CtWorkflowDto workflowDto = getWorkflowDto(dto.getWorkflow());
			// 論理削除
			workflowDto.setDeleteFlag(MospConst.DELETE_FLAG_ON);
			workflowRegist(workflowDto, vo);
			// コミット
			commit();
			// 一覧へ遷移
			setNextCmd(OverTimeRequestListAction.CMD_LIST_RE_SEARCH);
			// メッセージをセット
			request.setAttribute(MospConst.ATT_MESSAGE, MospUtility.getMessage(msg,
					CommonConst.MSG_CODE_REQUEST_WITHDRAW,
					""
			));
		} else {
			StringBuffer sb = new StringBuffer();
			sb.append(DatePart.convDateToFormatDateJP(dto.getWorkDate()));
			sb.append(CommonConst.MSG_OF);
			sb.append(CommonConst.NAM_OVER_TIME_REQUEST);
			// エラーメッセージ
			vo.addErrMessage(MospUtility.getMessage(msg,
					CommonConst.MSG_CODE_SELECT_ALREADY_APPROVED,
					sb.toString()
			));
		}
	}

	/**
	 * 承認状況情報の設定
	 * @param vo			対象VO
	 * @param dto			対象DTO
	 * @throws Exception
	 */
	private void setApprovalStatus(
			OverTimeRequestCardVo vo,
			CtOvertimeRequestDto dto
	) throws Exception {
		// 勤怠承認ステータスコード
		String statusCode = toKintaiApprovalStatus(dto.getWorkflow());
		vo.setLblStatus(getApprovalName(statusCode));
		// 下書き
		if (isStatusDraft(dto.getWorkflow())) {
			vo.setMode(OverTimeRequestCardVo.MODE_UPDATE);
		}
		// 申請中
		else if (KintaiApprovalPart.isRequest(statusCode)) {
			vo.setMode(OverTimeRequestCardVo.MODE_REQUEST);
		}
		// 一次承認
		else if (KintaiApprovalPart.is1stApproved(statusCode)) {
			vo.setLblApprover(getKName(getWorkflowDto(dto.getWorkflow()).getUpdateUser()));
			vo.setMode(OverTimeRequestCardVo.MODE_APPROVED);
		}
		// 一次差戻
		else if (KintaiApprovalPart.is1stReturned(statusCode)) {
			vo.setLblApprover(getKName(getWorkflowDto(dto.getWorkflow()).getUpdateUser()));
			// 最新コメントの取得
			vo.setLblComment(getCurrentWorkflowComment(mKihon.getKCode(), dto.getWorkflow()));
			vo.setMode(OverTimeRequestCardVo.MODE_RETURNED);
		}
		// 二次承認
		else if (KintaiApprovalPart.is2ndApproved(statusCode)) {
			vo.setLblApprover(getKName(getWorkflowDto(dto.getWorkflow()).getUpdateUser()));
			vo.setMode(OverTimeRequestCardVo.MODE_APPROVED);
		}
		// 二次差戻
		else if (KintaiApprovalPart.is2ndReturned(statusCode)) {
			vo.setLblApprover(getKName(getWorkflowDto(dto.getWorkflow()).getUpdateUser()));
			// 最新コメントの取得
			vo.setLblComment(getCurrentWorkflowComment(mKihon.getKCode(), dto.getWorkflow()));
			vo.setMode(OverTimeRequestCardVo.MODE_RETURNED);
		}
	}

}
