package nc.bs.bd.psn.psndoc.validator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import nc.bs.framework.common.NCLocator;
import nc.bs.logging.Logger;
import nc.bs.uif2.validation.ValidationFailure;
import nc.bs.uif2.validation.Validator;
import nc.itf.uap.IUAPQueryBS;
import nc.vo.bd.psn.PsnClVO;
import nc.vo.bd.psn.PsndocVO;
import nc.vo.bd.psn.PsnjobVO;
import nc.vo.bd.psn.util.GetBusiDateUtil;
import nc.vo.jcom.lang.StringUtil;
import nc.vo.org.DeptVO;
import nc.vo.pub.BusinessException;
import nc.vo.pub.VOStatus;
import nc.vo.pub.lang.UFLiteralDate;

/**
 * 人员档案新增时，工作信息子表校验
 * 
 * @author jiangjuna
 * 
 */
public class PsnjobValidator implements Validator {

	private static final long serialVersionUID = -2286186646912330964L;
	private PsndocVO oldVO = null;
	private static IUAPQueryBS querySerivce=null;

	private UFLiteralDate nowDate=getNowDate();
	
	/**
	 * 
	 * @param oldVO
	 */
	public PsnjobValidator(PsndocVO oldVO) {

		this.oldVO = oldVO;
	}

	public ValidationFailure validate(Object obj) {

		PsndocVO vo = (PsndocVO) obj;
		ValidationFailure f = null;

		// 修改后的工作信息数据
		List<PsnjobVO> job_list = new ArrayList<PsnjobVO>();
		List<PsnjobVO> newJob_list = new ArrayList<PsnjobVO>();

		PsnjobVO[] jobs = vo.getPsnjobs();

		if (getOldVO() == null) {
			// 新增时，全部数据为新增数据
			if (jobs != null && jobs.length > 0) {
				for(PsnjobVO job:jobs){
					job.setStatus(VOStatus.NEW);
				}
				job_list.addAll(Arrays.asList(jobs));
			}
		} else {
			// 若未修改工作信息数据，不进行校验
			if (jobs == null || jobs.length == 0) {
				return null;
			} else {
				// 根据原有数据获得完整的子表数据
				PsnjobVO[] oldjobs = getOldVO().getPsnjobs();
				Map<String, PsnjobVO> map = new HashMap<String, PsnjobVO>();
				// 如原有的字表数据为空
				if (oldjobs != null && oldjobs.length > 0) {
					for (PsnjobVO psnjobVO : oldjobs) {
						map.put(psnjobVO.getPrimaryKey(), psnjobVO);
					}
				}
				for (PsnjobVO psnjobVO : jobs) {
					// 根据数据的状态删除或替换原有数据
					int state = psnjobVO.getStatus();
					switch (state) {
					case VOStatus.DELETED:
						map.remove(psnjobVO.getPrimaryKey());
						break;
					case VOStatus.UPDATED:
						if(map.containsKey(psnjobVO.getPrimaryKey())){
							map.put(psnjobVO.getPrimaryKey(), psnjobVO);
						}else{
							psnjobVO.setStatus(VOStatus.NEW);
							job_list.add(psnjobVO);
							newJob_list.add(psnjobVO);
						}
						break;
					case VOStatus.NEW: {
						job_list.add(psnjobVO);
						newJob_list.add(psnjobVO);
						break;
					}
					default:
						break;
					}
				}
				job_list.addAll(map.values());
			}
		}

		// 人员档案的所属业务单元（非空性由非空校验保证）
		String pk_org = vo.getPk_org();
		String msg = checkPsnjobs(pk_org, job_list.toArray(new PsnjobVO[0]),newJob_list.toArray(new PsnjobVO[0]));
		if(job_list!=null && job_list.size()>0){
			for(PsnjobVO jobvo:job_list.toArray(new PsnjobVO[0])){
				if(jobvo.getEnddutydate()!=null && jobvo.getEnddutydate().equals("9999-12-31")){
					jobvo.setEnddutydate(null);
				}
			}
		}
		
		if (msg != null && msg.trim().length() > 0) {
			f = new ValidationFailure();
			f.setMessage(msg.toString());
		}

		return f;
	}


	/**
	 * 人员档案工作信息校验，（工作信息允许为空）
	 * 
	 * @param pk_org
	 *            所属业务单元
	 * @param jobs
	 *            待校验的人员档案的全部工作信息
	 * @return
	 */
	private String checkPsnjobs(String pk_org, PsnjobVO[] jobs,PsnjobVO[] psnclCheckVos) {
		List<String> msgList = new ArrayList<String>();
		// 工作信息不为空时，进行以下校验
		if (jobs != null && jobs.length > 0) {
			//先做排序 
			List<PsnjobVO> jobsList = Arrays.asList(jobs);
			Collections.sort(jobsList, Comparator.comparing(PsnjobVO::getIndutydate));
			jobs=jobsList.toArray(new PsnjobVO[jobsList.size()]);
			// 是否所在部门不重复
			boolean isDeptUnique = true;
			Set<String> deptSet = new HashSet<String>();
			
			//首先校验任职开始日期和任职结束日期是否正确
			CheckDutyDateIsCorrect(msgList,jobs);
			// 是否主职唯一
			boolean isMainjobUnique = true;
			boolean isMainjobExist = false;  
			//必须有一条任职记录勾选主职。
			boolean mustHasOneMainJob=false;

			boolean isOrg=false;
			
			int mainJobCount=0;//有效主职的条数

			for (PsnjobVO psnjobVO : jobs) {
//				String pk_dept = psnjobVO.getPk_dept();

//				// 所在部门已存在时
//				if (isDeptUnique && !deptSet.add(pk_dept)) {
//					isDeptUnique = false;
//				}
				
				if(psnjobVO.getIsmainjob().booleanValue()){
					mustHasOneMainJob=true;
				}

				if (isMainjobUnique) {
					// 是否主职
					boolean isMainJob=false;
					if(psnjobVO.getIsmainjob().booleanValue()&& (psnjobVO.getIndutydate().compareTo(nowDate)<=0 || psnjobVO.getIndutydate().isSameDate(nowDate))
							&&(psnjobVO.getEnddutydate()==null || (nowDate.compareTo(psnjobVO.getEnddutydate())<=0) || nowDate.isSameDate(psnjobVO.getEnddutydate()))){
						isMainJob=true;
						isMainjobExist=true;
						mainJobCount++;
					}
				
					// 存在两条可以为主职的数据，则主职不唯一（这里指有效主职）
					if (mainJobCount>1) {
						isMainjobUnique = false;
					}
					if(isMainJob)
					{
						String job_org=psnjobVO.getPk_org();
						if(pk_org.equalsIgnoreCase(job_org))
							isOrg=true;
					}
					
				}
			}

//			// 工作信息的所属部门重复时
//			if (!isDeptUnique) {
//				msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","010140psn0055"));//同一业务单元下的同一部门下只能有一条任职信息！
//			}
			
			if(!mustHasOneMainJob){
				
			}

			// 是否主职不唯一时
			if (!isMainjobUnique) {
				if(!msgList.contains(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0032"))){
				msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0032"));//同一人员在相同时间内只能有一条主任职！
				}
			}	

//			// 是否主职不存在时
//			if (!isMainjobExist) {
//				msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","010140psn0057"));//人员工作信息必须有一条为主职！
//			}
			//主职的业务单元
			if(isMainjobExist&&(!isOrg))
			{
				msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","010140psn0058"));//主职任职业务单元必须为人员所在的业务单元！
			}

		} else {
			msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","010140psn0059"));//人员必须存在一条工作信息！
		}
		if(psnclCheckVos!=null&&psnclCheckVos.length>0)
		{
			for(int i=0;i<psnclCheckVos.length;i++)
			{
				String pk_psncl=psnclCheckVos[i].getPk_psncl();
				String pk_dept=psnclCheckVos[i].getPk_dept();
				try
				{
				PsnClVO vo=(PsnClVO)getQueryBS().retrieveByPK(PsnClVO.class, pk_psncl,new String[]{"enablestate"});
				DeptVO  deptVo=(DeptVO)getQueryBS().retrieveByPK(DeptVO.class, pk_dept, new String[]{"enablestate"});
				int enablestate=vo.getEnablestate();
				if(enablestate==3)
				{
					msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","010140psn0060"));//新增的任职信息的人员类别不能是停用的类别！
					break;
				}
				enablestate=deptVo.getEnablestate();
				if(enablestate==3)
				{
					msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","010140psn0061"));//新增的任职信息的所属部门不能是停用的部门！
				}
				}
				catch(BusinessException e)
				{
					Logger.error(e);
				}
				
			}
		}

		if (msgList.size() > 0) {
			return StringUtil.toString(msgList.toArray(), "\n");
		}
		return null;
	}

	/**
	 * 校验任职开始日期和任职结束日期是否正确
	 * 规则1：任职开始日期必须早于任职结束日期
	 * 规则2：如果主职有多条记录（比如1,2,3）勾选，那么，这些1,2,3条记录的任职开始日期和任职结束日期不能出现重叠。
	 * 主要目的就是为了确保在一个时间段内，只能有一个主职。
	 */
	private void CheckDutyDateIsCorrect(List<String> msgList,PsnjobVO[] jobs){
		List<PsnjobVO> mainJobList=new ArrayList<PsnjobVO>();//勾选了是否主职的记录
		List<PsnjobVO> partTimeJobList=new ArrayList<PsnjobVO>();//兼职，即未勾选是否主职
		Map<UFLiteralDate,UFLiteralDate> mainJobMap=new HashMap<UFLiteralDate,UFLiteralDate>();
		Map<UFLiteralDate,UFLiteralDate> indutyAndEnddutydateMainJobMap=new HashMap<UFLiteralDate,UFLiteralDate>();
		for(PsnjobVO job:jobs){
			if(job.getIndutydate()!=null && job.getEnddutydate()!=null){
				if(job.getIndutydate().compareTo(job.getEnddutydate())>0){
					msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0031")
							/* 任职结束日期必须晚于任职开始日期！*/);				
				}
			}
			if(job.getEnddutydate()==null){
				job.setEnddutydate(new UFLiteralDate("9999-12-31"));
			}
			if(job.getIsmainjob().booleanValue()){	
				mainJobList.add(job);
				indutyAndEnddutydateMainJobMap.put(job.getIndutydate(),job.getEnddutydate());
			}else{
				partTimeJobList.add(job);
			}
		}
		int mainJobCount=0;//在当前业务日期下，有效的主职的条数
		if(mainJobList!=null && mainJobList.size()>0){			
			for(PsnjobVO jobvo:mainJobList){	
				if(jobvo.getIndutydate().compareTo(nowDate)<=0
					&&nowDate.compareTo(jobvo.getEnddutydate())<=0){
						mainJobCount++;
					}	
			}
		}

		if(mainJobList.size()<1){
			msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0038")
					/*人员工作信息必须有一条勾选是否主职！*/);
		}
		if(mainJobCount>1){
			if(!msgList.contains(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0032"))){
				msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0032")
						/* 同一人员在相同时间内只能有一条主任职！*/);
			}
					
		}else if(mainJobCount==1 && mainJobList.size()>1){
			/**
			 * 校验同一时间段内，只能有一条有效的主职，分两步：
			 * 1，如果任职开始日期和任职结束日期有重复的，那么，不允许，在同一个时间段内只能有一条有效主职！
			 * 2，任职开始日期和任职结束日期都不相同，判断任职开始日期和结束日期是否有重叠，
			 * 我们要求时间不能有重叠，同一个时间段内只能有一条有效主职！
			 */
			boolean dateIsRepeat=false;
			List<UFLiteralDate> startAndEndDateList=new ArrayList<UFLiteralDate>();
			for(PsnjobVO vo:mainJobList){
				if(vo!=null){
					UFLiteralDate startDate=vo.getIndutydate();
					UFLiteralDate endDate=vo.getEnddutydate();
					if(startAndEndDateList.contains(startDate)){//||startAndEndDateList.contains(endDate)
						dateIsRepeat=true;
					}
					if(!startAndEndDateList.contains(startDate)){
						startAndEndDateList.add(startDate);
					}
					if(!startAndEndDateList.contains(endDate)){
						startAndEndDateList.add(endDate);
					}	
				}		
			}
			if(dateIsRepeat){//若key有重复的，表示时间段有重叠的情况
				if(!msgList.contains(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0032"))){
					msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0032")
							/* 同一人员在相同时间内只能有一条主任职！*/);
				}
			}else{//若key不重复，全部加入map中
				for(PsnjobVO vo:mainJobList){
					if(vo!=null){
						mainJobMap.put(vo.getIndutydate(), vo.getEnddutydate());
					}		
				}
				for(UFLiteralDate date:startAndEndDateList){
					for(UFLiteralDate key:mainJobMap.keySet()){
						if(key.compareTo(date)<0 && date.compareTo(mainJobMap.get(key))<0){
							if(!msgList.contains(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0032"))){
								msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0032")
										/* 同一人员在相同时间内只能有一条主任职！*/);
							}
							return;
							}
						}
					}
				}
		}
		//校验主职不存在的时间段内，不允许有兼职存在
		checkPartTimeJobIsCorrect(msgList,partTimeJobList,indutyAndEnddutydateMainJobMap);
		
		
	}
	
	/**
	 * 校验主职不存在的时间段内，不允许有兼职存在。
	 */
	private void checkPartTimeJobIsCorrect(List<String> msgList,List<PsnjobVO> partTimeJobList,Map<UFLiteralDate,UFLiteralDate> indutyAndEnddutydateMainJobMap){
		if(partTimeJobList==null || partTimeJobList.size()==0 ||indutyAndEnddutydateMainJobMap==null ||indutyAndEnddutydateMainJobMap.size()==0){
			return;
		}
		boolean startFlag=false;
		boolean endFlag=false;
		for(PsnjobVO jobvo:partTimeJobList){
			UFLiteralDate ptStartDate=jobvo.getIndutydate();//兼职的开始时间
			UFLiteralDate ptEndDate=jobvo.getEnddutydate();//兼职的结束时间
			UFLiteralDate mainEndOneDate=null;//主职的第一个结束时间
			UFLiteralDate mainEndTwoDate=null;//主职的第二个结束开始时间
			for(UFLiteralDate key:indutyAndEnddutydateMainJobMap.keySet()){
				if((key.compareTo(ptStartDate)<=0 || key.isSameDate(ptStartDate))&& ptStartDate.compareTo(indutyAndEnddutydateMainJobMap.get(key))<=0){
					startFlag=true;
					mainEndOneDate=indutyAndEnddutydateMainJobMap.get(key);
				}
				if(key.compareTo(ptEndDate)<=0 && ptEndDate.compareTo(indutyAndEnddutydateMainJobMap.get(key))<=0){
					endFlag=true;
					mainEndTwoDate=indutyAndEnddutydateMainJobMap.get(key);
				}
			}
			if(startFlag && endFlag && mainEndOneDate!=null && mainEndTwoDate!=null){
				for(UFLiteralDate key:indutyAndEnddutydateMainJobMap.keySet()){
					if(mainEndOneDate!=null && indutyAndEnddutydateMainJobMap.get(mainEndOneDate.getDateAfter(1))!=null){
						mainEndOneDate=indutyAndEnddutydateMainJobMap.get(mainEndOneDate.getDateAfter(1));
					}
				}
				if(mainEndOneDate!=null && mainEndTwoDate!=null &&
						mainEndOneDate.compareTo(mainEndTwoDate)<0){
					msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0039")
							/*该人员在其他兼职单位还有任职，请处理*/);
					return;
				}
			}else{
				msgList.add(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("10140psn","110140psn0039")
						/*该人员在其他兼职单位还有任职，请处理*/);
				return;
			}		
		}
	}
	
	/**
	 * 返回原有人员数据，为null时默认为新增操作
	 * 
	 * @return
	 */
	protected PsndocVO getOldVO() {
		return oldVO;
	}
	private IUAPQueryBS getQueryBS()
	{
		if(querySerivce==null)
			querySerivce=NCLocator.getInstance().lookup(IUAPQueryBS.class);
		return querySerivce;
	}
	
	private UFLiteralDate getNowDate(){
		if(nowDate==null){
			nowDate=new GetBusiDateUtil().getNowDate();
		}
		return nowDate;
	}

}
