package weaver.sqsddldcxt.attendance.service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.cloudstore.dev.api.util.Util_TableMap;
import com.engine.kq.biz.KQBalanceOfLeaveBiz;
import com.engine.kq.biz.KQOverTimeFlowBiz;
import com.engine.kq.biz.KQOverTimeRuleCalBiz;
import com.engine.kq.biz.KQOvertimeLogBiz;
import com.engine.kq.biz.KQOvertimeRulesBiz;
import com.engine.kq.biz.KQReportBiz;
import com.engine.kq.biz.KQTimesArrayComInfo;
import com.engine.kq.biz.KQWorkTime;
import com.engine.kq.biz.chain.cominfo.ShiftInfoCominfoBean;
import com.engine.kq.biz.chain.shiftinfo.ShiftInfoBean;
import com.engine.kq.entity.KQOvertimeRulesDetailEntity;
import com.engine.kq.entity.TimeScopeEntity;
import com.engine.kq.entity.WorkTimeEntity;
import com.engine.kq.log.KQLog;
import com.engine.kq.timer.KQOvertimeCardBean;
import com.engine.kq.util.KQDurationCalculatorUtil;
import com.engine.kq.wfset.bean.OvertimeBalanceTimeBean;
import com.engine.kq.wfset.bean.SplitBean;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import weaver.common.StringUtil;
import weaver.conn.RecordSet;
import weaver.general.TimeUtil;
import weaver.general.Util;
import weaver.hrm.User;
import weaver.systeminfo.SystemEnv;


public class OvertimeRuleComputingMode5Service {
	private KQLog kqLog = null;
	private KQOverTimeRuleCalBiz calBiz = null;
	
	private int computingMode = 5;
	
	public int getComputingMode() {
		return this.computingMode;
	}
	
	public String getComputingModeTitle(int languageId) {
		return SystemEnv.getHtmlLabelName(536733, languageId);
	}
	
	public OvertimeRuleComputingMode5Service() {
		this.kqLog = new KQLog();
		this.calBiz = new KQOverTimeRuleCalBiz();
	}

	  public void doComputingMode(String resourceid, String splitDate,
	      Map<String, Integer> changeTypeMap,
	      Map<String, KQOvertimeRulesDetailEntity> overRulesDetailMap,
	      Map<String, List<String[]>> restTimeMap, Map<String, Integer> computingModeMap,
	      String main_uuid) {
		DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		KQTimesArrayComInfo kqTimesArrayComInfo = new KQTimesArrayComInfo();
	    String key = resourceid+"_"+splitDate;
	    //加班日志记录类
	    KQWorkTime kqWorkTime = new KQWorkTime();
	    WorkTimeEntity workTimeEntity = kqWorkTime.getWorkTime(resourceid, splitDate);
	    Map<String,Object> workTimeEntityLogMap = Maps.newHashMap();
	    workTimeEntityLogMap.put("resourceid", resourceid);
	    workTimeEntityLogMap.put("splitDate", splitDate);
	    workTimeEntityLogMap.put("workTimeEntity", workTimeEntity);
	    KQOvertimeLogBiz kqEventLogBiz = new KQOvertimeLogBiz();
	    String uuid = kqEventLogBiz.logDetailWorkTimeEntity(resourceid,workTimeEntityLogMap,main_uuid,"doComputingMode"+computingMode+"|加班计算,需审批，加班和出差、公出均统计，取两者的交集|key|"+key);
	    Map<String,Object> overtimeLogMap = Maps.newLinkedHashMap();

	    Map<String,Object> eventMap = Maps.newLinkedHashMap();
	    Map<String, KQOvertimeCardBean> lsCheckInfoMaps = Maps.newLinkedHashMap();
	    //获取出差、公出数据 
	    try {
			getFlowDataMap(resourceid, splitDate, splitDate, dateFormatter,kqTimesArrayComInfo,overRulesDetailMap,changeTypeMap,lsCheckInfoMaps,eventMap);
		} catch (Exception e) {
		}

	    if(lsCheckInfoMaps.isEmpty()){
	      calBiz.logOvertimeMap(overtimeLogMap, "没有出差、公出数据", "出差、公出数据");
	      kqEventLogBiz.logDetailOvertimeMap(resourceid,overtimeLogMap,uuid);
	      kqEventLogBiz.logDetailEvent(resourceid,eventMap,uuid,"doComputingMode"+computingMode+"|对应的加班流程数据|key|"+key);
	      return;
	    }
	    RecordSet rs = new RecordSet();
	    Iterator<Entry<String, KQOvertimeCardBean>> iterator = lsCheckInfoMaps.entrySet().iterator();
	    while (iterator.hasNext()) {
	      Entry<String, KQOvertimeCardBean> next = iterator.next();
	      String mapKey = next.getKey();
	      KQOvertimeCardBean kqOvertimeCardBean = next.getValue();
	      String[] mapKeys = mapKey.split("_");
	      if (mapKeys.length != 2) {
	        continue;
	      }
	      String realSplitDate = mapKeys[1];

	      Map<String,List<SplitBean>> splitBeanMaps = Maps.newHashMap();
	      //获取加班流程数据
	      calBiz.getOverTimeFlowData(resourceid,realSplitDate,realSplitDate,splitBeanMaps,dateFormatter);

	      String change_key = realSplitDate+"_"+resourceid;
	      int changeType = Util.getIntValue(""+changeTypeMap.get(change_key),-1);
	      String changeType_key = realSplitDate+"_"+changeType;
	      String changetypeName = 1==changeType ? "节假日" : (2 == changeType ? "工作日" : (3 == changeType ? "休息日" : "异常"));
	      String changetypeLogInfo = change_key+"|changeType|"+changeType+"|"+changetypeName;
	      calBiz.logOvertimeMap(overtimeLogMap, changetypeLogInfo, mapKey+"|"+"加班日期属性|changetypeLogInfo");

	      calBiz.clearOvertimeTX(resourceid, realSplitDate,overtimeLogMap,splitDate);
	      calBiz.logOvertimeMap(overtimeLogMap, kqOvertimeCardBean, mapKey+"|"+"出差、公出和加班数据|KQOvertimeCardBean");

	      KQOvertimeRulesDetailEntity kqOvertimeRulesDetailEntity = overRulesDetailMap.get(changeType_key);
	      if(kqOvertimeRulesDetailEntity == null){
	        String overRuleInfo = "changeType_key:"+changeType_key+":kqOvertimeRulesDetailEntity:"+kqOvertimeRulesDetailEntity;
	        calBiz.logOvertimeMap(overtimeLogMap, overRuleInfo, mapKey+"|"+"加班规则为null|kqOvertimeRulesDetailEntity");
	        continue;
	      }
	      int overtimeEnable = kqOvertimeRulesDetailEntity.getOvertimeEnable();
	      if(overtimeEnable != 1){
	        String overtimeEnableInfo = "overtimeEnable:"+overtimeEnable;
	        calBiz.logOvertimeMap(overtimeLogMap, overtimeEnableInfo, mapKey+"|"+"未开启加班规则|overtimeEnable");
	        continue;
	      }

	      if(kqOvertimeCardBean != null){

	        int[] initArrays = kqTimesArrayComInfo.getInitArr();
	        List<Map<String, String>> hasOverTime4SignList = Lists.newArrayList();
	        calBiz.getHasOverTimeData(resourceid,realSplitDate,hasOverTime4SignList);
	        Map<String, String> signinoffMap = null;
			try {
				signinoffMap = calBiz.buildOvertimeCard(kqOvertimeCardBean, resourceid, realSplitDate, kqTimesArrayComInfo, restTimeMap, changeType_key,initArrays,hasOverTime4SignList,
				    overRulesDetailMap,true,overtimeLogMap);
			} catch (Exception e) {
			}
			if(signinoffMap == null) signinoffMap = Maps.newHashMap();
	        calBiz.logOvertimeMap(overtimeLogMap, signinoffMap, mapKey+"|"+"获取上下班出差、公出数据|signinoffMap");

	        String signinTime = Util.null2String(signinoffMap.get("signinTime"));
	        String signoutTime = Util.null2String(signinoffMap.get("signoutTime"));
	        String signinDate = Util.null2String(signinoffMap.get("signinDate"));
	        String signoutDate = Util.null2String(signinoffMap.get("signoutDate"));
	        int signinTimeIndex = kqTimesArrayComInfo.getArrayindexByTimes(signinTime);
	        int signoutTimeIndex = kqTimesArrayComInfo.getArrayindexByTimes(signoutTime);

	        if(signinTimeIndex < signoutTimeIndex){
	          //先覆盖出差、公出区间都是1
	          int over_count = kqTimesArrayComInfo.getCnt(initArrays, signinTimeIndex, signoutTimeIndex, 1);
	          String overCountLogInfo = "signinTimeIndex:"+signinTimeIndex+":signoutTimeIndex:"+signoutTimeIndex+":over_count:"+over_count;
	          calBiz.logOvertimeMap(overtimeLogMap, overCountLogInfo, mapKey+"|"+"出差、公出区间，得到出差、公出时长|over_count");
	          if(over_count > 0){
	            int restTimeType = 1;
	            String kqOvertimeRulesDetailEntityLogInfo = kqOvertimeRulesDetailEntity==null ? "" :JSON.toJSONString(kqOvertimeRulesDetailEntity);
	            calBiz.logOvertimeMap(overtimeLogMap, kqOvertimeRulesDetailEntityLogInfo, mapKey+"|具体这个人这一天对应的加班规则|KQOvertimeRulesDetailEntity");
	            int minimumLen = -1;
	            if(kqOvertimeRulesDetailEntity != null){
	              minimumLen = kqOvertimeRulesDetailEntity.getMinimumLen();
	              if(over_count < minimumLen){
	                String minInfo = "over_count:"+over_count+":minimumLen:"+minimumLen;
	                calBiz.logOvertimeMap(overtimeLogMap, minInfo, mapKey+"|出差、公出时长小于最小加班时长|over_count<minimumUnit");
	                continue;
	              }
	            }
	            if(splitBeanMaps.containsKey(mapKey)) {
	              List<SplitBean> splitBeans = splitBeanMaps.get(mapKey);
	              String flowinfo = "";
	              if(splitBeans != null && !splitBeans.isEmpty()){
	                flowinfo = JSON.toJSONString(splitBeans, SerializerFeature.DisableCheckSpecialChar,SerializerFeature.DisableCircularReferenceDetect);
	              }
	              eventMap.put(mapKey+"|"+"加班流程数据|flowinfo", flowinfo);

	              if(splitBeans == null || splitBeans.isEmpty()){
	                return;
	              }

	              for (int m = 0; m < splitBeans.size(); m++) {
	                SplitBean splitBean = splitBeans.get(m);
	                String dataid = splitBean.getDataId();
	                String detailid = splitBean.getDetailId();
	                String flow_fromdate = splitBean.getFromDate();
	                String flow_fromtime = splitBean.getFromTime();
	                String flow_todate = splitBean.getToDate();
	                String flow_totime = splitBean.getToTime();
	                String fromdatedb = splitBean.getFromdatedb();
	                String fromtimedb = splitBean.getFromtimedb();
	                String todatedb = splitBean.getTodatedb();
	                String totimedb = splitBean.getTotimedb();
	                String requestid = splitBean.getRequestId();
	                double d_mins = splitBean.getD_Mins();
	                if(d_mins <= 0){
	                  continue;
	                }
	                String flow_key =  mapKey+"|"+"flow_fromdate|"+flow_fromdate+"|flow_todate|"+flow_todate
	                    +"|flow_fromtime|"+flow_fromtime+"|flow_totime|"+flow_totime;
	                //如果打卡数据有了，再拿流程数据去覆盖，得到有效的打卡区间，这个区间肯定已经是去除了上下班时间和休息时间还有重复打卡的部分
	                List<Integer> cross_time_list = Lists.newArrayList();
//	              cross_time_list里存的是排除了工作时间的打卡段，找到1表示找到打卡开始的点了，找到-2表示找到打卡结束的点了
	                calBiz.get_cross_time_list(cross_time_list,initArrays,signinTimeIndex,signoutTimeIndex,1,-2);
	                calBiz.logOvertimeMap(overtimeLogMap, cross_time_list, flow_key+"|cross_time_list");
	                int[] initArrays_flow = Arrays.copyOfRange(initArrays,0,initArrays.length);
	                if(flow_fromdate.compareTo(realSplitDate) > 0){
	                  flow_fromtime = kqTimesArrayComInfo.turn24to48Time(flow_fromtime);
	                }
	                if(flow_todate.compareTo(realSplitDate) > 0){
	                  flow_totime = kqTimesArrayComInfo.turn24to48Time(flow_totime);
	                }
	                int flow_fromIndex = kqTimesArrayComInfo.getArrayindexByTimes(flow_fromtime);
	                int flow_toIndex = kqTimesArrayComInfo.getArrayindexByTimes(flow_totime);
	                //在已经出差、公出的区间1上覆盖2，那么在有效出差、公出范围内是2的就是交集的部分
	                Arrays.fill(initArrays_flow, flow_fromIndex, flow_toIndex,2);

	                int across_mins = 0;
	                for(int i = 0 ; i < cross_time_list.size() ;) {
	                  int cross_fromtime_index = cross_time_list.get(i);
	                  int cross_totime_index = cross_time_list.get(i + 1);
	                  //前面打卡区间段已经都被流程给覆盖了，所以取获取打卡区间段内有多少流程的标识2，就是交叉部分了
	                  int flow_count = kqTimesArrayComInfo.getCnt(initArrays_flow, cross_fromtime_index, cross_totime_index, 2);
	                  calBiz.logOvertimeMap(overtimeLogMap, flow_count, flow_key+"|取出差、公出和加班相交的时长|flow_count");

	                  if(flow_count > 0){
	                    List<Integer> flow_cross_time_list = Lists.newArrayList();
	                    // 找到2表示找到流程开始的点了，找到1表示找到流程结束的点了
	                    calBiz.get_cross_time_list(flow_cross_time_list,initArrays_flow,cross_fromtime_index,cross_totime_index,2,1);

	                    calBiz.logOvertimeMap(overtimeLogMap, flow_cross_time_list, flow_key+"|取出差、公出和加班相交的区间|flow_cross_time_list");
	                    for(int j = 0 ; j < flow_cross_time_list.size() ;){
	                      int flow_cross_fromtime_index = flow_cross_time_list.get(j);
	                      int flow_cross_totime_index = flow_cross_time_list.get(j+1);

	                      int mins = flow_cross_totime_index-flow_cross_fromtime_index;
	                      if(mins <= 0){
	                        String crossInfo = "flow_cross_fromtime_index:"+flow_cross_fromtime_index+":flow_cross_totime_index:"+flow_cross_totime_index+":mins:"+mins;
	                        calBiz.logOvertimeMap(overtimeLogMap, crossInfo, flow_key+"|出差、公出时长小于最小加班时长|crossInfo");
	                        continue;
	                      }
	                      across_mins += mins;

	                      String flow_cross_key = "加班计算区间|"+kqTimesArrayComInfo.getTimesByArrayindex(flow_cross_fromtime_index)+"-"+kqTimesArrayComInfo.getTimesByArrayindex(flow_cross_totime_index);
	                      calBiz.logOvertimeMap(overtimeLogMap, mins, flow_cross_key+"|原始加班区间生成的加班时长|mins");

	                      String cross_fromtime = kqTimesArrayComInfo.getTimesByArrayindex(flow_cross_fromtime_index);
	                      String cross_totime = kqTimesArrayComInfo.getTimesByArrayindex(flow_cross_totime_index);
	                      String cross_fromdate = realSplitDate;
	                      String cross_todate = realSplitDate;

	                      boolean needSplitByTime = false;
	                      if(needSplitByTime){
	                        //        按照加班时长转调休的 时长设置 这个逻辑如果后面要开启来可以直接用的
	                        List<String> timepointList = null;
	                        if(kqOvertimeRulesDetailEntity != null){
	                          timepointList = calBiz.get_timepointList(kqOvertimeRulesDetailEntity);
	                          calBiz.logOvertimeMap(overtimeLogMap, timepointList, flow_cross_key+"|如果要生成调休且是根据时间区间来转调休，返回对应的时间区间|timepointList");
	                        }

	                        List<OvertimeBalanceTimeBean> overtimeBalanceTimeBeans = Lists.newArrayList();
	                        if(timepointList != null && !timepointList.isEmpty()){
	                          int[] time_initArrays = kqTimesArrayComInfo.getInitArr();
	                          for(int t = flow_cross_fromtime_index;t < flow_cross_totime_index; t++){
	                            time_initArrays[t] = initArrays_flow[t];
	                          }
	                          calBiz.get_overtimeBalanceTimeBeans(timepointList,overtimeBalanceTimeBeans,kqTimesArrayComInfo,time_initArrays,flow_cross_totime_index,flow_cross_fromtime_index,2);
	                        }
	                        String overtimeBalanceTimeBeansLogInfo = "";
	                        if(overtimeBalanceTimeBeans == null || overtimeBalanceTimeBeans.isEmpty()){
	                        }else{
	                          overtimeBalanceTimeBeansLogInfo = JSON.toJSONString(overtimeBalanceTimeBeans);
	                        }
	                        calBiz.logOvertimeMap(overtimeLogMap, overtimeBalanceTimeBeansLogInfo, flow_cross_key+"|如果要生成调休且是根据时间区间来转调休，返回对应的时间区间对应的时长|overtimeBalanceTimeBeans");

	                        if(overtimeBalanceTimeBeans != null && !overtimeBalanceTimeBeans.isEmpty()){
	                          String bean_cross_fromtime = cross_fromtime;
	                          String bean_cross_totime = cross_totime;
	                          for(int timeIndex = 0 ; timeIndex < overtimeBalanceTimeBeans.size() ;timeIndex++){
	                            OvertimeBalanceTimeBean overtimeBalanceTimeBean = overtimeBalanceTimeBeans.get(timeIndex);
	                            String timePointStart = overtimeBalanceTimeBean.getTimepoint_start();
	                            String timePointEnd = overtimeBalanceTimeBean.getTimepoint_end();
	                            boolean isNeedTX = overtimeBalanceTimeBean.isNeedTX();
	                            int timePointStart_index = kqTimesArrayComInfo.getArrayindexByTimes(timePointStart);
	                            int timePointEnd_index = kqTimesArrayComInfo.getArrayindexByTimes(timePointEnd);
	                            if(timePointStart_index > flow_cross_fromtime_index){
	                              bean_cross_fromtime = kqTimesArrayComInfo.getTimesByArrayindex(timePointStart_index);
	                            }else{
	                              bean_cross_fromtime = cross_fromtime;
	                            }
	                            if(timePointEnd_index < flow_cross_totime_index){
	                              bean_cross_totime = kqTimesArrayComInfo.getTimesByArrayindex(timePointEnd_index);
	                            }else{
	                              bean_cross_totime = cross_totime;
	                            }
	                            int timepoint_mins = overtimeBalanceTimeBean.getTimepoint_mins();
	                            if(timepoint_mins == 0){
	                              continue;
	                            }
	                            mins = timepoint_mins;
	                          }
	                        }
	                      }else{
	                      }
	                      j =j + 2;
	                    } }else{

	                  }
	                  i = i +2;
	                }

	                if(kqOvertimeRulesDetailEntity != null){
	                  //我这个方法是针对每次生成的加班数据做排除休息时长的处理
	                  restTimeType = kqOvertimeRulesDetailEntity.getRestTimeType();
	                  if(restTimeType == 2){
	                    across_mins = new KQOverTimeFlowBiz().handle_restlength(across_mins,restTimeMap,changeType_key);
	                  }
	                }
	                int card_mins = over_count;
	                double double_mins = calBiz.getD_MinsByUnit((1.0*across_mins));
	                across_mins = (int)double_mins;
	                if(across_mins <= 0){
	                  calBiz.logOvertimeMap(overtimeLogMap, across_mins, flow_key+"|经过单位换算之后时长为0|across_mins");
	                  continue;
	                }
	                if(across_mins < minimumLen){
	                  String minInfo = "across_mins:"+across_mins+":minimumLen:"+minimumLen;
	                  calBiz.logOvertimeMap(overtimeLogMap, minInfo, flow_key+"|出差、公出时长小于最小加班时长|over_count<minimumUnit");
	                  continue;

	                }

	                String overtime_uuid = UUID.randomUUID().toString();
	                String tiaoxiuId = "";
	                String flow_dataid = "";

	                int unit = KQOvertimeRulesBiz.getMinimumUnit();
	                String workingHours = "";
	                String overtime_type = splitBean.getOvertime_type();
	                Map<String,Object> otherParam = Maps.newHashMap();
	                otherParam.put("overtime_type", overtime_type);
	                int paidLeaveEnableType = kqOvertimeRulesDetailEntity.getPaidLeaveEnableType();
	                if(2 == paidLeaveEnableType){
	                  calBiz.logOvertimeMap(overtimeLogMap, overtime_type, flow_key+"|关联调休与否来自于流程选择,加班类型下拉框值|overtime_type");
	                }

	                int paidLeaveEnable = calBiz.getPaidLeaveEnable(kqOvertimeRulesDetailEntity, overtime_type);
	                //目前不处理按照时间段生成调休
	                boolean needSplitByTime = false;//getNeedSplitByTime(kqOvertimeRulesDetailEntity, paidLeaveEnable);
	                if(needSplitByTime){

	                }else{
	                  otherParam.put("overtimeLogMap", overtimeLogMap);
	                  calBiz.logOvertimeMap(overtimeLogMap, across_mins, flow_key+"|最终生成的加班分钟数|overtime_mins");
	                  tiaoxiuId = KQBalanceOfLeaveBiz.addExtraAmountByDis5(resourceid,realSplitDate,across_mins+"","0",workingHours,requestid,"1",realSplitDate,otherParam);
	                  if(Util.getIntValue(tiaoxiuId) > 0){
	                    kqLog.info("doComputingMode"+computingMode+" 生成调休成功，调休id:"+tiaoxiuId+":resourceid:"+resourceid+":realSplitDate:"+realSplitDate);
	                  }else{
	                    kqLog.info("doComputingMode"+computingMode+" 生成调休失败，调休id:"+tiaoxiuId+":resourceid:"+resourceid+":realSplitDate:"+realSplitDate);
	                  }
	                  calBiz.logOvertimeMap(overtimeLogMap, tiaoxiuId, flow_key+"|最终生成的调休id|tiaoxiuId");

	                  String flow_overtime_sql = "insert into kq_flow_overtime (requestid,resourceid,fromdate,fromtime,todate,totime,duration_min,expiringdate,belongdate,"
	                      + "workMins,durationrule,changetype,paidLeaveEnable,computingMode,tiaoxiuId,uuid,fromdatedb,fromtimedb,todatedb,totimedb,flow_mins,card_mins,ori_belongdate,flow_dataid)"+
	                      " values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ";
	                  signinTime = kqTimesArrayComInfo.turn48to24Time(signinTime);
	                  signoutTime = kqTimesArrayComInfo.turn48to24Time(signoutTime);
	                  if(signinTime.length() == 5){
	                    signinTime = signinTime+":00";
	                  }
	                  if(signoutTime.length() == 5){
	                    signoutTime = signoutTime+":00";
	                  }
	                  rs.executeUpdate(flow_overtime_sql, requestid,resourceid,signinDate,signinTime,signoutDate,signoutTime,across_mins,"",realSplitDate,
	                      "",unit,changeType,paidLeaveEnable,computingMode,tiaoxiuId,overtime_uuid,fromdatedb,fromtimedb,todatedb,totimedb,d_mins,card_mins,splitDate,flow_dataid);

	                  String overtimeid = calBiz.get_overtime_uuid(overtime_uuid);
	                  kqEventLogBiz.updateOvertimeId(uuid, overtimeid);
	                }
	              }
	            }else{
	              //有打卡没有流程
	              calBiz.logOvertimeMap(overtimeLogMap, mapKey, mapKey+"|"+"加班流程为空");
	            }
	          }else{
	            calBiz.logOvertimeMap(overtimeLogMap, overCountLogInfo, mapKey+"|"+"出差、公出数据时长为0");
	          }
	        }else{
	          String overCountLogInfo = "signinTimeIndex:"+signinTimeIndex+":signoutTimeIndex:"+signoutTimeIndex;
	          calBiz.logOvertimeMap(overtimeLogMap, overCountLogInfo, mapKey+"|"+"出差、公出数据异常");
	        }
	      }else{
	        calBiz.logOvertimeMap(overtimeLogMap, "出差、公出数据KQOvertimeCardBean为null", mapKey+"|"+"出差、公出和加班数据|KQOvertimeCardBean");
	      }
	    }
	    kqEventLogBiz.logDetailOvertimeMap(resourceid,overtimeLogMap,uuid);
	    kqEventLogBiz.logDetailEvent(resourceid,eventMap,uuid,"doComputingMode"+computingMode+"|对应的加班流程数据|key|"+key);

	  }

	  /**
	   * 根据出差、公出数据和加班归属 拆分出来需要计算加班的区段
	   * @param resourceid
	   * @param fromDate
	   * @param toDate
	   * @param dateFormatter
	   * @param kqTimesArrayComInfo
	   * @param overRulesDetailMap
	   * @param changeTypeMap
	   * @param lsCheckInfoMaps
	   * @param eventMap
	   */
	  public void getFlowDataMap(String resourceid, String fromDate, String toDate,
	      DateTimeFormatter dateFormatter,
	      KQTimesArrayComInfo kqTimesArrayComInfo,
	      Map<String, KQOvertimeRulesDetailEntity> overRulesDetailMap,
	      Map<String, Integer> changeTypeMap, Map<String, KQOvertimeCardBean> lsCheckInfoMaps,
	      Map<String, Object> eventMap) throws Exception{

	    KQOverTimeFlowBiz kqOverTimeFlowBiz = new KQOverTimeFlowBiz();

	    List<KqFlowSplitData> lsCheckInfos = Lists.newArrayList();
	    Map<String,String> result = getFlowData(resourceid, fromDate, dateFormatter,eventMap,lsCheckInfos,changeTypeMap,overRulesDetailMap);

	    //获取一下当天的上班时间
	    String firstworkTime = Util.null2String(result.get("firstworkTime"));
	    int pre_has_cut_point = Util.getIntValue(Util.null2String(result.get("pre_has_cut_point")));
	    String pre_cut_point = Util.null2String(result.get("pre_cut_point"));
	    int has_cut_point = Util.getIntValue(Util.null2String(result.get("has_cut_point")));
	    String cut_point = Util.null2String(result.get("cut_point"));
	    int before_startTime = Util.getIntValue(Util.null2String(result.get("before_startTime")));
	    int preChangeType = Util.getIntValue(Util.null2String(result.get("preChangeType")));
	    int changeType = Util.getIntValue(Util.null2String(result.get("changeType")));

	    LocalDate localbelongDate = LocalDate.parse(fromDate);
	    String splitDate = localbelongDate.format(dateFormatter);
	    LocalDate preLocalDate = localbelongDate.minusDays(1);
	    String preSplitDate = preLocalDate.format(dateFormatter);
	    String nextSplitDate = localbelongDate.plusDays(1).format(dateFormatter);

	    String preKey = resourceid+"_"+preSplitDate;
	    String key = resourceid+"_"+splitDate;
	    String nextkey = resourceid+"_"+nextSplitDate;

	    eventMap.put("key:"+key+"|lsCheckInfos", lsCheckInfos);
	    if(!lsCheckInfos.isEmpty()){
	    	KqFlowSplitData flowBean = (KqFlowSplitData) lsCheckInfos.get(0);
	      String signindate = "";
	      String signintime = "";
	      String signoutdate = "";
	      String signouttime = "";

	      if(flowBean != null){
	    	signindate = flowBean.getFromdate();
	        signintime = flowBean.getFromtime();
	        signoutdate = flowBean.getTodate();
	        signouttime = flowBean.getTotime();
	        if(lsCheckInfos.size() > 1){
	          Map<String, Object> lastSignMap = (Map<String, Object>) lsCheckInfos.get(lsCheckInfos.size()-1);
	          signoutdate = Util.null2String(lastSignMap.get("signoutdate"));
	          signouttime = Util.null2String(lastSignMap.get("signouttime"));
	        }
	      }
	      KQOvertimeCardBean kqOvertimeBean = new KQOvertimeCardBean();
	      kqOvertimeBean.setSigninDate(signindate);
	      kqOvertimeBean.setSigninTime(signintime);
	      kqOvertimeBean.setSignoutDate(signoutdate);
	      kqOvertimeBean.setSignoutTime(signouttime);
	      kqOvertimeBean.setBelongDate(splitDate);
	      eventMap.put("pre_has_cut_point", pre_has_cut_point);
	      eventMap.put("has_cut_point", has_cut_point);
	      if(pre_has_cut_point == 0){
	        //未设置打卡归属
	        if(preChangeType == 2){
	          eventMap.put("preChangeType", preChangeType);
	          //如果前一天是工作日
	          String pre_overtime_cut_point = "";
	          ShiftInfoBean pre_shiftInfoBean = KQDurationCalculatorUtil
	              .getWorkTime(resourceid, preSplitDate, false);
	          if(pre_shiftInfoBean != null){
	            List<int[]> workLongTimeIndex = pre_shiftInfoBean.getWorkLongTimeIndex();
	            List<int[]> real_workLongTimeIndex = Lists.newArrayList();
	            SplitBean splitBean = new SplitBean();
	            splitBean.setResourceId(resourceid);
	            kqOverTimeFlowBiz.get_real_workLongTimeIndex(workLongTimeIndex,real_workLongTimeIndex,pre_shiftInfoBean,kqTimesArrayComInfo,splitBean);

	            if(real_workLongTimeIndex != null && !real_workLongTimeIndex.isEmpty()){
	              pre_overtime_cut_point = kqTimesArrayComInfo.getTimesByArrayindex(real_workLongTimeIndex.get(0)[0]);
	            }
	            eventMap.put("pre_overtime_cut_point", pre_overtime_cut_point);
	            if(pre_overtime_cut_point.length() >= 0){
	            	calBiz.rePutCheckInfoMap(lsCheckInfoMaps, kqOvertimeBean, preKey, key, pre_overtime_cut_point, splitDate,eventMap);
	            }
	          }else{
	            String errorMsg = "前一天是工作日但是前一天的ShiftInfoBean班次获取不到信息";
	            eventMap.put("errorMsg", errorMsg);
	          }
	        }else {
	          eventMap.put("changeType", changeType);
	          if(changeType == 2){
	            eventMap.put("firstworkTime", firstworkTime);
	            if(has_cut_point == 1 && before_startTime > 0){
	              firstworkTime = kqTimesArrayComInfo.getTimesByArrayindex(kqTimesArrayComInfo.getArrayindexByTimes(firstworkTime)-before_startTime);
	            }
	            //如果前一天是非工作日，今天是工作日的话
	            calBiz.rePutCheckInfoMap(lsCheckInfoMaps, kqOvertimeBean, preKey, key, firstworkTime, splitDate,
	                eventMap);
	          }else{
	            //如果前一天是非工作日，今天是非工作日的话，那就是打卡获取的是啥就是啥
	            lsCheckInfoMaps.put(key, kqOvertimeBean);
	          }
	        }
	      }else{
	        String pre_splittime = "";
	        List<KqFlowSplitData> pre_lsCheckInfos = Lists.newArrayList();
	        getFlowData(resourceid, preSplitDate, dateFormatter, eventMap, pre_lsCheckInfos, changeTypeMap, overRulesDetailMap);
	        if(!pre_lsCheckInfos.isEmpty()){
	        	KqFlowSplitData preFlowBean = (KqFlowSplitData) pre_lsCheckInfos.get(0);
	          String pre_signindate = "";
	          String pre_signintime = "";
	          String pre_signoutdate = "";
	          String pre_signouttime = "";
	          if(preFlowBean != null){
	            pre_signindate = preFlowBean.getFromdate();
	            pre_signintime = preFlowBean.getFromtime();
	            pre_signoutdate = preFlowBean.getTodate();
	            pre_signouttime = preFlowBean.getTotime();
	            if(pre_signindate.length() > 0 && pre_signintime.length() > 0){
	              pre_splittime = pre_signindate+" "+pre_signintime;
	            }else if(pre_signoutdate.length() > 0 && pre_signouttime.length() > 0){
	              pre_splittime = pre_signoutdate+" "+pre_signouttime;
	            }
	          }
	        }
	        eventMap.put("pre_cut_point", pre_cut_point);
	        //设置了打卡归属 那么一天的打卡就可能被前一天给拆成两部分和后一天的打卡归属给拆分成两部分
	        calBiz.rePutCheckInfoCutPointMap(lsCheckInfoMaps, kqOvertimeBean, preKey, key, pre_cut_point, splitDate,
	            eventMap,cut_point,nextSplitDate,nextkey,has_cut_point,pre_splittime);
	      }
	    }
	  }

	  /**
	   * 获取流程数据
	   * @param resourceid
	   * @param belongDate
	   * @param dateFormatter
	   * @param eventMap
	   * @param lsCheckInfos
	   * @param changeTypeMap
	   * @param overRulesDetailMap
	   */
	  private Map<String, String> getFlowData(String resourceid, String belongDate,
	      DateTimeFormatter dateFormatter, Map<String, Object> eventMap,
	      List<KqFlowSplitData> lsCheckInfos, Map<String, Integer> changeTypeMap,
	      Map<String, KQOvertimeRulesDetailEntity> overRulesDetailMap) throws Exception{
	    Map<String,String> result = Maps.newHashMap();
	    String firstworkDate = belongDate;
	    String firstworkTime = "";
	    
	    KQWorkTime kqWorkTime = new KQWorkTime();
	    WorkTimeEntity workTime = kqWorkTime.getWorkTime(resourceid, belongDate);
	    if(workTime == null || workTime.getWorkMins() == 0) {
	    	firstworkTime = "00:00";
	    } else if(workTime.getKQType().equals("3")) {
	    	firstworkTime = StringUtil.vString(workTime.getSignStart());
	    } else {
	    	List<TimeScopeEntity> lsWorkTime = workTime.getWorkTime();
	    	for(TimeScopeEntity time : lsWorkTime) {
	    		firstworkTime = StringUtil.vString(time.getBeginTime());
	    		break;
	    	}
	    }

	    LocalDate localbelongDate = LocalDate.parse(belongDate);
	    String splitDate = localbelongDate.format(dateFormatter);
	    LocalDate preLocalDate = localbelongDate.minusDays(1);
	    String preSplitDate = preLocalDate.format(dateFormatter);

	    String change_key = splitDate+"_"+resourceid;
	    String preChange_key = preSplitDate+"_"+resourceid;
	    int changeType = Util.getIntValue(""+changeTypeMap.get(change_key),-1);
	    int preChangeType = Util.getIntValue(""+changeTypeMap.get(preChange_key),-1);
	    String changeType_key = splitDate+"_"+changeType;
	    String preChangeType_key = preSplitDate+"_"+preChangeType;

	    KQOvertimeRulesDetailEntity curKqOvertimeRulesDetailEntity = overRulesDetailMap.get(changeType_key);
	    KQOvertimeRulesDetailEntity preKqOvertimeRulesDetailEntity = overRulesDetailMap.get(preChangeType_key);

	    int pre_has_cut_point = 0;
	    String pre_cut_point = "";
	    if(preKqOvertimeRulesDetailEntity != null){
	      pre_has_cut_point = preKqOvertimeRulesDetailEntity.getHas_cut_point();
	      pre_cut_point = preKqOvertimeRulesDetailEntity.getCut_point();
	    }
	    int has_cut_point = 0;
	    String cut_point = "";
	    int before_startTime = -1;
	    if(curKqOvertimeRulesDetailEntity != null){
	      has_cut_point = curKqOvertimeRulesDetailEntity.getHas_cut_point();
	      cut_point = curKqOvertimeRulesDetailEntity.getCut_point();
	      before_startTime =curKqOvertimeRulesDetailEntity.getBefore_startTime();
	    }

	    result.put("pre_has_cut_point", ""+pre_has_cut_point);
	    result.put("pre_cut_point", pre_cut_point);
	    result.put("has_cut_point", ""+has_cut_point);
	    result.put("cut_point", cut_point);
	    result.put("before_startTime", ""+before_startTime);
	    result.put("preChangeType", ""+preChangeType);
	    result.put("changeType", ""+changeType);

	    lsCheckInfos.addAll(getFlowInfo(resourceid,splitDate,eventMap));
	    
	    if(firstworkDate.length() > 0 && firstworkTime.length() > 0){
	      result.put("firstworkDate", firstworkDate);
	      result.put("firstworkTime", firstworkTime);
	    }
	    return result;
	  }
	  
	  /**
	   * 获取出差、公出数据
	   * @param userId
	   * @param kqDate
	   * @param eventMap
	   * @return 
	   */
	  private List<KqFlowSplitData> getFlowInfo(String userId, String kqDate, Map<String, Object> eventMap) {
	    List<KqFlowSplitData> list = Lists.newArrayList();
	    RecordSet rs = new RecordSet();
	    StringBuffer sql = new StringBuffer().append("select t.* from (")
	    		.append(" select t.resourceid, t.fromdate, t.fromtime, t.todate, t.totime, t.belongDate from kq_flow_split_evection t where t.resourceid = ? and t.belongDate = ?")
	    	    .append(" UNION ALL")
	    	    .append(" select t.resourceid, t.fromdate, t.fromtime, t.todate, t.totime, t.belongDate from kq_flow_split_out t where t.resourceid = ? and t.belongDate = ?")
	    		.append(") t order by t.resourceid, t.fromdate, t.fromtime");
        rs.executeQuery(sql.toString(), userId, kqDate, userId, kqDate);
        String work_card_sql = "sql:"+sql.toString()+"|resourceid|"+userId+"|kqDate|"+kqDate;

        eventMap.put("出差、公出sql|work_card_sql", work_card_sql);
        eventMap.put("出差、公出sql结果|work_card_sql_getCounts", rs.getCounts());
        while (rs.next()) {
          KqFlowSplitData bean = new KqFlowSplitData();
          bean.setResourceid(StringUtil.vString(rs.getString("resourceid")));
          bean.setBelongdate(StringUtil.vString(rs.getString("belongDate")));
          bean.setFromdate(StringUtil.vString(rs.getString("fromdate")));
          bean.setFromtime(StringUtil.vString(rs.getString("fromtime")));
          bean.setTodate(StringUtil.vString(rs.getString("todate")));
          bean.setTotime(StringUtil.vString(rs.getString("totime")));
          list.add(bean);
        }
	    return list;
	  }
	  
	  class KqFlowSplitData {
		  	private String resourceid;
		  	private String belongdate;
			private String fromdate;
			private String fromtime;
			private String todate;
			private String totime;
			
			public String getResourceid() {
				return resourceid;
			}
			public void setResourceid(String resourceid) {
				this.resourceid = resourceid;
			}
			public String getBelongdate() {
				return belongdate;
			}
			public void setBelongdate(String belongdate) {
				this.belongdate = belongdate;
			}
			public String getKey() {
				return resourceid + "_"+ belongdate;
			}
			public String getFromdate() {
				return fromdate;
			}
			public void setFromdate(String fromdate) {
				this.fromdate = fromdate;
			}
			public String getFromtime() {
				return fromtime;
			}
			public void setFromtime(String fromtime) {
				this.fromtime = fromtime;
			}
			public String getTodate() {
				return todate;
			}
			public void setTodate(String todate) {
				this.todate = todate;
			}
			public String getTotime() {
				return totime;
			}
			public void setTotime(String totime) {
				this.totime = totime;
			}
	  }

	  /**
	   * 加班和出差、公出均统计 取交集 生成加班明细
	   * @param params
	   * @param user
	   */
	  public String buildTableString4CustomOvertimeFlow(Map<String, Object> params, User user) {
	    String backfields = " * ";
	    String fromDate = Util.null2String(params.get("fromDate"));
	    String toDate = Util.null2String(params.get("toDate"));
	    String typeselect =Util.null2String(params.get("typeselect"));
	    String belongdateWhere = "";
	    if(typeselect.length()==0){
	      typeselect = "3";
	    }
	    if(!typeselect.equals("") && !typeselect.equals("0")&& !typeselect.equals("6")){
	      if(typeselect.equals("1")){
	        fromDate = TimeUtil.getCurrentDateString();
	        toDate = TimeUtil.getCurrentDateString();
	      }else{
	        fromDate = TimeUtil.getDateByOption(typeselect,"0");
	        toDate = TimeUtil.getDateByOption(typeselect,"1");
	      }
	    }

	    if (fromDate.length() > 0 && toDate.length() > 0){
	      belongdateWhere += " and ( belongdate between '"+fromDate+"' and '"+toDate+"' or belongdate between '"+fromDate+"' and '"+toDate+"' "
	          + " or '"+fromDate+"' between belongdate and belongdate or '"+toDate+"' between belongdate and belongdate) ";
	    }
	    String overtimeTable = " select requestid,resourceid,fromdate,fromtime,todate,totime,fromdatedb,fromtimedb,todatedb,totimedb,computingmode,paidLeaveEnable,expiringdate,duration_min,durationrule from kq_flow_overtime where computingmode = "+computingMode+"  "+(belongdateWhere.length() == 0 ? "" :belongdateWhere);

	    String fromSql  = " (select b.lastname,b.loginid,b.subcompanyid1,b.departmentid,b.jobtitle,b.managerid,b.managerstr,a.* from ("+overtimeTable+") a left join hrmresource b on a.resourceid = b.id) f ";
	    String sqlWhere = " 1=1 ";
	    String tableString = "";
	    String tabletype="none";
	    String orderby = " computingmode ";

	    String tabkey = Util.null2String(params.get("tabKey"));
	    int kqtype = Util.getIntValue(Util.null2String(params.get("kqtype")),-1);
	    String resourceId = Util.null2String(params.get("resourceId"));
	    String subCompanyId = Util.null2String(params.get("subCompanyId"));
	    String departmentId = Util.null2String(params.get("departmentId"));

	    //来自我的考勤,resourceid为空时，默认取当前用户的id
	    String source =Util.null2String(params.get("source"));
	    if(source.equals("isMyKq")){
	      if(resourceId.equals("")){
	        resourceId = user.getUID()+"";
	      }
	    }

	    String keyWord = Util.null2String(params.get("keyWord"));
	    String requestId =Util.null2String(params.get("requestId"));
	    String viewScope = Util.null2String(params.get("viewScope"));
	    String allLevel = Util.null2String(params.get("allLevel"));
	    String isNoAccount = Util.null2String(params.get("isNoAccount"));

	    String isMyKQ = Util.null2String(params.get("isMyKQ"));

	    boolean isFinished = false;
	    if("1".equalsIgnoreCase(tabkey)){
	      //已归档
	      isFinished = true;
	    }

	    if (keyWord.length() > 0){
	      sqlWhere += " and lastname = "+keyWord;
	    }

	    if(resourceId.length() > 0){
	      sqlWhere += " and resourceId in("+resourceId+")";
	    }

	    if(subCompanyId.length()>0){
	      sqlWhere +=" and subcompanyid1 in("+subCompanyId+") ";
	    }

	    if(departmentId.length()>0){
	      sqlWhere +=" and departmentid in("+departmentId+") ";
	    }

	    if(viewScope.equals("4")){//我的下属
	      if(allLevel.equals("1")){//所有下属
	        sqlWhere+=" and managerstr like '%,"+user.getUID()+",%'";
	      }else{
	        sqlWhere+=" and managerid="+user.getUID();//直接下属
	      }
	    }
	    if (!"1".equals(isNoAccount)) {
	      sqlWhere += " and loginid is not null "+(new RecordSet().getDBType().equals("oracle")?"":" and loginid<>'' ");
	    }

	    String rightSql = new KQReportBiz().getReportRight("1",""+user.getUID(),"aa");
	    String hrmSql = " select id from hrmresource aa where 1=1 "+rightSql;
	    if (null != rightSql && rightSql.length()>0) {
	      sqlWhere += " and resourceId in("+hrmSql+")";
	    }

	    new KQLog().info("KQ_OvertimeTotal_Detail_FlowInCard>>>>>>backfields:"+backfields+">>>>>fromSql:"+fromSql +">>>>>sqlWhere:"+sqlWhere);
	    String otherPram = user.getLanguage()+"";
	    String timePram = "column:fromtime+column:todate+column:totime";
	    String fromTimePram = kqtype+"+0+"+user.getLanguage()+"++column:durationrule";
	    String toTimePram = kqtype+"+1+"+user.getLanguage()+"++column:durationrule";

	    String pageUid = "dfb4c634-5769-432f-a65e-787b99ab9872";//UUID.randomUUID()

	    tableString =" <table pageUid=\""+pageUid+"\" tabletype=\""+tabletype+"\" pagesize=\"10\" >"+
	        "	   <sql backfields=\""+backfields+"\" sqlform=\""+fromSql+"\" sqlwhere=\""+Util.toHtmlForSplitPage(sqlWhere)+"\"  sqlorderby=\""+orderby+"\"  sqlprimarykey=\"a.id\" sqlsortway=\"desc\" sqlisdistinct=\"false\"/>"+
	        "			<head>";
	    tableString += "				<col width=\"10%\"  text=\""+ SystemEnv.getHtmlLabelName(413,user.getLanguage()) +"\" column=\"lastname\" orderkey=\"lastname\" />";
	    tableString += "				<col width=\"10%\"  text=\""+ SystemEnv.getHtmlLabelName(714,user.getLanguage()) +"\" column=\"resourceId\" orderkey=\"resourceId\" transmethod=\"weaver.hrm.resource.ResourceComInfo.getWorkcode\" />";
	    tableString += "				<col width=\"10%\"  text=\""+ SystemEnv.getHtmlLabelName(124,user.getLanguage()) +"\" column=\"departmentId\" orderkey=\"departmentId\" transmethod=\"weaver.hrm.company.DepartmentComInfo.getDepartmentname\" />";
	    tableString += "				<col width=\"10%\"  text=\""+ SystemEnv.getHtmlLabelName(740,user.getLanguage()) +"\" column=\"fromdatedb\" orderkey=\"fromdatedb\"  transmethod=\"com.engine.kq.util.TransMethod.getRequestLink\" otherpara=\"column:requestid\"  />";
	    tableString += "				<col width=\"10%\"  text=\""+ SystemEnv.getHtmlLabelName(742,user.getLanguage()) +"\" column=\"fromtimedb\" orderkey=\"fromtimedb\" transmethod=\"com.engine.kq.util.TransMethod.getFlowTimeByUnit\" otherpara=\""+fromTimePram+"\"  />";
	    tableString += "				<col width=\"10%\"  text=\""+ SystemEnv.getHtmlLabelName(741,user.getLanguage()) +"\" column=\"todatedb\" orderkey=\"todatedb\" />";
	    tableString += "				<col width=\"10%\"  text=\""+ SystemEnv.getHtmlLabelName(743,user.getLanguage()) +"\" column=\"totimedb\" orderkey=\"totimedb\"  transmethod=\"com.engine.kq.util.TransMethod.getFlowTimeByUnit\" otherpara=\""+toTimePram+"\"  />";
	    tableString += "				<col width=\"20%\"  text=\""+ SystemEnv.getHtmlLabelName(536756,user.getLanguage()) +"\" column=\"fromdate\" orderkey=\"fromdate\"  transmethod=\"com.engine.kq.util.TransMethod.getOvertimeCard\" otherpara=\""+timePram+"\"  />";
	    tableString += "				<col width=\"10%\"  text=\""+ SystemEnv.getHtmlLabelName(509604,user.getLanguage()) +"\" column=\"duration_min\" orderkey=\"duration_min\" transmethod=\"com.engine.kq.util.TransMethod.getDuration_minByUnit\" />";
	    tableString += "				<col width=\"10%\"  text=\""+ SystemEnv.getHtmlLabelName(125804,user.getLanguage()) +"\" column=\"paidLeaveEnable\" orderkey=\"paidLeaveEnable\" transmethod=\"com.engine.kq.util.TransMethod.getPaidLeaveEnable\" otherpara=\""+otherPram+"\"  />";
	    tableString +="			</head>"+
	        " </table>";
	    String sessionkey = pageUid + "_" + Util.getEncrypt(Util.getRandom());
	    Util_TableMap.setVal(sessionkey, tableString);
	    return sessionkey;
	  }

}
