/*
 * 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 Affero General Public License
 * as published by the Free Software Foundation, either version 3
 * 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package jp.mosp.platform.bean.workflow.impl;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import jp.mosp.framework.base.MospException;
import jp.mosp.framework.base.MospParams;
import jp.mosp.framework.utils.MospUtility;
import jp.mosp.platform.base.PlatformBean;
import jp.mosp.platform.bean.human.ConcurrentReferenceBeanInterface;
import jp.mosp.platform.bean.human.HumanReferenceBeanInterface;
import jp.mosp.platform.bean.human.HumanSearchBeanInterface;
import jp.mosp.platform.bean.workflow.ApprovalRouteReferenceBeanInterface;
import jp.mosp.platform.bean.workflow.ApprovalRouteUnitReferenceBeanInterface;
import jp.mosp.platform.bean.workflow.ApprovalUnitReferenceBeanInterface;
import jp.mosp.platform.bean.workflow.RouteApplicationReferenceBeanInterface;
import jp.mosp.platform.bean.workflow.SubApproverReferenceBeanInterface;
import jp.mosp.platform.bean.workflow.WorkflowIntegrateBeanInterface;
import jp.mosp.platform.bean.workflow.WorkflowReferenceBeanInterface;
import jp.mosp.platform.constant.PlatformConst;
import jp.mosp.platform.constant.PlatformMessageConst;
import jp.mosp.platform.dto.human.ConcurrentDtoInterface;
import jp.mosp.platform.dto.human.HumanDtoInterface;
import jp.mosp.platform.dto.workflow.ApprovalRouteDtoInterface;
import jp.mosp.platform.dto.workflow.ApprovalRouteUnitDtoInterface;
import jp.mosp.platform.dto.workflow.ApprovalUnitDtoInterface;
import jp.mosp.platform.dto.workflow.RouteApplicationDtoInterface;
import jp.mosp.platform.dto.workflow.SubApproverDtoInterface;
import jp.mosp.platform.dto.workflow.WorkflowDtoInterface;

/**
 * ワークフロー統括クラス。
 */
public class WorkflowIntegrateBean extends PlatformBean implements WorkflowIntegrateBeanInterface {
	
	/**
	 * ワークフロー参照クラス。
	 */
	protected WorkflowReferenceBeanInterface			workflowReference;
	
	/**
	 * 承認ルート適用参照クラス。
	 */
	protected RouteApplicationReferenceBeanInterface	applicationReference;
	
	/**
	 * 承認ルート参照クラス。
	 */
	protected ApprovalRouteReferenceBeanInterface		routeReference;
	
	/**
	 * 承認ルートユニット情報参照クラス。
	 */
	protected ApprovalRouteUnitReferenceBeanInterface	routeUnitReference;
	
	/**
	 * 承認ユニット参照クラス。
	 */
	protected ApprovalUnitReferenceBeanInterface		unitReference;
	
	/**
	 * 人事マスタ検索クラス。
	 */
	protected HumanSearchBeanInterface					humanSearch;
	
	/**
	 * 人事マスタ参照クラス。
	 */
	protected HumanReferenceBeanInterface				humanReference;
	
	/**
	 * 代理承認者テーブル参照クラス。
	 */
	protected SubApproverReferenceBeanInterface			subApproverReference;
	

	/**
	 * {@link PlatformBean#PlatformBean()}を実行する。<br>
	 */
	public WorkflowIntegrateBean() {
		super();
	}
	
	/**
	 * {@link PlatformBean#PlatformBean(MospParams, Connection)}を実行する。<br>
	 * @param mospParams MosP処理情報
	 * @param connection DBコネクション
	 */
	public WorkflowIntegrateBean(MospParams mospParams, Connection connection) {
		super(mospParams, connection);
	}
	
	@Override
	public void initBean() throws MospException {
		routeReference = (ApprovalRouteReferenceBeanInterface)createBean(ApprovalRouteReferenceBeanInterface.class);
		applicationReference = (RouteApplicationReferenceBeanInterface)createBean(RouteApplicationReferenceBeanInterface.class);
		routeUnitReference = (ApprovalRouteUnitReferenceBeanInterface)createBean(ApprovalRouteUnitReferenceBeanInterface.class);
		unitReference = (ApprovalUnitReferenceBeanInterface)createBean(ApprovalUnitReferenceBeanInterface.class);
		humanSearch = (HumanSearchBeanInterface)createBean(HumanSearchBeanInterface.class);
		humanReference = (HumanReferenceBeanInterface)createBean(HumanReferenceBeanInterface.class);
		workflowReference = (WorkflowReferenceBeanInterface)createBean(WorkflowReferenceBeanInterface.class);
		subApproverReference = (SubApproverReferenceBeanInterface)createBean(SubApproverReferenceBeanInterface.class);
	}
	
	@Override
	public WorkflowDtoInterface getLatestWorkflowInfo(long workflow) throws MospException {
		return workflowReference.getLatestWorkflowInfo(workflow);
	}
	
	/**
	 * ルート適用情報にルート{@link PlatformConst#APPROVAL_ROUTE_SELF}が設定されていた場合は、
	 * 承認者リスト(自己承認)を返す。<br>
	 * ルート適用情報にその他のルートが設定されていた場合は、ルート情報からユニット情報を取得し
	 * 承認者リストを作成する。<br>
	 * ルート適用情報が取得できなかった場合は、空のリストを返す。<br>
	 */
	@Override
	public List<List<String[]>> getRouteApproverList(String personalId, Date targetDate, int workflowType)
			throws MospException {
		// ルート承認者リスト準備
		List<List<String[]>> routeApproverList = new ArrayList<List<String[]>>();
		// ルート適用情報取得及び確認
		RouteApplicationDtoInterface routeApplicationDto = findForPerson(personalId, targetDate, workflowType);
		if (routeApplicationDto == null) {
			return routeApproverList;
		}
		// ルートコード取得
		String routeCode = routeApplicationDto.getRouteCode();
		// 自己承認確認
		if (routeCode.equals(PlatformConst.APPROVAL_ROUTE_SELF)) {
			// 承認者リスト(自己承認)作成(自己承認の場合の承認階層は1)
			routeApproverList.add(getSelfApproverList());
			return routeApproverList;
		}
		// ルート情報取得及び確認
		ApprovalRouteDtoInterface routeDto = routeReference.getApprovalRouteInfo(routeCode, targetDate);
		if (routeDto == null) {
			return routeApproverList;
		}
		// 承認ルートユニット取得(承認階層順)
		List<ApprovalRouteUnitDtoInterface> unitList = routeUnitReference.getApprovalRouteUnitList(routeCode,
				targetDate);
		// ユニット毎に承認者を設定
		for (ApprovalRouteUnitDtoInterface routeUnitDto : unitList) {
			// ユニット承認者リスト取得
			List<HumanDtoInterface> unitAppriverList = getUnitApproverList(routeUnitDto.getUnitCode(), targetDate);
			// 代理承認者を設定しルート承認者リストに追加
			routeApproverList.add(getApproverList(unitAppriverList, personalId, targetDate, workflowType));
		}
		return routeApproverList;
	}
	
	@Override
	public Collection<WorkflowDtoInterface> getList(String personalId, Date startDate, Date endDate, String functionCode)
			throws MospException {
		Map<Long, WorkflowDtoInterface> map = new HashMap<Long, WorkflowDtoInterface>();
		// ワークフローに設定されている承認者個人IDで取得
		List<WorkflowDtoInterface> approverList = workflowReference.getListForApproverId(functionCode, personalId);
		// ワークフロー毎に段階及び状態を確認して操作対象ワークフローリストに追加
		for (WorkflowDtoInterface dto : approverList) {
			if (PlatformConst.CODE_STATUS_APPLY.equals(dto.getWorkflowStatus())
					|| PlatformConst.CODE_STATUS_APPROVED.equals(dto.getWorkflowStatus())
					|| PlatformConst.CODE_STATUS_REVERT.equals(dto.getWorkflowStatus())
					|| PlatformConst.CODE_STATUS_CANCEL.equals(dto.getWorkflowStatus())
					|| PlatformConst.CODE_STATUS_COMPLETE.equals(dto.getWorkflowStatus())) {
				// 未承認・承認済(最終承認済でない)・差戻・承認解除・最終承認済(完了)の場合
				map.put(dto.getWorkflow(), dto);
			}
		}
		// 承認対象の申請一覧
		Date targetDate = startDate;
		while (!targetDate.after(endDate)) {
			List<ApprovalRouteUnitDtoInterface> unitList = getListForApprover(personalId, targetDate);
			for (ApprovalRouteUnitDtoInterface approvalRouteUnitDto : unitList) {
				List<WorkflowDtoInterface> workflowList = workflowReference.getListForRoute("", approvalRouteUnitDto
					.getRouteCode(), functionCode);
				for (WorkflowDtoInterface dto : workflowList) {
					if (PlatformConst.CODE_STATUS_APPLY.equals(dto.getWorkflowStatus())
							|| PlatformConst.CODE_STATUS_APPROVED.equals(dto.getWorkflowStatus())
							|| PlatformConst.CODE_STATUS_REVERT.equals(dto.getWorkflowStatus())
							|| PlatformConst.CODE_STATUS_CANCEL.equals(dto.getWorkflowStatus())
							|| PlatformConst.CODE_STATUS_COMPLETE.equals(dto.getWorkflowStatus())) {
						// 未承認・承認済(最終承認済でない)・差戻・承認解除・最終承認済(完了)の場合
						if (!map.containsKey(dto.getWorkflow())) {
							// mapにない場合
							map.put(dto.getWorkflow(), dto);
						}
					}
				}
			}
			targetDate = addDay(targetDate, 1);
		}
		return map.values();
	}
	
	@Override
	public List<WorkflowDtoInterface> getListForNonApproved(String personalId, Date targetDate, String functionCode)
			throws MospException {
		// 操作対象ワークフローリスト準備
		List<WorkflowDtoInterface> list = new ArrayList<WorkflowDtoInterface>();
		// ワークフローに設定されている承認者個人IDで取得
		List<WorkflowDtoInterface> approverList = workflowReference.getListForApproverId(functionCode, personalId);
		// ワークフロー毎に段階及び状態を確認して操作対象ワークフローリストに追加
		for (WorkflowDtoInterface dto : approverList) {
			// 操作権確認
			if (isApprover(dto, personalId) == false) {
				continue;
			}
			// ワークフロー状態取得
			String workflowStatus = dto.getWorkflowStatus();
			// 未承認
			if (PlatformConst.CODE_STATUS_APPLY.equals(workflowStatus)) {
				list.add(dto);
				continue;
			}
			// 承認済(最終承認済でない)
			if (PlatformConst.CODE_STATUS_APPROVED.equals(workflowStatus)) {
				list.add(dto);
				continue;
			}
			// 差戻
			if (PlatformConst.CODE_STATUS_REVERT.equals(workflowStatus)) {
				list.add(dto);
			}
			// 承認解除
			if (PlatformConst.CODE_STATUS_CANCEL.equals(workflowStatus)) {
				list.add(dto);
			}
		}
		// 承認対象の申請一覧
		// 重複チェック用List
		List<WorkflowDtoInterface> dupliCheckList = new ArrayList<WorkflowDtoInterface>();
		List<ApprovalRouteUnitDtoInterface> unitList = getListForApprover(personalId, targetDate);
		for (ApprovalRouteUnitDtoInterface dto : unitList) {
			int approvalStage = dto.getApprovalStage();
			String routeCode = dto.getRouteCode();
			ApprovalRouteDtoInterface approvalRouteDto = routeReference.getApprovalRouteInfo(routeCode, targetDate);
			if (approvalStage > 0) {
				if (approvalStage == 1) {
					// 未承認
					dupliCheckList.addAll(workflowReference.getListForRoute(approvalStage,
							PlatformConst.CODE_STATUS_APPLY, routeCode, functionCode));
				} else {
					// (stage -1)次承認済
					dupliCheckList.addAll(workflowReference.getListForRoute(approvalStage - 1,
							PlatformConst.CODE_STATUS_APPROVED, routeCode, functionCode));
				}
				// (stage +1)次差戻
				dupliCheckList.addAll(workflowReference.getListForRoute(approvalStage + 1,
						PlatformConst.CODE_STATUS_REVERT, routeCode, functionCode));
				// 最終承認者
				if (approvalRouteDto.getApprovalCount() == approvalStage) {
					dupliCheckList.addAll(workflowReference.getListForRoute(10, PlatformConst.CODE_STATUS_CANCEL,
							routeCode, functionCode));
				}
			}
		}
		// ワークフローの重複チェック
		for (int i = 0; i < list.size(); i++) {
			if (dupliCheckList.size() == 0) {
				dupliCheckList.addAll(list);
				break;
			}
			int workflowFlg = 0;
			for (int j = 0; j < dupliCheckList.size(); j++) {
				if (dupliCheckList.get(j).getWorkflow() == list.get(i).getWorkflow()) {
					workflowFlg = 1;
					break;
				}
			}
			if (workflowFlg != 1) {
				dupliCheckList.add(list.get(i));
			}
		}
		return dupliCheckList;
	}
	
	@Override
	public List<ApprovalRouteUnitDtoInterface> getListForApprover(String personalId, Date targetDate)
			throws MospException {
		Map<Long, ApprovalUnitDtoInterface> unitMap = new HashMap<Long, ApprovalUnitDtoInterface>();
		// 承認者個人ID
		List<ApprovalUnitDtoInterface> unitList = unitReference.findForApproverPersonalId(personalId, targetDate);
		for (ApprovalUnitDtoInterface dto : unitList) {
			unitMap.put(dto.getPfmApprovalUnitId(), dto);
		}
		// 承認者所属コード、承認者職位コード
		HumanDtoInterface humanDto = getHumanInfo(personalId, targetDate);
		unitList = unitReference.findForApproverSection(humanDto.getSectionCode(), humanDto.getPositionCode(),
				targetDate);
		for (ApprovalUnitDtoInterface dto : unitList) {
			unitMap.put(dto.getPfmApprovalUnitId(), dto);
		}
		// 兼務
		ConcurrentReferenceBeanInterface concurrentReference;
		concurrentReference = (ConcurrentReferenceBeanInterface)createBean(ConcurrentReferenceBeanInterface.class);
		List<ConcurrentDtoInterface> concurrentList = concurrentReference.getConcurrentList(personalId, targetDate);
		for (ConcurrentDtoInterface concurrentDto : concurrentList) {
			unitList = unitReference.findForApproverSection(concurrentDto.getSectionCode(), concurrentDto
				.getPositionCode(), targetDate);
			for (ApprovalUnitDtoInterface dto : unitList) {
				unitMap.put(dto.getPfmApprovalUnitId(), dto);
			}
		}
		// MapからListへ変換。
		unitList.clear();
		Set<Entry<Long, ApprovalUnitDtoInterface>> unitSet = unitMap.entrySet();
		for (Entry<Long, ApprovalUnitDtoInterface> entry : unitSet) {
			unitList.add(entry.getValue());
		}
		Map<Long, ApprovalRouteUnitDtoInterface> map = new HashMap<Long, ApprovalRouteUnitDtoInterface>();
		for (ApprovalUnitDtoInterface unitDto : unitList) {
			List<ApprovalRouteUnitDtoInterface> list = routeUnitReference.findForApprovalUnit(unitDto.getUnitCode(),
					targetDate);
			for (ApprovalRouteUnitDtoInterface dto : list) {
				map.put(dto.getPfaApprovalRouteUnitId(), dto);
			}
		}
		// MapからListへ変換。
		List<ApprovalRouteUnitDtoInterface> list = new ArrayList<ApprovalRouteUnitDtoInterface>();
		Set<Entry<Long, ApprovalRouteUnitDtoInterface>> set = map.entrySet();
		for (Entry<Long, ApprovalRouteUnitDtoInterface> entry : set) {
			list.add(entry.getValue());
		}
		return list;
	}
	
	@Override
	public List<SubApproverDtoInterface> findForSubApproverId(String subApproverId, int workflowType, Date termStart,
			Date termEnd) throws MospException {
		return subApproverReference.findForSubApproverId(subApproverId, workflowType, termStart, termEnd);
	}
	
	@Override
	public HumanDtoInterface findSubApprover(String personalId, int workflowType, Date targetDate) throws MospException {
		// 代理承認情報取得(システム日付で取得)
		SubApproverDtoInterface dto = subApproverReference.findForDate(personalId, workflowType, getSystemDate());
		// 代理承認情報確認
		if (dto == null) {
			return null;
		}
		// 人事情報取得
		return humanReference.getHumanInfo(dto.getSubApproverId(), targetDate);
	}
	
	@Override
	public RouteApplicationDtoInterface findForPerson(String personalId, Date targetDate, int workflowType)
			throws MospException {
		return applicationReference.findForPerson(personalId, targetDate, workflowType);
	}
	
	@Override
	public List<WorkflowDtoInterface> getListForApproved(String personalId, Date targetDate, String functionCode)
			throws MospException {
		// 操作対象ワークフローリスト準備
		List<WorkflowDtoInterface> list = new ArrayList<WorkflowDtoInterface>();
		// ワークフローに設定されている承認者個人IDで取得
		List<WorkflowDtoInterface> approverList = workflowReference.getListForApproverId(functionCode, personalId);
		// ワークフロー毎に段階及び状態を確認して操作対象ワークフローリストに追加
		for (WorkflowDtoInterface dto : approverList) {
			// 操作権確認
			if (isApprover(dto, personalId) == false) {
				continue;
			}
			// ワークフロー状態取得
			String workflowStatus = dto.getWorkflowStatus();
			// 最終承認済(完了)の場合
			if (PlatformConst.CODE_STATUS_COMPLETE.equals(workflowStatus)) {
				list.add(dto);
			}
		}
		// TODO 自己承認のワークフローを取得して追加
		// 承認対象の申請一覧
		// 重複チェック用List
		List<WorkflowDtoInterface> dupliCheckList = new ArrayList<WorkflowDtoInterface>();
		List<ApprovalRouteUnitDtoInterface> unitList = getListForApprover(personalId, targetDate);
		for (ApprovalRouteUnitDtoInterface dto : unitList) {
			int approvalStage = dto.getApprovalStage();
			String routeCode = dto.getRouteCode();
			ApprovalRouteDtoInterface approvalRouteDto = routeReference.getApprovalRouteInfo(routeCode, targetDate);
			if (approvalStage > 0) {
				// 最終承認者
				if (approvalRouteDto.getApprovalCount() == approvalStage) {
					dupliCheckList.addAll(workflowReference.getListForRoute(10, PlatformConst.CODE_STATUS_COMPLETE,
							routeCode, functionCode));
				}
			}
		}
		// ワークフローの重複チェック
		for (int i = 0; i < dupliCheckList.size(); i++) {
			if (list.size() == 0) {
				list.addAll(dupliCheckList);
				break;
			}
			int workflowFlg = 0;
			for (int j = 0; j < list.size(); j++) {
				if (list.get(j).getWorkflow() == dupliCheckList.get(i).getWorkflow()) {
					workflowFlg = 1;
					break;
				}
			}
			if (workflowFlg != 1) {
				list.add(dupliCheckList.get(i));
			}
		}
		return list;
	}
	
	@Override
	public String getWorkflowStatus(String status, int stage) {
		// ワークフロー状態確認
		if (PlatformConst.CODE_STATUS_DRAFT.equals(status)) {
			// 下書
			return getNameDraft();
		}
		if (PlatformConst.CODE_STATUS_APPLY.equals(status)) {
			// 未承認
			return getNameNotApproved();
		}
		if (PlatformConst.CODE_STATUS_CANCEL.equals(status)) {
			// 承解除
			return getNameRelease();
		}
		if (PlatformConst.CODE_STATUS_WITHDRAWN.equals(status)) {
			// 取下
			return getNameWithdraw();
		}
		if (PlatformConst.CODE_STATUS_COMPLETE.equals(status)) {
			// 承認済
			return getNameFinish();
		}
		if (PlatformConst.CODE_STATUS_APPROVED.equals(status)) {
			// n次済
			return getNameStageApprove(stage - 1);
		}
		if (PlatformConst.CODE_STATUS_REVERT.equals(status)) {
			// n次戻
			return getNameStageRemand(stage + 1);
		}
		return status;
	}
	
	@Override
	public String getWorkflowOperation(String status) {
		// ワークフロー状態確認
		if (PlatformConst.CODE_STATUS_DRAFT.equals(status)) {
			// 下書
			return getNameDraft();
		} else if (status.equals(PlatformConst.CODE_STATUS_APPLY)) {
			// 申請
			return getNameApply();
		} else if (status.equals(PlatformConst.CODE_STATUS_APPROVED)) {
			// 承認
			return getNameApprove();
		} else if (status.equals(PlatformConst.CODE_STATUS_REVERT)) {
			// 差戻
			return getNameRemand();
		} else if (status.equals(PlatformConst.CODE_STATUS_CANCEL)) {
			// 承解除(取消)
			return getNameRelease();
		} else if (status.equals(PlatformConst.CODE_STATUS_WITHDRAWN)) {
			// 取下
			return getNameWithdraw();
		} else if (status.equals(PlatformConst.CODE_STATUS_COMPLETE)) {
			// 承認(最終承認)
			return getNameApprove();
		}
		return status;
	}
	
	@Override
	public boolean isFinalApprover(WorkflowDtoInterface dto, String personalId, Date targetDate) throws MospException {
		// 操作権を持つ段階を取得
		if (dto == null) {
			return false;
		}
		int finalStage = 0;
		int approverStage = 0;
		if (dto.getApproverId().isEmpty()) {
			ApprovalRouteDtoInterface routeDto = routeReference.getApprovalRouteInfo(dto.getRouteCode(), targetDate);
			if (routeDto == null) {
				return false;
			}
			finalStage = routeDto.getApprovalCount();
			ApprovalRouteUnitDtoInterface routeUnitDto = routeUnitReference.findForKey(routeDto.getRouteCode(),
					routeDto.getActivateDate(), routeDto.getApprovalCount());
			if (routeUnitDto == null) {
				return false;
			}
			List<HumanDtoInterface> humanList = getUnitApproverList(routeUnitDto.getUnitCode(), targetDate);
			for (HumanDtoInterface humanDto : humanList) {
				if (personalId.equals(humanDto.getPersonalId())) {
					approverStage = routeDto.getApprovalCount();
					break;
				}
			}
		} else {
			String[] approverArray = split(dto.getApproverId(), SEPARATOR_DATA);
			finalStage = approverArray.length;
			int i = 1;
			for (String approver : approverArray) {
				if (approver.equals(personalId)) {
					approverStage = i;
					break;
				}
				i++;
			}
		}
		if (approverStage == finalStage) {
			return true;
		}
		return false;
	}
	
	/**
	 * 対象ワークフローにおいて、対象個人IDが操作権を持つかどうかを確認する。<br>
	 * @param dto        対象ワークフロー情報
	 * @param personalId 対象個人ID
	 * @return 確認結果(true：操作権を持つ、false：操作権を持たない)
	 */
	protected boolean isApprover(WorkflowDtoInterface dto, String personalId) {
		// 操作権を持つ段階を取得
		int approverStage = getApproverStage(dto, personalId);
		// ワークフロー段階確認
		if (dto.getWorkflowStage() == approverStage) {
			return true;
		}
		return false;
	}
	
	/**
	 * 対象ワークフローにおいて、対象個人IDが操作権を持つ段階を取得する。<br>
	 * 操作権を持たない場合は0を返す。<br>
	 * @param dto        対象ワークフロー情報
	 * @param personalId 対象個人ID
	 * @return 操作権を持つ段階
	 */
	protected int getApproverStage(WorkflowDtoInterface dto, String personalId) {
		// 承認者個人ID配列取得
		String[] approverArray = split(dto.getApproverId(), SEPARATOR_DATA);
		// 対象個人ID確認
		for (int i = 0; i < approverArray.length; i++) {
			if (approverArray[i].equals(personalId)) {
				return ++i;
			}
		}
		// TODO ルート確認(日付が必要になる)
		return 0;
	}
	
	/**
	 * 対象日におけるユニットに設定されている承認者を取得する。<br>
	 * 但し、代理承認者は含まれない。<br>
	 * @param unitCode   ユニットコード
	 * @param targetDate 対象日
	 * @return ユニット承認者リスト
	 * @throws MospException インスタンスの取得、SQLの作成及び実行に失敗した場合
	 */
	protected List<HumanDtoInterface> getUnitApproverList(String unitCode, Date targetDate) throws MospException {
		// ユニット承認者リスト準備
		List<HumanDtoInterface> approverList = new ArrayList<HumanDtoInterface>();
		// ユニット情報取得
		ApprovalUnitDtoInterface unitDto = unitReference.getApprovalUnitInfo(unitCode, targetDate);
		// ユニット区分が個人IDの場合
		if (PlatformConst.UNIT_TYPE_PERSON.equals(unitDto.getUnitType())) {
			// 個人ID配列取得
			String[] approverIdArray = split(unitDto.getApproverPersonalId(), SEPARATOR_DATA);
			// 各個人IDから人事情報を取得してユニット承認者リストに設定
			for (String approverId : approverIdArray) {
				// 承認者人事情報取得及び確認
				HumanDtoInterface approverDto = humanReference.getHumanInfo(approverId, targetDate);
				if (approverDto == null) {
					continue;
				}
				// ユニット承認者リストに追加
				approverList.add(approverDto);
			}
		}
		// ユニット区分が所属の場合
		if (PlatformConst.UNIT_TYPE_SECTION.equals(unitDto.getUnitType())) {
			// 検索条件設定(対象日)
			humanSearch.setTargetDate(targetDate);
			// 検索条件設定(所属コード)
			humanSearch.setSectionCode(unitDto.getApproverSectionCode());
			// 検索条件設定(職位コード)
			humanSearch.setPositionCode(unitDto.getApproverPositionCode());
			// 検索条件設定(兼務要否)
			humanSearch.setNeedConcurrent(true);
			// 検索条件設定(休退職区分)
			humanSearch.setStateType(PlatformConst.EMPLOYEE_STATE_PRESENCE);
			// 承認者検索
			approverList = humanSearch.search();
		}
		// 承認者リスト確認
		if (approverList.isEmpty()) {
			// エラーメッセージ設定
			addUnitNotHaveApproverMessage(unitDto.getUnitCode(), targetDate);
		}
		return approverList;
	}
	
	/**
	 * 承認者リスト(代理含む)を作成する。<br>
	 * 承認者に代理登録がされている場合、代理承認者もリストに追加する。<br>
	 * 代理承認者は、リスト上、代理元承認者の前に加えられる。<br>
	 * 取得されるリストには、{@link #getApproverOption(HumanDtoInterface, boolean)}
	 * で取得した配列が含まれる。<br>
	 * @param list         承認者リスト
	 * @param personalId   申請者個人ID
	 * @param targetDate   対象年月日
	 * @param workflowType フロー区分
	 * @return 承認者リスト(代理含む)
	 * @throws MospException インスタンスの取得、SQLの作成及び実行に失敗した場合
	 */
	protected List<String[]> getApproverList(List<HumanDtoInterface> list, String personalId, Date targetDate,
			int workflowType) throws MospException {
		// 承認者リスト準備
		List<String[]> approverList = new ArrayList<String[]>();
		// 承認者リストから申請用承認者情報を作成
		for (HumanDtoInterface approver : list) {
			// 代理承認設定確認
			HumanDtoInterface subApprover = findSubApprover(approver.getPersonalId(), workflowType, targetDate);
			if (subApprover != null) {
				// 申請用承認者情報配列作成用リストに追加
				approverList.add(getApproverOption(subApprover, true));
			}
			// 申請用承認者情報配列作成用リストに追加
			approverList.add(getApproverOption(approver, false));
		}
		return approverList;
	}
	
	/**
	 * 承認者リスト(自己承認)を作成する。<br>
	 * 取得されるリストには、以下内容の配列のみが含まれる。<br>
	 * <ul><li>
	 * 1列目：{@link PlatformConst#APPROVAL_ROUTE_SELF}
	 * </li><li>
	 * 2列目：自己承認
	 * </li></ul>
	 * @return 承認者リスト(自己承認)
	 */
	protected List<String[]> getSelfApproverList() {
		// 承認者リスト準備
		List<String[]> approverList = new ArrayList<String[]>();
		// 自己承認設定
		approverList.add(new String[]{ PlatformConst.APPROVAL_ROUTE_SELF, mospParams.getName("SelfApproval") });
		// 申請用承認者情報作成
		return approverList;
	}
	
	/**
	 * 申請用承認者情報を作成する。<br>
	 * 取得される配列の内容は以下の通り。<br>
	 * <ul><li>
	 * 1列目：個人ID
	 * </li><li>
	 * 2列目：社員コード+社員名
	 * </li></ul>
	 * @param dto           承認者社員情報
	 * @param isSubApprover 代理人フラグ(true：代理、false：代理でない)
	 * @return 申請用承認者情報
	 */
	protected String[] getApproverOption(HumanDtoInterface dto, boolean isSubApprover) {
		// 社員名準備
		StringBuffer sb = new StringBuffer();
		// 代理確認
		if (isSubApprover) {
			sb.append(mospParams.getName("FrontParentheses"));
			sb.append(mospParams.getName("Substitution"));
			sb.append(mospParams.getName("BackParentheses"));
		}
		sb.append(MospUtility.getHumansName(dto.getFirstName(), dto.getLastName()));
		// 申請用承認者情報作成
		return new String[]{ dto.getPersonalId(),
			getCodedName(dto.getEmployeeCode(), sb.toString(), dto.getEmployeeCode().length()) };
	}
	
	/**
	 * ユニットに承認者が存在しない場合のエラーメッセージを追加する。
	 * @param unitCode   ユニットコード
	 * @param targetDate 対象日
	 */
	protected void addUnitNotHaveApproverMessage(String unitCode, Date targetDate) {
		String[] aryMeassage = { unitCode, getStringDate(targetDate) };
		mospParams.addErrorMessage(PlatformMessageConst.MSG_UNIT_NOT_HAVE_APPROVER, aryMeassage);
	}
	
	/**
	 * 下書名称を取得する。<br>
	 * @return 下書名称
	 */
	protected String getNameDraft() {
		return mospParams.getName("WorkPaper");
	}
	
	/**
	 * 申請名称を取得する。<br>
	 * @return 申請名称
	 */
	protected String getNameApply() {
		return mospParams.getName("Application");
	}
	
	/**
	 * 承認名称を取得する。<br>
	 * @return 承認名称
	 */
	protected String getNameApprove() {
		return mospParams.getName("Approval");
	}
	
	/**
	 * 差戻名称を取得する。<br>
	 * @return 差戻名称
	 */
	protected String getNameRemand() {
		return mospParams.getName("SendingBack");
	}
	
	/**
	 * 取下名称を取得する。<br>
	 * @return 取下名称
	 */
	protected String getNameWithdraw() {
		return mospParams.getName("TakeDown");
	}
	
	/**
	 * 承認解除名称を取得する。<br>
	 * @return 承認解除名称
	 */
	protected String getNameRelease() {
		return mospParams.getName("ApprovalRelease");
	}
	
	/**
	 * 未承認名称を取得する。<br>
	 * @return 未承認名称
	 */
	protected String getNameNotApproved() {
		return mospParams.getName("Ram") + mospParams.getName("Approval");
	}
	
	/**
	 * n次済名称を取得する。<br>
	 * @param stage 段階
	 * @return n次済名称
	 */
	protected String getNameStageApprove(int stage) {
		return stage + mospParams.getName("Following") + mospParams.getName("Finish");
	}
	
	/**
	 * n次戻名称を取得する。<br>
	 * @param stage 段階
	 * @return n次戻名称
	 */
	protected String getNameStageRemand(int stage) {
		return stage + mospParams.getName("Following") + mospParams.getName("Back");
	}
	
	/**
	 * 承認済名称を取得する。<br>
	 * @return 承認済名称
	 */
	protected String getNameFinish() {
		return mospParams.getName("Approval") + mospParams.getName("Finish");
	}
	
}
