package com.persagy.calendar.handle;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.persagy.calendar.constant.WorkCalendarConstant;
import com.persagy.calendar.pojo.dto.WorkCalendar;
import com.persagy.calendar.pojo.dto.WorkCalendarDate;
import com.persagy.calendar.pojo.dto.WorkCalendarRule;
import com.persagy.calendar.pojo.vo.CalendarDateResult;
import com.persagy.calendar.pojo.vo.CustomCalendarVO;
import com.persagy.calendar.pojo.vo.WorkCalendarDateCreateVO;
import com.persagy.calendar.pojo.vo.WorkCalendarDateQueryVO;
import com.persagy.calendar.pojo.vo.WorkCalendarDateUpdateVO;
import com.persagy.calendar.pojo.vo.WorkCalendarMoreDateCreateVO;
import com.persagy.calendar.service.IWorkCalendarDateService;
import com.persagy.calendar.service.IWorkCalendarDictService;
import com.persagy.calendar.service.IWorkCalendarRuleService;
import com.persagy.calendar.service.IWorkCalendarService;
import com.persagy.common.enums.ResponseCode;
import com.persagy.common.exception.BusinessException;
import com.persagy.common.utils.DateUtil;
import com.persagy.common.utils.IdGenerator;
import com.persagy.common.utils.StringUtil;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import lombok.extern.slf4j.Slf4j;

/**
 * @version 
 * @description 
 * @company persagy
 * @author zhangqiankun
 * @since 2020年10月3日:	下午1:03:19
 */
@Slf4j
@Component
public class WorkCalendarDateHandler {

	@Autowired
    private IWorkCalendarService workCalendarService;
    
    @Autowired
    private IWorkCalendarRuleService workCalendarRuleService;
    
    @Autowired
    private IWorkCalendarDateService workCalendarDateService;
    
	@Autowired
	private IWorkCalendarDictService workCalendarDictService;
    
	/**
	 * 创建工作历作息时间信息,先删除在创建
	 * 
	 * @param workCalendarDates
	 * @param workDateStart 不能为空
	 * @param workDateEnd 不能为空
	 * @return
	 */
	@Transactional
	public boolean createCalendarDateByDelete(List<WorkCalendarDate> workCalendarDates, String workDateStart, String workDateEnd) {
		// 1.防止重复执行,优先删除从今日开始的非自定义的作息时间信息
		QueryWrapper<WorkCalendarDate> queryWrapper = new WorkCalendarDate.Builder().createQueryWrapper()
				.customFlagEq(WorkCalendarConstant.CUSTOM_CALENDAR_DATE_NO)
				.workDateGe(workDateStart).workDateLe(workDateEnd).builderQueryWrapper();
		this.workCalendarDateService.remove(queryWrapper);
		
		// 2.信息插入
		boolean result = this.workCalendarDateService.batchCreateCalendarDate(workCalendarDates);
		return result;
	}
	
    /**
     * 实时查询作息时间信息,包括自定义的,当日的作息时间,走规则解析
     * 
     * @param queryVO
     * @return
     */
    public List<CalendarDateResult> queryWorkCalendarDateList(WorkCalendarDateQueryVO queryVO) {
    	// 优先进行时间调整解析,所有的时间都必须是 YYYYMMDD 格式
    	String dateStartStr = queryVO.getWorkDateStart();
    	String dateEndStr = queryVO.getWorkDateEnd();
    	
    	// 中间时间
    	String now = DateUtil.format(new Date(), DateUtil.FORMAT_DATE_YYYYMMDD);
    	DateTime dateStart = DateUtil.parse(dateStartStr, DateUtil.FORMAT_DATE_YYYYMMDD);
		DateTime dateEnd = DateUtil.parse(dateEndStr, DateUtil.FORMAT_DATE_YYYYMMDD);
		
		Map<String, DateTime> parseWorkDate = this.parseWorkDate(dateStart, dateEnd, now);
		
		DateTime historyStart = parseWorkDate.get("historyStart");
		DateTime historyEnd = parseWorkDate.get("historyEnd");
		DateTime parseRuleStart = parseWorkDate.get("parseRuleStart");
		DateTime parseRuleEnd = parseWorkDate.get("parseRuleEnd");
		
		// 判断字典类型,TODO 这里该不该判断??后续再做修改
		int dictTypeLevel = this.workCalendarDictService.getDictTypeLevel(null, queryVO.getDictType());
    	
		// 1.取历史作息时间记录
		Map<String, List<WorkCalendarDate>> calendarDateMap = new HashMap<String, List<WorkCalendarDate>>();
		if (historyStart != null && historyEnd != null) {
			queryVO.setWorkDateStart(DateUtil.format(historyStart, DateUtil.FORMAT_DATE_YYYYMMDD));
			queryVO.setWorkDateEnd(DateUtil.format(historyEnd, DateUtil.FORMAT_DATE_YYYYMMDD));
			List<WorkCalendarDate> historyDateList = this.selectWorkCalendarDateList(queryVO, null, dictTypeLevel);
	    	if (CollectionUtil.isNotEmpty(historyDateList)) {
				for (WorkCalendarDate historyDate : historyDateList) {
					if (calendarDateMap.containsKey(historyDate.getWorkDate())) {
						calendarDateMap.get(historyDate.getWorkDate()).add(historyDate);
					} else {
						calendarDateMap.put(historyDate.getWorkDate(), Lists.newArrayList(historyDate));
					}
				}
			}
		}
		
		// 2.取当日往后的自定义作息时间
		List<WorkCalendarDate> customDateList = null;
		if (parseRuleStart != null && parseRuleEnd != null) {
			queryVO.setWorkDateStart(DateUtil.format(parseRuleStart, DateUtil.FORMAT_DATE_YYYYMMDD));
			queryVO.setWorkDateEnd(DateUtil.format(parseRuleEnd, DateUtil.FORMAT_DATE_YYYYMMDD));
			customDateList = this.selectWorkCalendarDateList(queryVO, WorkCalendarConstant.CUSTOM_CALENDAR_DATE_YES, dictTypeLevel);
		}
		
		// 3.获取当日往后的规则信息中的作息时间
		if (parseRuleStart != null && parseRuleEnd != null) {
			List<WorkCalendarRule> ruleList = this.selectWorkCalendarRuleList(queryVO, dictTypeLevel);
			long betweenDay = DateUtil.between(parseRuleStart, parseRuleEnd, DateUnit.DAY) + 1;
			this.paserWorkCalendarRule(calendarDateMap, ruleList, parseRuleStart, betweenDay);
		}
		
		// 获取start~end之间的天数,+1 包括首尾
    	dateStart = DateUtil.parse(dateStartStr, DateUtil.FORMAT_DATE_YYYYMMDD);
		long betweenDay = DateUtil.between(dateStart, dateEnd, DateUnit.DAY) + 1;
		
		// 4.结果加工处理返回
		return this.setResultList(calendarDateMap, customDateList, dateStart, betweenDay);
    }
    
    /**
     * 响应数据,最后处理加工,自定义的将会覆盖掉非自定义的
     * 
     * @param calendarDateMap 包含历史与实时规则中的作息时间集合
     * @param customDateList
     * @param dateStart
     * @param betweenDay
     * @return
     */
    private List<CalendarDateResult> setResultList(Map<String, List<WorkCalendarDate>> calendarDateMap, List<WorkCalendarDate> customDateList, 
    		DateTime dateStart, long betweenDay) {
    	// 结果集
    	List<CalendarDateResult> resultList = new ArrayList<CalendarDateResult>();
    	
    	// 自定义作息时间 当日~end时间内的
    	Map<String, List<WorkCalendarDate>> customDateMap = new HashMap<String, List<WorkCalendarDate>>();
    	if (CollectionUtil.isNotEmpty(customDateList)) {
			for (WorkCalendarDate customDate : customDateList) {
				if (customDateMap.containsKey(customDate.getWorkDate())) {
					customDateMap.get(customDate.getWorkDate()).add(customDate);
				} else {
					customDateMap.put(customDate.getWorkDate(), Lists.newArrayList(customDate));
				}
			}
		}
    	
    	String workDate = null;
		for (int i = 0; i < betweenDay; i++) {
			workDate = dateStart.toString(DateUtil.FORMAT_DATE_YYYYMMDD);
			List<WorkCalendarDate> historyOrRuleDates = calendarDateMap.get(workDate);
			List<WorkCalendarDate> customDates = customDateMap.get(workDate);
			
			CalendarDateResult result = new CalendarDateResult();
			int dayOfWeek = DateUtil.dayOfWeek(dateStart);
			if (dayOfWeek == 1 || dayOfWeek == 7) {
				result.setWorkday(false);
			}
			result.setWorkDate(workDate);
			
			// 判断是否需要覆盖掉非自定义的作息时间信息
			if (CollectionUtil.isNotEmpty(customDates)) {
				historyOrRuleDates = this.coverCalendarDate(historyOrRuleDates, customDates, true);
			}
			
			result.setDate(DateUtil.dayOfMonth(dateStart));
			result.setWeek(WorkCalendarConstant.DAY_OF_WEEK.get(dayOfWeek));
			if (CollectionUtil.isNotEmpty(historyOrRuleDates)) {
				for (int j = historyOrRuleDates.size() - 1; j >= 0; j--) {
					WorkCalendarDate calendarDate = historyOrRuleDates.get(j);
					// 是工作日,剔除非工作日的数据,目前仅有OpenTime-1,工作日,OpenTime-2,休息日
					if (result.isWorkday() && "OpenTime-2".equals(calendarDate.getDictCode())) {
						historyOrRuleDates.remove(j);
					} else if (!result.isWorkday() && "OpenTime-1".equals(calendarDate.getDictCode())) {
						historyOrRuleDates.remove(j);
					}
				}
			}
			
			result.setTimeTable(CollectionUtil.isEmpty(historyOrRuleDates) ? Lists.newArrayList() : historyOrRuleDates);
			resultList.add(result);
			dateStart.offset(DateField.DAY_OF_YEAR, 1);	 	// 下一天
		}
		
		customDateMap.clear();   //释放
		calendarDateMap.clear();
		return resultList;
    }
    
    
    /**
	 * 自定义与规则的进行判断,存在的自定义的将不再进行插入
	 * 
	 * @param queryVO
	 * @param customDateList
	 * @param calendarDateMap
	 * @return
	 */
	public List<WorkCalendarDate> handleParseCalendarRule(WorkCalendarDateQueryVO queryVO, List<WorkCalendarDate> customDateList,
			Map<String, List<WorkCalendarDate>> calendarDateMap) {
		List<WorkCalendarDate> resultList = new ArrayList<WorkCalendarDate>();
		
		Set<String> keySet = calendarDateMap.keySet();
		if (CollectionUtil.isEmpty(customDateList)) {
			for (String key : keySet) {
				resultList.addAll(calendarDateMap.get(key));
			}
		} else {
			for (String key : keySet) {
				List<WorkCalendarDate> ruleDates = calendarDateMap.get(key);
				ruleDates = this.coverCalendarDate(ruleDates, customDateList, false);
				resultList.addAll(ruleDates);
			}
		}
		
		resultList.forEach(calendarDate -> calendarDate.setId(IdGenerator.getSnowIdStr(WorkCalendarConstant.WORK_CALENDAR_DATE_ID_PREFIX)));
		return resultList;
	}
	
    /**
     * 是否需要覆盖掉非自定义的作息时间,自定义覆盖掉规则的
     * 
     * @param ruleDates 允许为空
     * @param customDates 不能为空
     * @param isCover true-自定义的覆盖非自定义的,false-当天存在自定义的信息时,非自定义的丢弃
     * @return 不会返回null
     */
	private List<WorkCalendarDate> coverCalendarDate(List<WorkCalendarDate> ruleDates, List<WorkCalendarDate> customDates, boolean isCover) {
		if (CollectionUtil.isEmpty(ruleDates)) {
			return customDates;
		}
		
		// 开始验证
		List<WorkCalendarDate> result = new ArrayList<WorkCalendarDate>();
		Map<String, Integer> dictTypeLevelMap = new HashMap<String, Integer>();
		
		for (int i = ruleDates.size() - 1; i >= 0; i--) {
			WorkCalendarDate ruleDate = ruleDates.get(i);
			// 判断当前字典类型级别
			Integer dictTypeLevel = dictTypeLevelMap.get(ruleDate.getDictType());
			if (dictTypeLevel == null) {
				dictTypeLevel = this.workCalendarDictService.getDictTypeLevel(ruleDate.getGroupCode(), ruleDate.getDictType());
				dictTypeLevelMap.put(ruleDate.getDictType(), dictTypeLevel);
			}
			
			// 项目ID和工作历ID转换
			if (dictTypeLevel == 0) {
				ruleDate.setProjectId("0");
				ruleDate.setCalendarId("0");
			} else if (dictTypeLevel == 1) {
				ruleDate.setCalendarId("0");
			}
			
			boolean isCustom = false;
			for (WorkCalendarDate customDate : customDates) {
				// 项目ID和工作历ID转换
				if (dictTypeLevel == 0) {
					customDate.setProjectId("0");
					customDate.setCalendarId("0");
				} else if (dictTypeLevel == 1) {
					customDate.setCalendarId("0");
				}
				// 相等,证明非自定义的需要被覆盖
				if (customDate.equals(ruleDate)) {
					isCustom = true;
					if (isCover) {	// 是否需要将自定义的加入到结果集中
						result.add(customDate);
					} else {
						// 移除这一作息时间
						ruleDates.remove(i);
					}
					break;
				}
			}
			// 如果没有找到自定义的,加入到结果集
			if (!isCustom) {
				result.add(ruleDate);
			}
		}
		
		return result;
	}

    /**
	 * 解析此段时间的规则
	 * 
	 * @param ruleList 规则信息
	 * @param dateStart 开始时间
	 * @param betweenDay 时间范围
	 * @return 这里返回的结果,一定要在后续判断当日是否存在自定义的作息时间,才能继续使用,此处不会返回null
	 */
	public void paserWorkCalendarRule(Map<String, List<WorkCalendarDate>> calendarDateMap, List<WorkCalendarRule> ruleList, 
			DateTime dateStart, long betweenDay) {
		Map<String, WorkCalendar> calendarMap = new HashMap<String, WorkCalendar>();
		for(int i = 0; i < betweenDay; i++) {
			// 判断此天有没有对应的规则信息,每次都要循环全部,生成多条信息
			for (WorkCalendarRule rule : ruleList) {
				// 验证对应的工作历类型是否存,假若为工作历级别的规则配置
				WorkCalendar calendar = null;
				if (!"0".equals(rule.getCalendarId())) {
					calendar = this.workCalendarService.getById(rule.getCalendarId(), rule.getGroupCode(), rule.getProjectId());
					if (calendar == null) {
						log.warn("规则ID为[{}]的规则,所对应的工作历信息不存在", rule.getId());
						continue;
					}
				}
				// 判断当前规则是否生效
				WorkCalendarDate calendarDate = this.parseWorkCalendarRule(rule, calendar, dateStart);
				if (calendarDate == null) {
					continue;
				}
				// 数据添加
				String workDate = dateStart.toString(DateUtil.FORMAT_DATE_YYYYMMDD);
				if (calendarDateMap.containsKey(workDate)) {
					calendarDateMap.get(workDate).add(calendarDate);
				} else {
					calendarDateMap.put(workDate, Lists.newArrayList(calendarDate));
				}
			}
			
			dateStart.offset(DateField.DAY_OF_YEAR, 1);
		}
		
		calendarMap.clear();
	}
	
	/**
	 * 解析规则信息,生成对应作息时间记录
	 * 
	 * @param rule
	 * @param workCalendar 为null, 代表非工作历级别的规则配置
	 * @param dateStart
	 */
	private WorkCalendarDate parseWorkCalendarRule(WorkCalendarRule rule, WorkCalendar workCalendar, DateTime currentDate) {
		String workDate = currentDate.toString(DateUtil.FORMAT_DATE_YYYYMMDD);
		String dictCode = StringUtil.isBlank(rule.getDictCode()) ? "" : rule.getDictCode();
		int indexOf = dictCode.indexOf(WorkCalendarConstant.WORK_CALENDAR_D_OF_W);
		if (indexOf <= 0) {
			indexOf = dictCode.indexOf(WorkCalendarConstant.WORK_CALENDAR_D_OF_M);
			if (indexOf <= 0) {
				indexOf = dictCode.indexOf(WorkCalendarConstant.WORK_CALENDAR_M_AND_D);
			}
		}
		if (indexOf > 0) {
			dictCode = dictCode.substring(0, indexOf - 1);
		}
		
		// 解析规则,生成数据
		int work = Integer.valueOf(workDate);
		String ruleStart = rule.getRuleDateStart();
		String ruleEnd = rule.getRuleDateEnd();
		if (StringUtil.isNotBlank(ruleStart) && StringUtil.isNotBlank(ruleEnd)) {
			int start = Integer.valueOf(ruleStart);
			int end = Integer.valueOf(ruleEnd);
			if (work >= start && work <= end) {
				// 当日期生效
				if (indexOf > 0) {
					// 验证value是否存在,存在按周 月 解析,判断是否生效
					boolean result = this.parseRuleValue(rule, currentDate, workDate);
					if (!result) {
						return null;
					}
				}
				
				// 组合数据
				WorkCalendarDate calendarDate = this.comWorkCalendarOrRule(rule, workDate, dictCode, workCalendar);
				return calendarDate;
			}
		}
		
		return null;
	}
	
	
	/**
	 * 获取满足条件的所有新版规则信息
	 * TODO 这里工作历和项目ID不传参,则无影响,若传参了,目前仅支持工作历级别的规则解析
	 * 
	 * @param workCalendarDateQueryVO
	 * @param dictTypeLevel 0-集团级别,1-项目级别,2-工作历级别,null-默认工作历级别
	 * @return
	 */
	public List<WorkCalendarRule> selectWorkCalendarRuleList(WorkCalendarDateQueryVO queryVO, Integer dictTypeLevel) {
		QueryWrapper<WorkCalendarRule> queryWrapper = new WorkCalendarRule.Builder().createQueryWrapper().projectIdEq(queryVO.getProjectId(), dictTypeLevel)
				.calendarIdEq(queryVO.getCalendarId(), dictTypeLevel).ruleDateBetween(queryVO.getWorkDateStart(), queryVO.getWorkDateEnd())
				.dictTypeEq(queryVO.getDictType()).dictCodeIn(queryVO.getDictCode()).dictTypeIn(queryVO.getDictTypes())
				.idEq(queryVO.getRuleId()).delFlagEq(WorkCalendarConstant.WORK_CALENDAR_DEL_FLAG_NOR)
				.ruleFlagEq(WorkCalendarConstant.WORK_CALENDAR_RULE_FLAG_NEW).builderQueryWrapper();
    	return this.workCalendarRuleService.list(queryWrapper);
	}
	
	 /**
     * 获取满足条件的所有已存在的作息时间信息,包括自定义的
     * @param workCalendarDateQueryVO
     * @return
     */
	public List<WorkCalendarDate> selectWorkCalendarDateList(WorkCalendarDateQueryVO workCalendarDateQueryVO, String customFlag, Integer dictTypeLevel) {
		QueryWrapper<WorkCalendarDate> queryWrapper = new WorkCalendarDate.Builder().createQueryWrapper()
				.projectIdEq(workCalendarDateQueryVO.getProjectId(), dictTypeLevel).idEq(workCalendarDateQueryVO.getId())
				.ruleIdEq(workCalendarDateQueryVO.getRuleId()).calendarIdEq(workCalendarDateQueryVO.getCalendarId(), dictTypeLevel)
				.workDateGe(workCalendarDateQueryVO.getWorkDateStart()).workDateLe(workCalendarDateQueryVO.getWorkDateEnd())
				.dictTypeEq(workCalendarDateQueryVO.getDictType()).dictTypeIn(workCalendarDateQueryVO.getDictTypes())
				.dictCodeIn(workCalendarDateQueryVO.getDictCode()).calendarNameLike(workCalendarDateQueryVO.getCalendarName())
				.customFlagEq(customFlag).builderQueryWrapper();
		queryWrapper.select("ID, GROUP_CODE, RULE_ID, CALENDAR_ID, PROJECT_ID, CALENDAR_NAME, CALENDAR_DESC, DICT_TYPE, "
				+ "DICT_CODE, WORK_DATE, WORK_TIME, CUSTOM_FLAG, UPDATE_USER");
    	List<WorkCalendarDate> list = workCalendarDateService.list(queryWrapper);
    	return list == null ? new ArrayList<WorkCalendarDate>() : list;
	}
	
	/**
	 * 组合出作息时间对象
	 * 
	 * @param rule
	 * @param workDate
	 * @param dictCode
	 * @param workCalendar
	 * @return
	 */
	public WorkCalendarDate comWorkCalendarOrRule(WorkCalendarRule rule, String workDate, String dictCode, WorkCalendar workCalendar) {
		// 首先判断工作历是否还存在
		WorkCalendarDate workCalendarDate = new WorkCalendarDate();
		workCalendarDate.setGroupCode(rule.getGroupCode());
		workCalendarDate.setCalendarId(workCalendar == null ? "0" : workCalendar.getId());
		workCalendarDate.setRuleId(rule.getId());
		workCalendarDate.setCalendarName(workCalendar == null ? "" : workCalendar.getCalendarName());
		workCalendarDate.setCalendarDesc(workCalendar == null ? "" : workCalendar.getCalendarDesc());
		workCalendarDate.setProjectId(rule.getProjectId());
		workCalendarDate.setDictType(rule.getDictType());
		workCalendarDate.setDictCode(dictCode);
		workCalendarDate.setWorkDateStart(rule.getRuleDateStart());
		workCalendarDate.setWorkDateEnd(rule.getRuleDateEnd());
		workCalendarDate.setWorkDate(workDate);
		
		workCalendarDate.setWorkTime(StringUtil.isBlank(rule.getRuleTime()) ? 
				(CollectionUtil.isEmpty(rule.getValue()) ? null : rule.getValue().stream().collect(Collectors.joining(","))) 
				: rule.getRuleTime());
		// 自定义的一定是查出来的,封装的一定是非自定义添加的
		workCalendarDate.setCustomFlag(WorkCalendarConstant.CUSTOM_CALENDAR_DATE_NO);
		workCalendarDate.setUpdateUser(rule.getUpdateUser());
		return workCalendarDate;
	}
	
	
	/**
	 * 批量自定义作息时间信息
	 * @return 
	 */
	public void batchCreateCalendarDate(CustomCalendarVO<WorkCalendarDateCreateVO> createVO) {
		boolean result = false;
		List<WorkCalendarDateCreateVO> batchInfos = createVO.getBatchInfo();
		// 判断日期是否合法
		DateTime now = DateUtil.date();
		//now = now.offset(DateField.DAY_OF_YEAR, 1);	//明天
		String format = DateUtil.format(now, DateUtil.FORMAT_DATE_YYYYMMDD);
		Integer current = Integer.valueOf(format);
		for (WorkCalendarDateCreateVO batchInfo : batchInfos) {
			int dictTypeLevel = this.workCalendarDictService.getDictTypeLevel(createVO.getGroupCode(), batchInfo.getDictType());
			
			Integer workDate = Integer.valueOf(batchInfo.getWorkDate());
			if (workDate < current) {
				throw new BusinessException("作息日期不合法,必须大于等于当日");
			}
			// 判断工作历类型是否存在
			WorkCalendar calendar = null;
			if (dictTypeLevel == 2) {
				calendar = this.workCalendarService.getById(batchInfo.getCalendarId(), createVO.getGroupCode(), createVO.getProjectId());
				if (calendar == null) {
					throw new BusinessException("工作历类型不存在");
				}
			}
			
			WorkCalendarDate calendarDate = new WorkCalendarDate();
			BeanUtils.copyProperties(batchInfo, calendarDate);
			// 验证数据有效性
			result = this.workCalendarDateService.checkWorkDateValid(calendarDate, dictTypeLevel);
			if (!result) {
				throw new BusinessException("当天已存在相同类型额定义,不可重复添加");
			}
			calendarDate.setGroupCode(createVO.getGroupCode());
			calendarDate.setCalendarName(calendar == null ? null : calendar.getCalendarName());
			calendarDate.setCalendarDesc(calendar == null ? null : calendar.getCalendarDesc());
			calendarDate.setProjectId(dictTypeLevel == 0 ? "0" : createVO.getProjectId());
			if (dictTypeLevel != 2) {
				calendarDate.setCalendarId("0");
			}
			calendarDate.setUpdateUser(createVO.getUserId());
			calendarDate.setCustomFlag(WorkCalendarConstant.CUSTOM_CALENDAR_DATE_YES);
			result = this.workCalendarDateService.save(calendarDate);
			if (!result) {
				throw new BusinessException("自定义工作历作息时间添加失败");
			}
		}
	}
	
	/**
	 * 解析rule 的 value属性,判断其是否生效
	 * @param rule
	 * @param workDate
	 * @return value为空,默认返回true
	 */
	private boolean parseRuleValue(WorkCalendarRule rule, DateTime currentDate, String workDate) {
		if (CollectionUtil.isEmpty(rule.getValue())) {
			return true;
		}
		// 获取月日
		String mmddStr = workDate.substring(4, 8);
		Integer mmdd = Integer.valueOf(mmddStr);
		
		Set<String> values = rule.getValue();
		String dictCode = rule.getDictCode();
		String[] split = dictCode.split("-");
		dictCode = split[0];		// 真实的code编码
		String type = split[1];		// 类型
		switch (type) {
			case WorkCalendarConstant.WORK_CALENDAR_D_OF_W:	 //周
				// 1表示周日,2表示周一
				int dayOfWeek = DateUtil.dayOfWeek(currentDate);	
				dayOfWeek = dayOfWeek - 1;
				if (dayOfWeek == 0) {
					dayOfWeek = 7;
				}
				String num = String.valueOf(dayOfWeek);
				if (values.contains(num)) {
					return true;
				}
				break;
			case WorkCalendarConstant.WORK_CALENDAR_D_OF_M:	 //月
				// 当前日期为此月的第几天
				int ofMonth = DateUtil.dayOfMonth(currentDate);
				Iterator<String> iterator = values.iterator();
				while(iterator.hasNext()) {
					String next = iterator.next();
					if (next.contains("-")) {
						String[] split2 = next.split("-");
						int start = Integer.parseInt(split2[0]);
						int end = Integer.parseInt(split2[1]);
						if (ofMonth >= start && ofMonth <= end) {
							return true;
						}
					} else if (next.equals(String.valueOf(ofMonth))) {
						return true;
					}
				}
				break;
			case WorkCalendarConstant.WORK_CALENDAR_M_AND_D: //年
				iterator = values.iterator();
				while(iterator.hasNext()) {
					String next = iterator.next();
					if (next.contains("-")) {
						String[] split2 = next.split("-");
						Integer startInt = Integer.valueOf(split2[0]);
						Integer endInt = Integer.valueOf(split2[1]);
						if (mmdd >= startInt && mmdd <= endInt) {
							return true;
						}
					} else if (mmddStr.equals(next)) {
						return true;
					}
				}
				break;
			default: 
				break;
		}
		return false;
	}
	
	/**
	 * 批量自定义作息时间信息
	 * @return 
	 */
	public <T> void batchUpdateCalendarDate(CustomCalendarVO<WorkCalendarDateUpdateVO> updateVO) {
		boolean result = false;
		List<WorkCalendarDateUpdateVO> batchInfos = updateVO.getBatchInfo();
		// 判断日期是否合法
		DateTime now = DateUtil.date();
		//now = now.offset(DateField.DAY_OF_YEAR, 1);	//明天
		String format = DateUtil.format(now, DateUtil.FORMAT_DATE_YYYYMMDD);
		Integer current = Integer.valueOf(format);
		for (WorkCalendarDateUpdateVO batchInfo : batchInfos) {
			Integer workDate = Integer.valueOf(batchInfo.getWorkDate());
			if (workDate < current) {
				throw new BusinessException("作息日期不合法,必须大于等于当日");
			}
			// 验证是否存在
			WorkCalendarDate temp = this.workCalendarDateService.getById(batchInfo.getId());
			if (temp == null || !WorkCalendarConstant.CUSTOM_CALENDAR_DATE_YES.equals(temp.getCustomFlag())) {
				throw new BusinessException("当天不存在自定义的作息时间信息");
			}
			int dictTypeLevel = this.workCalendarDictService.getDictTypeLevel(updateVO.getGroupCode(), batchInfo.getDictType());
			
			// 判断工作历类型是否存在
			WorkCalendar calendar = null;
			if (dictTypeLevel == 2) {
				calendar = this.workCalendarService.getById(batchInfo.getCalendarId(), updateVO.getGroupCode(), updateVO.getProjectId());
				if (calendar == null) {
					throw new BusinessException("工作历类型不存在");
				}
			}
			
			WorkCalendarDate calendarDate = new WorkCalendarDate();
			BeanUtils.copyProperties(batchInfo, calendarDate);
			calendarDate.setCustomFlag(WorkCalendarConstant.CUSTOM_CALENDAR_DATE_YES);
			
			calendarDate.setGroupCode(updateVO.getGroupCode());
			calendarDate.setCalendarName(calendar == null ? null : calendar.getCalendarName());
			calendarDate.setCalendarDesc(calendar == null ? null : calendar.getCalendarDesc());
			calendarDate.setProjectId(dictTypeLevel == 0 ? "0" : updateVO.getProjectId());
			if (dictTypeLevel != 2) {
				calendarDate.setCalendarId("0");
			}
			
			calendarDate.setUpdateUser(updateVO.getUserId());
			result = this.workCalendarDateService.updateById(calendarDate);
			if (!result) {
				throw new BusinessException("自定义工作历作息时间添加失败");
			}
		}
	}

	/**
	 * 多时间段添加工作历作息时间信息,先删除此dictType下数据,再添加
	 * 
	 * @param createVO
	 * @param calendar 
	 */
	@Transactional
	public void batchCreateCalendarMoreDate(WorkCalendarMoreDateCreateVO createVO, WorkCalendar calendar) {
		int dictTypeLevel = this.workCalendarDictService.getDictTypeLevel(createVO.getGroupCode(), createVO.getDictType());
		
		String calendarId = createVO.getCalendarId();
		String projectId = createVO.getProjectId();
		String now = DateUtil.format(new Date(), DateUtil.FORMAT_DATE_YYYYMMDDHHMMSS);
		DateTime dateStart = DateUtil.parse(createVO.getWorkDateStart(), DateUtil.FORMAT_DATE_YYYYMMDD);
		DateTime dateEnd = DateUtil.parse(createVO.getWorkDateEnd(), DateUtil.FORMAT_DATE_YYYYMMDD);
		long betweenDay = DateUtil.between(dateStart, dateEnd, DateUnit.DAY) + 1;
		
		Set<String> timetables = createVO.getTimetable();
		List<WorkCalendarDate> datas = new ArrayList<WorkCalendarDate>();
		for (int i = 0; i < betweenDay; i++) {
			String currentDay = DateUtil.format(dateStart, DateUtil.FORMAT_DATE_YYYYMMDD);
			if (CollectionUtil.isEmpty(timetables)) {
				WorkCalendarDate calendarDate = this.setCalendarDate(createVO, calendar, currentDay, null, now);
				datas.add(calendarDate);
			} else {
				for (String timetable : timetables) {
					// 数据库数据组装
					WorkCalendarDate calendarDate = this.setCalendarDate(createVO, calendar, currentDay, timetable, now);
					datas.add(calendarDate);
				}
			}
			
			// 偏移天数
			dateStart.offset(DateField.DAY_OF_YEAR, 1);
		}
		// 先删除
		QueryWrapper<WorkCalendarDate> queryWrapper = new WorkCalendarDate.Builder().createQueryWrapper()
				.calendarIdEq(calendarId, dictTypeLevel).projectIdEq(projectId, dictTypeLevel).dictTypeEq(createVO.getDictType())
				.workDateGe(createVO.getWorkDateStart()).workDateLe(createVO.getWorkDateEnd())
				.customFlagEq(createVO.getCustomFlag()).builderQueryWrapper();
		this.workCalendarDateService.remove(queryWrapper);
		
		// 批量添加数据
		this.workCalendarDateService.batchCreateCalendarDate(datas);
	}
	
	/**
	 * 参数赋值
	 * @param createVO
	 * @param calendar
	 * @param currentDay
	 * @param timetable
	 * @param now
	 * @return
	 */
	private WorkCalendarDate setCalendarDate(WorkCalendarMoreDateCreateVO createVO, WorkCalendar calendar, 
			String currentDay, String timetable, String now) {
		WorkCalendarDate calendarDate = new WorkCalendarDate();
		calendarDate.setId(IdGenerator.getSnowIdStr(WorkCalendarConstant.WORK_CALENDAR_DATE_ID_PREFIX));
		calendarDate.setGroupCode(createVO.getGroupCode());
		calendarDate.setProjectId(createVO.getProjectId());
		calendarDate.setCalendarId(createVO.getCalendarId());
		calendarDate.setCustomFlag(WorkCalendarConstant.CUSTOM_CALENDAR_DATE_YES);
		calendarDate.setCalendarName(calendar == null ? "" : calendar.getCalendarName());
		calendarDate.setCalendarDesc(calendar == null ? "" : calendar.getCalendarDesc());
		calendarDate.setDictType(createVO.getDictType());
		calendarDate.setDictCode(createVO.getDictCode());
		calendarDate.setWorkDate(currentDay);
		calendarDate.setWorkTime(timetable);
		calendarDate.setCreateTime(now);
		calendarDate.setUpdateTime(now);
		calendarDate.setUpdateUser(createVO.getUserId());
		
		return calendarDate;
	}
	
	/**
	 * 检查参数日期是否大于当前日期
	 * @param workDate 工作日期 yyyyMMdd
	 * @return
	 */
	public static boolean isMoreThanToday(String workDate) {
		DateTime now = DateUtil.date();
		//now = now.offset(DateField.DAY_OF_YEAR, 1);		//明天
		String format = DateUtil.format(now, DateUtil.FORMAT_DATE_YYYYMMDD);
		Integer current = Integer.valueOf(format);
		Integer dateInt = Integer.valueOf(workDate);
		if (dateInt < current) {
			return false;
		}
		return true;
	}
	
	/**
	 * 解析起止时间,判读当前时间位于哪里
	 * @param dateStart yyyyMMdd
	 * @param dateEnd yyyyMMdd
	 * @param now yyyyMMdd
	 * @return
	 */
	private Map<String, DateTime> parseWorkDate(DateTime dateStart, DateTime dateEnd, String now) {
		if (dateEnd.before(dateStart)) {
			throw new BusinessException(ResponseCode.A0400.getCode(), "结束日期不能早于开始日期");
		}
		
		DateTime historyStart = null;
		DateTime historyEnd = null;
		DateTime parseRuleStart = null;
		DateTime parseRuleEnd = null;
		
		Map<String, DateTime> result = new HashMap<String, DateTime>();
		
		DateTime currentDate = DateUtil.parse(now, DateUtil.FORMAT_DATE_YYYYMMDD);
		// 第一种情况,当日在start之前
		if (!dateStart.before(currentDate)) {
			// 开始日期,不早于当日,全部走解析
			parseRuleStart = dateStart;
			parseRuleEnd = dateEnd;
		} else if (dateStart.before(currentDate) && !dateEnd.before(currentDate)) {
			// 第二种情况,当日在start~end之间,包含等于dateEnd 的情况
			historyStart = dateStart;
			historyEnd = currentDate.offset(DateField.DAY_OF_YEAR, -1);
			parseRuleStart = DateUtil.parse(now, DateUtil.FORMAT_DATE_YYYYMMDD);
			parseRuleEnd = dateEnd;
		} else {
			// 第三种情况,当日在dataEnd之后,全部查历史即可
			historyStart = dateStart;
			historyEnd = dateEnd;
		}
		
		result.put("historyStart", historyStart);
		result.put("historyEnd", historyEnd);
		result.put("parseRuleStart", parseRuleStart);
		result.put("parseRuleEnd", parseRuleEnd);
		return result;
	}
	
	/**
	 * 判断是否存在自动作息时间的依据key
	 * 
	 * @param calendarId 工作历类型ID
	 * @param workDate 当日
	 * @param dictType 字典类型,不可为空
	 * @param dictCode 字典类型下的编码,允许为空
	 * @return
	 */
	public String getCustomCalendarDateTempKey(String calendarId, String workDate, String dictType, String dictCode) {
		return workDate + dictType + (StringUtil.isBlank(dictCode) ? "" : dictCode);
	}
	
	/**
	 * 判断是否存在自动作息时间的依据key
	 * 
	 * @param rule
	 * @param workDate
	 * @param dictCode
	 * @return
	 */
	public String getCustomKey(WorkCalendarRule rule, String workDate, String dictCode) {
		String customKey = rule.getCalendarId() + rule.getProjectId() + workDate + rule.getDictType() + (StringUtil.isBlank(dictCode) ? "" : dictCode);
		return customKey;
	}

}