/*
 * 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.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jp.mosp.common.CommonConst;
import jp.mosp.common.dto.HumanBasisDtoInterface;
import jp.mosp.common.dto.KintaiCommonDtoInterface;
import jp.mosp.common.part.PartInfo;
import jp.mosp.common.utils.DateUtil;
import jp.mosp.common.utils.StringUtil;
import jp.mosp.common.utils.VariousUtil;
import jp.mosp.kintai.common.dto.MKihonDto;
import jp.mosp.workflow.dao.AttendanceRouteDao;
import jp.mosp.workflow.dao.PmAttendanceDao;
import jp.mosp.workflow.dto.AttendanceRouteDto;
import jp.mosp.workflow.dto.PmAttendanceDto;

/**
 * 勤怠承認用Partクラス
 * @author yoshida
 *	@version	0.0.9
 */
public class KintaiApprovalPart extends KintaiBasePart {
	
	/**
	 * コンストラクタ
	 */
	public KintaiApprovalPart() {
		super();
	}
	
	/**
	 * コンストラクタ
	 * @param partInfo Partを利用する際に必要な情報
	 */
	public KintaiApprovalPart(PartInfo partInfo) {
		super(partInfo);
	}
	

	/**
	 * AttendanceRouteDaoインスタンス
	 */
	private AttendanceRouteDao	attendanceRouteDao;
	

	/**
	 * 勤怠承認用ルートテーブル用のDAO取得
	 * @since	0.0.2
	 * @return	初期化済みAttendanceRouteDaoインスタンス
	 * @throws Exception	例外処理が発生した場合
	 */
	public AttendanceRouteDao getAttendanceRouteDao() throws Exception {
		if (VariousUtil.isNull(attendanceRouteDao)) {
			attendanceRouteDao = (AttendanceRouteDao)getPreparedDao(AttendanceRouteDao.class.getCanonicalName());
		}
		return attendanceRouteDao;
	}
	

	/**
	 * PmAttendanceDaoインスタンス
	 */
	private PmAttendanceDao	pmAttendanceDao;
	

	/**
	 * 勤怠承認ルートマスタテーブル用のDAO取得
	 * @since	0.0.2
	 * @return	初期化済みPmAttendanceDaoインスタンス
	 * @throws Exception	例外処理が発生した場合
	 */
	public PmAttendanceDao getPmAttendanceDao() throws Exception {
		if (VariousUtil.isNull(pmAttendanceDao)) {
			pmAttendanceDao = (PmAttendanceDao)getPreparedDao(PmAttendanceDao.class.getCanonicalName());
		}
		return pmAttendanceDao;
	}
	
	/**
	 * 出勤簿申請中フラグ取得
	 * @param snriyuu		対象承認理由
	 * @return
	 * <p>
	 * 申請中ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean isRequest(String snriyuu) {
		return VariousUtil.getApprovalStatusCodeArray()[0].equals(snriyuu);
	}
	
	/**
	 * 出勤簿申請中フラグ取得
	 * @param dto		対象出勤簿DTO
	 * @return
	 * <p>
	 * 申請中ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean isRequest(KintaiCommonDtoInterface dto) {
		if (VariousUtil.isNotNull(dto)) {
			return isRequest(dto.getSnRiyuu());
		}
		return false;
	}
	
	/**
	 * 出勤簿一次承認済フラグ取得
	 * @param snriyuu		対象承認理由
	 * @return
	 * <p>
	 * 承認済ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean is1stApproved(String snriyuu) {
		return VariousUtil.getApprovalStatusCodeArray()[1].equals(snriyuu);
	}
	
	/**
	 * 出勤簿一次承認済フラグ取得
	 * @param dto		対象出勤簿DTO
	 * @return
	 * <p>
	 * 承認済ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean is1stApproved(KintaiCommonDtoInterface dto) {
		if (VariousUtil.isNotNull(dto)) {
			return is1stApproved(dto.getSnRiyuu());
		}
		return false;
	}
	
	/**
	 * 出勤簿一次差戻フラグ取得
	 * @since	0.0.4
	 * @param snriyuu		対象承認理由
	 * @return
	 * <p>
	 * 一次差戻ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean is1stReturned(String snriyuu) {
		return VariousUtil.getApprovalStatusCodeArray()[2].equals(snriyuu);
	}
	
	/**
	 * 出勤簿一次差戻フラグ取得
	 * @since	0.0.4
	 * @param dto		対象出勤簿DTO
	 * @return
	 * <p>
	 * 一次差戻ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean is1stReturned(KintaiCommonDtoInterface dto) {
		if (VariousUtil.isNotNull(dto)) {
			return is1stReturned(dto.getSnRiyuu());
		}
		return false;
	}
	
	/**
	 * 出勤簿二次承認済フラグ取得
	 * @param snriyuu		対象承認理由
	 * @return
	 * <p>
	 * 承認済ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean is2ndApproved(String snriyuu) {
		return VariousUtil.getApprovalStatusCodeArray()[3].equals(snriyuu);
	}
	
	/**
	 * 出勤簿二次承認済フラグ取得
	 * @param dto		対象出勤簿DTO
	 * @return
	 * <p>
	 * 承認済ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean is2ndApproved(KintaiCommonDtoInterface dto) {
		if (VariousUtil.isNotNull(dto)) {
			return is2ndApproved(dto.getSnRiyuu());
		}
		return false;
	}
	
	/**
	 * 出勤簿二次承認済フラグ取得
	 * @since	0.0.4
	 * @param snriyuu		対象承認理由
	 * @return
	 * <p>
	 * 二次差戻済ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean is2ndReturned(String snriyuu) {
		return VariousUtil.getApprovalStatusCodeArray()[4].equals(snriyuu);
	}
	
	/**
	 * 出勤簿二次承認済フラグ取得
	 * @since	0.0.4
	 * @param dto		対象出勤簿DTO
	 * @return
	 * <p>
	 * 二次差戻済ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean is2ndReturned(KintaiCommonDtoInterface dto) {
		if (VariousUtil.isNotNull(dto)) {
			return is2ndReturned(dto.getSnRiyuu());
		}
		return false;
	}
	
	/**
	 * 出勤簿承認済フラグ取得
	 * @param dto		対象出勤簿DTO
	 * @return
	 * <p>
	 * 承認済ならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean isApproved(KintaiCommonDtoInterface dto) {
		if (VariousUtil.isNotNull(dto)) {
			if (is1stApproved(dto) || is2ndApproved(dto)) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 出勤簿下書きフラグ取得
	 * @since	0.0.7
	 * @param snriyuu		対象承認理由
	 * @return
	 * <p>
	 * 下書きならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean isDraft(String snriyuu) {
		return VariousUtil.getApprovalStatusCodeArray()[5].equals(snriyuu) || StringUtil.isNull(snriyuu);
	}
	
	/**
	 * 出勤簿下書きフラグ取得
	 * @since	0.0.7
	 * @param dto		対象出勤簿DTO
	 * @return
	 * <p>
	 * 下書きならtrue、そうでない場合false
	 * </p>
	 */
	public static boolean isDraft(KintaiCommonDtoInterface dto) {
		if (VariousUtil.isNotNull(dto)) {
			return isDraft(dto.getSnRiyuu());
		}
		return false;
	}
	
	/**
	 * 利用可能勤怠承認ルート情報一覧
	 * @since	0.0.2
	 * @param kCode  対象社員コード
	 * @param targetDate	対象年月日
	 * @return 現状所属承認ユニットコードリスト
	 * @throws Exception	例外処理が発生した場合
	 */
	public String[][] getBelongRouteInfoArray(String kCode, Date targetDate) throws Exception {
		// 情報の取得
		List<AttendanceRouteDto> listRoute = getAttendanceRouteList(kCode, targetDate);
		String[][] aryRoute = new String[listRoute.size()][5];
		for (int i = 0; i < aryRoute.length; i++) {
			aryRoute[i][0] = listRoute.get(i).getSCode();
			aryRoute[i][1] = listRoute.get(i).getKCode();
			aryRoute[i][2] = listRoute.get(i).getLayer1();
			aryRoute[i][3] = listRoute.get(i).getLastLayer();
			aryRoute[i][4] = listRoute.get(i).getJCode();
		}
		return aryRoute;
	}
	
	/**
	 * 利用可能勤怠承認ルート情報一覧
	 * @since	0.0.2
	 * @param kCode 		対象社員コード
	 * @param approver		承認者社員コード
	 * @param targetDate	対象年月日
	 * @return 現状所属承認ユニットコードリスト
	 * <p>
	 * [0]…一次承認ルートコード
	 * [1]…二次承認ルートコード
	 * </p>
	 * @throws Exception	例外処理が発生した場合
	 */
	public String[] getTargetRouteInfo(String kCode, String approver, Date targetDate) throws Exception {
		// 出力配列
		String[] aryRoute = StringUtil.getBlankArrayOneDimension(2);
		List<AttendanceRouteDto> routeList = getAttendanceRouteList(approver, targetDate);
		Map<String, AttendanceRouteDto> kCodeMap = new HashMap<String, AttendanceRouteDto>();
		Map<String, AttendanceRouteDto> sectionMap = new HashMap<String, AttendanceRouteDto>();
		for (AttendanceRouteDto dto : routeList) {
			// 社員コード
			if (StringUtil.isNotNull(dto.getKCode())) {
				kCodeMap.put(dto.getKCode(), dto);
			}
			// 事業所、所属コード
			if (StringUtil.isNotNull(dto.getJCode()) && StringUtil.isNotNull(dto.getSCode())) {
				StringBuffer sb = new StringBuffer();
				sb.append(dto.getJCode());
				sb.append(CommonConst.STR_UNDER_SEPARATOR);
				sb.append(dto.getSCode());
				sectionMap.put(sb.toString(), dto);
			}
		}
		// 対象社員情報
		HumanBasisDtoInterface humanBasis = part().human().getMKihonDao().findForApprovalKCode(kCode,
				part().human().getBasisInfo(approver).getJCode(),
				part().mospuser().getUserInfoForKCode(approver).getDataLevel(),
				DateUtil.convDateToInteger(part().calculate().getStartDate(targetDate)));
		if (VariousUtil.isNotNull(humanBasis)) {
			// 社員コード
			if (kCodeMap.containsKey(humanBasis.getKCode())) {
				aryRoute[0] = kCodeMap.get(kCode).getLayer1();
				aryRoute[1] = kCodeMap.get(kCode).getLastLayer();
			} else {
				// 事業所コード、所属コード
				StringBuffer sectionKey = new StringBuffer();
				sectionKey.append(humanBasis.getJCode());
				sectionKey.append(CommonConst.STR_UNDER_SEPARATOR);
				sectionKey.append(humanBasis.getSCode());
				if (sectionMap.containsKey(sectionKey.toString())) {
					aryRoute[0] = sectionMap.get(sectionKey.toString()).getLayer1();
					aryRoute[1] = sectionMap.get(sectionKey.toString()).getLastLayer();
				}
			}
		}
		return aryRoute;
	}
	
	/**
	 * 承認理由配列取得
	 * @since	0.0.3
	 * @return	承認理由配列
	 * @throws Exception	例外処理が発生した場合
	 */
	public String[][] getApprovalReasonArray() throws Exception {
		// 承認理由
		return part().mospcode().getMosPCodeArray(CommonConst.TID_APPROVAL_REASON);
	}
	
	/**
	 * 承認理由表示
	 * @since	0.0.3
	 * @param riyuu 承認理由
	 * @return	result
	 * @throws Exception 	例外処理が発生した場合
	 */
	public String[] getApproval(String riyuu) throws Exception {
		String[][] aryApprovalReason = getApprovalReasonArray();
		String[] result = new String[2];
		if (KintaiApprovalPart.isRequest(riyuu)) {
			// 申請中の場合（一次…申請中、二次…空欄）
			result[0] = aryApprovalReason[0][1];
			result[1] = "";
		} else if (KintaiApprovalPart.is1stApproved(riyuu)) {
			// 一次承認済の場合（一次…承認済、二次申請中）
			result[0] = aryApprovalReason[1][1];
			result[1] = aryApprovalReason[0][1];
		} else if (riyuu.equals(CommonConst.NUM_ATTENDANCE_1ST_RETURNED)) {
			// 一次差戻の場合（一次…差戻、二次…空欄）
			result[0] = aryApprovalReason[2][1];
			result[1] = "";
		} else if (KintaiApprovalPart.is2ndApproved(riyuu)) {
			// 二次承認済の場合（一次…承認済、二次承認済）
			result[0] = aryApprovalReason[1][1];
			result[1] = aryApprovalReason[3][1];
		} else if (riyuu.equals(CommonConst.NUM_ATTENDANCE_2ND_RETURNED)) {
			// 一次差戻の場合（一次…二次差戻、二次…空欄）
			result[0] = aryApprovalReason[4][1];
			result[1] = "";
		} else {
			result[0] = "";
			result[1] = "";
		}
		return result;
	}
	
	/**
	 * 勤怠承認状況名称取得
	 * @since	0.0.3
	 * @param snRiyuu		勤怠承認状況コード
	 * @return				勤怠承認状況名称
	 * @throws Exception	例外処理が発生した場合
	 */
	public String getApprovalName(String snRiyuu) throws Exception {
		return part().mospcode().getTName(CommonConst.TID_APPROVAL_REASON, snRiyuu);
	}
	
	/**
	 * 勤怠承認状況名称取得
	 * @since	0.0.3
	 * @param dto		対象DTO
	 * @return			勤怠承認状況名称
	 * @throws Exception	例外処理が発生した場合
	 */
	public String getApprovalName(KintaiCommonDtoInterface dto) throws Exception {
		return getApprovalName(dto.getSnRiyuu());
	}
	
	/**
	 * 承認対象者一覧
	 * @since	0.0.4
	 * @param kCode			対象承認者社員コード
	 * @param targetDate	対象年月日
	 * @return	承認対象者一覧
	 * @throws Exception	例外処理が発生した場合
	 */
	public List<MKihonDto> getApprovalEmployeeList(String kCode, Date targetDate) throws Exception {
		// 情報の設定
		List<MKihonDto> listEmployee = new ArrayList<MKihonDto>();
		List<AttendanceRouteDto> listRoute = getAttendanceRouteList(kCode, targetDate);
		Set<String> employeeKCodeSet = new HashSet<String>();
		for (AttendanceRouteDto dto : listRoute) {
			// 対象所属社員一覧
			List<MKihonDto> selectSectionUserList = part().human().getMKihonDao().findForApproval(dto.getSCode(),
					part().office().getBelongOfficeCode(kCode), kCode,
					part().mospuser().getUserInfoForKCode(kCode).getDataLevel(),
					DateUtil.convDateToInteger(part().calculate().getStartDate(targetDate)));
			for (MKihonDto mKihonDto : selectSectionUserList) {
				employeeKCodeSet.add(mKihonDto.getKCode());
			}
			// 追加社員情報
			MKihonDto addMKihonDto = part().human().getBasisInfo(dto.getKCode());
			if (VariousUtil.chkExistDto(addMKihonDto)) {
				employeeKCodeSet.add(addMKihonDto.getKCode());
			}
		}
		// 社員情報を一覧へ追加
		for (String employeeKCode : employeeKCodeSet) {
			listEmployee.add(part().human().getBasisInfo(employeeKCode));
		}
		return listEmployee;
	}
	
	/**
	 * 対象勤怠承認ルート一覧リスト取得
	 * @since	0.0.5
	 * @param kCode			対象承認者社員コード
	 * @param targetDate	対象年月日
	 * @return list 検索結果(DTOのList)
	 * @throws Exception	例外処理が発生した場合
	 */
	public List<AttendanceRouteDto> getAttendanceRouteList(String kCode, Date targetDate) throws Exception {
		return getAttendanceRouteDao().findForApproval(kCode, part().section().getBelongSectionCode(kCode),
				part().office().getBelongOfficeCode(kCode),
				DateUtil.convDateFormattedByHyphen(part().calculate().getStartDate(targetDate)));
	}
	
	/**
	 * 対象社員勤怠承認ルートコード取得
	 * @since	0.0.5
	 * @param kCode		対象社員コード
	 * @return	勤怠承認ルートコード
	 * @throws Exception	例外処理が発生した場合
	 */
	public String getRequestRouteCode(String kCode) throws Exception {
		PmAttendanceDto dto = getPmAttendanceDao().findForKCode(kCode);
		if (VariousUtil.isNull(dto)) {
			dto = getPmAttendanceDao().findForRequest(part().section().getBelongSectionCode(kCode),
					part().office().getBelongOfficeCode(kCode));
		}
		if (VariousUtil.chkExistDto(dto)) {
			return dto.getRtCode();
		}
		return "";
	}
	
	/**
	 * 勤怠承認ワークフロー承認状況コード取得
	 * @since	0.0.6
	 * @param snriyuu	対象勤怠承認コード
	 * @return
	 * <p>
	 * [0]…承認階層
	 * [1]…承認状況
	 * </p>
	 */
	public static String[] toWorkflowStatusArray(String snriyuu) {
		return new String[]{ toWorkflowLayer(snriyuu), toWorkflowStatus(snriyuu) };
	}
	
	/**
	 * 承認階層取得
	 * @since	0.0.9
	 * @param snriyuu	対象勤怠承認コード
	 * @return	承認階層
	 */
	public static String toWorkflowLayer(String snriyuu) {
		String number = "";
		if (isRequest(snriyuu) || isDraft(snriyuu)) {
			number = String.valueOf(CommonConst.NUM_REQUEST_LAYER);
		}
		if (is1stApproved(snriyuu) || is1stReturned(snriyuu)) {
			number = String.valueOf(CommonConst.NUM_LAYER1);
		}
		if (is2ndApproved(snriyuu) || is2ndReturned(snriyuu)) {
			number = String.valueOf(CommonConst.NUM_LAST_LAYER);
		}
		return number;
	}
	
	/**
	 * 承認状況名称取得
	 * @since	0.0.9
	 * @param snriyuu	対象勤怠承認コード
	 * @return	承認状況
	 */
	public static String toWorkflowStatus(String snriyuu) {
		String status = "";
		if (StringUtil.isNotNull(snriyuu)) {
			if (isRequest(snriyuu)) {
				status = WorkflowPart.getStatusCodeArray()[0];
			}
			if (is1stApproved(snriyuu) || is2ndApproved(snriyuu)) {
				status = WorkflowPart.getStatusCodeArray()[1];
			}
			if (is1stReturned(snriyuu) || is2ndReturned(snriyuu)) {
				status = WorkflowPart.getStatusCodeArray()[2];
			}
			// 下書き
			if (isDraft(snriyuu)) {
				status = WorkflowPart.getStatusCodeArray()[4];
			}
		}
		return status;
	}
	
	/**
	 * 勤怠承認者判断
	 * @since	0.0.9
	 * @param kCode			対象社員コード
	 * @param approver		対象承認者社員コード
	 * @param snriyuu	承認状況コード
	 * @param targetDate	対象年月日
	 * @return
	 * <p>
	 * 勤怠承認者である場合true、そうでない場合false
	 * </p>
	 * @throws Exception	例外処理が発生した場合
	 */
	public boolean isApprover(String kCode, String approver, String snriyuu, Date targetDate) throws Exception {
		String[] aryRouteinfo = getTargetRouteInfo(kCode, approver, targetDate);
		boolean is1stApprover = part().approval().isApprover(aryRouteinfo[0], approver, targetDate);
		boolean is2ndApprover = part().approval().isApprover(aryRouteinfo[1], approver, targetDate);
		if (StringUtil.isNull(snriyuu)) {
			return is1stApprover || is2ndApprover;
		} else {
			if (isRequest(snriyuu)) {
				return is1stApprover;
			}
			if (is1stApproved(snriyuu)) {
				return is2ndApprover;
			}
			return false;
		}
	}
	
}
