package jp.mosp.workflow.action;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

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.part.DatePart;
import jp.mosp.common.part.KintaiApprovalPart;
import jp.mosp.common.part.NumberPart;
import jp.mosp.common.part.PartManager;
import jp.mosp.common.part.StringPart;

import jp.mosp.human.dto.MKihonDto;

import jp.mosp.kintai.dto.MSyukkinboDto;

import jp.mosp.workflow.dto.CtOvertimeRequestDto;
import jp.mosp.workflow.dto.KintaiAppicationDto;
import jp.mosp.workflow.vo.ManagerApprovalListVo;

public class ManagerApprovalListAction extends MosPWorkflowAction {

	// コマンド
	private static final String CMD_LIST_SHOW 		= "K2130";
	private static final String CMD_LIST_SEARCH 		= "K2131";
	private static final String CMD_LIST_RE_SEARCH 	= "K2132";
	private static final String CMD_LIST_SORT 		= "K2133";
	private static final String CMD_LIST_APPROVAL		= "K2134";

	// フィールド
	/**
	 * 表示用リスト
	 */
	List<KintaiAppicationDto> listApplication;

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

	public void action() throws Exception {
		// VOの初期化
		ManagerApprovalListVo vo = (ManagerApprovalListVo) prepareVo();
		// プルダウンの設定
		setPulldownList(vo);
		// ユーザ情報の設定
		getInfo(user.getUserId());
		// コマンド毎の処理
		if (cmd.equals(CMD_LIST_SHOW)) {
			Date todayDate = DatePart.getSystemDate();
			vo.setPltYear(String.valueOf(MospUtility.getYear(todayDate)));
			vo.setPltMonth(String.valueOf(MospUtility.getMonth(todayDate)));
			vo.setPltDay(String.valueOf(MospUtility.getDay(todayDate)));
			vo.setPltSection(mKihon.getSCode());
		} else if (cmd.equals(CMD_LIST_SEARCH)) {
			vo.setParams(request);
			// 検索条件による一覧取得
			searchApplicationList(vo);
			vo.setFormerKey(vo.KEY_K_CODE);
			vo.setIsAscending(true);
			vo.initListInfo();
			vo.setSearchmode(ManagerApprovalListVo.SEARCH_ON);
		} else if (cmd.equals(CMD_LIST_RE_SEARCH)) {
			// 再検索
			if (vo.getSearchmode() == ManagerApprovalListVo.SEARCH_ON) {
				session.removeAttribute(MospConst.ATT_DTO);
				searchApplicationList(vo);
				vo.setPageButton();
				sortList(vo);
			}
		} else if (cmd.equals(CMD_LIST_SORT)) {
			// ソート
			sortList(key1, vo);
		} else if (cmd.equals(CMD_LIST_APPROVAL)) {
			vo.setParams(request);
			// 一括承認
			runApprovalProcess(vo);
			// 再検索
			searchApplicationList(vo);
			vo.setPageButton();
			sortList(vo);
		} else {
			throw new MospException(MospConst.EX_CMD_INVALID);
		}
	}

	protected ManagerApprovalListVo getSpecificVo() {
		return new ManagerApprovalListVo();
	}

	/**
	 * プルダウンの設定
	 * @param vo		対象VO
	 * @throws Exception 
	 */
	private void setPulldownList(ManagerApprovalListVo vo) throws Exception {
		vo.aryPltSection 		= StringPart.addArrayFirstRowSpace(getSectionArrayAll());
		vo.aryPltApplication 	= StringPart.addArrayFirstRowSpace(getApplicationArray());
		vo.aryPltStatus 		= StringPart.addArrayFirstRowSpace(
				PartManager.kintaiapproval(partInfo()).getApprovalReasonArray()
		);
		vo.aryPltYear 			= StringPart.getYearArray(MospUtility.getYear(DatePart.getSystemDate()));
		vo.aryPltMonth 			= StringPart.getMonthArray();
		vo.aryPltDay 			= StringPart.getDayArray();
	}

	/**
	 * 検索条件による一覧設定
	 * @param vo	対象VO
	 * @throws Exception 
	 */
	private void searchApplicationList(ManagerApprovalListVo vo) throws Exception {
		// リストの初期化
		listApplication = new ArrayList<KintaiAppicationDto>();
		// 開始年月日
		Date startDate;
		// 終了年月日
		Date endDate;
		if (vo.getPltDay().length() != 0) {
			startDate = DatePart.getDate(vo.getPltYear(), vo.getPltMonth(), vo.getPltDay());
			endDate = startDate;
		} else {
			startDate = DatePart.getFirstDateOfMonth(vo.getPltYear(), vo.getPltMonth());
			endDate = DatePart.getLastDateOfMonth(vo.getPltYear(), vo.getPltMonth());
		}
		// 承認対象社員一覧リスト
		List<MKihonDto> mKihonList = getApprovalEmployeeList(startDate);
		for (Iterator iter = mKihonList.iterator(); iter.hasNext();) {
			MKihonDto dto = (MKihonDto) iter.next();
			if (vo.getPltSection().length() != 0
					&& !vo.getPltSection().equals(dto.getSCode())
			) {
				continue;
			}
			if (vo.getTxtKCode().length() != 0
					&& !dto.getKCode().startsWith(vo.getTxtKCode())	
			) {
				continue;
			}
			if (vo.getTxtKName().length() == 0
					&& !dto.getSimei().matches(".*" + vo.getTxtKName() + ".*")
			) {
				continue;
			}
			/*			
			if (vo.getPltApplication().length() == 0
					|| vo.getPltApplication().equals(getApplicationArray()[0][0])
			) {
				// 日次勤怠情報追加
				addSyukkinboInfoToList(dto, startDate, endDate, vo.getPltStatus());
			}
			 */			
			if (vo.getPltApplication().length() == 0
					|| 	vo.getPltApplication().equals(getApplicationArray()[0][0])
			) {
				// 残業申請情報追加
				addOverTimeRequestToList(dto, startDate, endDate, vo.getPltStatus());
			}
			/*			
			if (vo.getPltApplication().length() == 0
					|| vo.getPltApplication().equals(getApplicationArray()[0][0])
			) {
				// 休暇申請情報追加
			}
			 */
		}
		// 社員コードでソート。
		util.sortList(listApplication, new CompKCode());
		// VOにセット
		vo.setFields(listApplication);
		// 対象が無かった場合のメッセージ設定
		if (vo.getEscAryApplication().length == 0) {
			vo.addErrMessage(MospUtility.getMessage(msg, MospConst.MSG_NO_DATA, ""));
		}
	}

	/**
	 * 日次勤怠情報追加
	 * @param mKihonDto		対象社員情報DTO
	 * @param startDate		開始年月日
	 * @param endDate		終了年月日
	 * @param snriyuu		対象承認状況
	 * @throws Exception
	 */
	protected void addSyukkinboInfoToList(
			MKihonDto mKihonDto,
			Date startDate,
			Date endDate,
			String snriyuu
	) throws Exception {
		// 対象期間日次勤怠一覧取得
		List<MSyukkinboDto> listSyukkinbo = syukkinboDao().findForApprovalList(
				mKihonDto.getKCode(),
				DatePart.convDateFormatted(startDate),
				DatePart.convDateFormatted(endDate),
				snriyuu
		);
		for (Iterator iterator = listSyukkinbo.iterator(); iterator.hasNext();) {
			MSyukkinboDto dto = (MSyukkinboDto) iterator.next();
			KintaiAppicationDto appicationDto = new KintaiAppicationDto();
			// コマンド
			//appicationDto.setCmd("K2126");
			// キー
			appicationDto.setKey(dto.getHizuke());
			// 社員コード
			appicationDto.setKCode(dto.getKCode());
			// 社員氏名
			appicationDto.setSimei(mKihonDto.getSimei());
			// 所属名
			appicationDto.setSName(getSectionName(mKihonDto.getSCode()));
			// 日付
			appicationDto.setDate(DatePart.convStringDateToDate(dto.getHizuke()));
			// 申請種類
			appicationDto.setApprication(CommonConst.NAM_DAILY_APPROVAL);
			// 承認状況
			appicationDto.setStatus(PartManager.kintaiapproval(partInfo()).getApprovalName(dto));
			// チェックボックス
			if (KintaiApprovalPart.isRequest(dto)
					|| KintaiApprovalPart.is1stApproved(dto)
			) {
				StringBuffer sb = new StringBuffer();
				// 申請承認種類
				sb.append(CommonConst.CODE_DAILY_APPROVAL);
				sb.append(CommonConst.STR_UNDER_SEPARATOR);
				appicationDto.setCkbValue(sb.toString());
			}
			listApplication.add(appicationDto);
		}
	}

	/**
	 * 残業申請情報追加
	 * @param mKihonDto		対象社員情報DTO
	 * @param startDate		開始年月日
	 * @param endDate		終了年月日
	 * @param snriyuu		対象承認状況
	 * @throws Exception
	 */
	private void addOverTimeRequestToList(
			MKihonDto mKihonDto,
			Date startDate,
			Date endDate,
			String snriyuu
	) throws Exception {
		// ワークフロー承認状況コード
		String[] targetStatus = KintaiApprovalPart.toWorkflowStatus(snriyuu);
		List<CtOvertimeRequestDto> listOverTime = overRequestDao().findForCondition(
				mKihonDto.getKCode(),
				DatePart.convDateFormattedByHyphen(startDate),
				DatePart.convDateFormattedByHyphen(endDate),
				NumberPart.getIntParam(targetStatus[0]),
				targetStatus[1]
		);
		for (Iterator iter = listOverTime.iterator(); iter.hasNext();) {
			CtOvertimeRequestDto dto = (CtOvertimeRequestDto) iter.next();
			// 下書き以外
			if (!isStatusDraft(dto.getWorkflow())) {
				KintaiAppicationDto appicationDto = new KintaiAppicationDto();
				// コマンド
				appicationDto.setCmd(OverTimeApprovalCardAction.CMD_CARD_SELECT);
				// キー
				appicationDto.setKey(String.valueOf(dto.getVoucher()));
				// 社員コード
				appicationDto.setKCode(dto.getKCode());
				// 社員氏名
				appicationDto.setSimei(mKihonDto.getSimei());
				// 所属名
				appicationDto.setSName(getSectionName(mKihonDto.getSCode()));
				// 日付
				appicationDto.setDate(dto.getWorkDate());
				// 申請種類
				appicationDto.setApprication(CommonConst.NAM_OVER_TIME_REQUEST);
				String statusCode = toKintaiApprovalStatus(dto.getWorkflow());
				// 承認状況
				appicationDto.setStatus(getApprovalName(statusCode));
				// チェックボックス
				if (KintaiApprovalPart.isRequest(statusCode)
						|| KintaiApprovalPart.is1stApproved(statusCode)	
				) {
					StringBuffer sb = new StringBuffer();
					// 申請承認種類
					sb.append(CommonConst.CODE_OVER_TIME_REQUEST);
					sb.append(CommonConst.STR_UNDER_SEPARATOR);
					// 申請伝票番号
					sb.append(dto.getVoucher());
					appicationDto.setCkbValue(sb.toString());
				}
				listApplication.add(appicationDto);
			}
		}
	}

	/**
	 * 一括承認処理
	 * @param vo			対象VO
	 * @throws Exception
	 */
	private void runApprovalProcess(ManagerApprovalListVo vo) throws Exception {
		String[] arySelectValue = vo.getCkbApproval();
		// コミットフラグ
		Set<Boolean> commitSet = new HashSet<Boolean>();
		for (String selectValue : arySelectValue) {
			// 日々勤怠承認
			// 残業申請承認
			if (selectValue.indexOf(CommonConst.CODE_OVER_TIME_REQUEST) == 0) {
				// 残業申請承認処理 
				commitSet.add(runOverTimeRequestApproved(
						getOverTimeRequest(NumberPart.getIntParam(
								selectValue.split(CommonConst.STR_UNDER_SEPARATOR)[1])
						),
						vo)
				);
			}
			// 休暇申請承認
		}
		// エラーが無ければコミットする。
		if (!commitSet.contains(false)) {
			// コミット
			commit();
			// メッセージ
			StringBuffer sb = new StringBuffer();
			sb.append(commitSet.size());
			sb.append(CommonConst.NAM_COMMON_COUNT);
			sb.append(CommonConst.NAM_APPROVED);
			vo.setMessage(MospUtility.getMessage(msg, CommonConst.MSG_DONE, sb.toString()));
		}
	}

	/**
	 * ソート(VO内のキー情報でソート)
	 * @param vo ソート対象Listを含むVO
	 * @throws MospException
	 */
	private void sortList(ManagerApprovalListVo vo) throws MospException {
		vo.sortList(getComparator(vo.getFormerKey(), vo));
		vo.setFields(vo.getList());
	}

	/**
	 * ソート
	 * @param key ソートキー
	 * @param vo ソート対象Listを含むVO
	 * @throws MospException
	 */
	private void sortList(String key, ManagerApprovalListVo vo) throws MospException {
		vo.sortList(key, getComparator(key, vo));
		vo.setFields(vo.getList());
	}

	/**
	 * 比較クラス取得
	 * @param key ソートキー
	 * @param vo ソート対象Listを含むVO
	 * @throws MospException
	 */
	private Comparator<Object> getComparator(String key, ManagerApprovalListVo vo) throws MospException {
		Comparator<Object> comp = null;
		if (key.equals(vo.KEY_K_CODE)) {
			comp = new CompKCode();
		} else if (key.equals(vo.KEY_K_NAME)) {
			comp = new CompKName();
		} else if (key.equals(vo.KEY_SECTION)) {
			comp = new CompSection();
		} else if (key.equals(vo.KEY_DATE)) {
			comp = new CompDate();
		} else if (key.equals(vo.KEY_APPLICATION)) {
			comp = new CompApplication();
		} else if (key.equals(vo.KEY_STATUS)) {
			comp = new CompStatus();
		} else {
			throw new MospException(MospConst.EX_SORTKEY_INVALID);
		}
		return comp;
	}

	/**
	 * 社員コードによる比較クラス
	 */
	protected static class CompKCode implements Comparator<Object>, Serializable {
		private static final long serialVersionUID = -6587672856397520392L;
		public int compare(Object obj1, Object obj2) {
			KintaiAppicationDto dto1 = (KintaiAppicationDto)obj1;
			KintaiAppicationDto dto2 = (KintaiAppicationDto)obj2;
			return dto1.getKCode().compareTo(dto2.getKCode());
		}
	}

	/**
	 * 社員氏名による比較クラス
	 */
	protected static class CompKName implements Comparator<Object>, Serializable {
		private static final long serialVersionUID = 6321920436763711779L;
		public int compare(Object obj1, Object obj2) {
			KintaiAppicationDto dto1 = (KintaiAppicationDto)obj1;
			KintaiAppicationDto dto2 = (KintaiAppicationDto)obj2;
			return dto1.getSimei().compareTo(dto2.getSimei());
		}
	}

	/**
	 * 社員氏名による比較クラス
	 */
	protected static class CompSection implements Comparator<Object>, Serializable {
		private static final long serialVersionUID = -6522555390412324071L;
		public int compare(Object obj1, Object obj2) {
			KintaiAppicationDto dto1 = (KintaiAppicationDto)obj1;
			KintaiAppicationDto dto2 = (KintaiAppicationDto)obj2;
			return dto1.getSName().compareTo(dto2.getSName());
		}
	}

	/**
	 * 日付による比較クラス
	 */
	protected static class CompDate implements Comparator<Object>, Serializable {
		private static final long serialVersionUID = -2059568153842913234L;
		public int compare(Object obj1, Object obj2) {
			KintaiAppicationDto dto1 = (KintaiAppicationDto)obj1;
			KintaiAppicationDto dto2 = (KintaiAppicationDto)obj2;
			return dto1.getDate().compareTo(dto2.getDate());
		}
	}

	/**
	 * 申請種類による比較クラス
	 */
	protected static class CompApplication implements Comparator<Object>, Serializable {
		private static final long serialVersionUID = -2395226905215857602L;
		public int compare(Object obj1, Object obj2) {
			KintaiAppicationDto dto1 = (KintaiAppicationDto)obj1;
			KintaiAppicationDto dto2 = (KintaiAppicationDto)obj2;
			return dto1.getApprication().compareTo(dto2.getApprication());
		}
	}

	/**
	 * 承認状況による比較クラス
	 */
	protected static class CompStatus implements Comparator<Object>, Serializable {
		private static final long serialVersionUID = -8920699379965954199L;
		public int compare(Object obj1, Object obj2) {
			KintaiAppicationDto dto1 = (KintaiAppicationDto)obj1;
			KintaiAppicationDto dto2 = (KintaiAppicationDto)obj2;
			return dto1.getStatus().compareTo(dto2.getStatus());
		}
	}

}
