package com.engine.kq.biz.chain.shiftinfo;

import com.engine.kq.biz.KQOvertimeRulesBiz;
import com.engine.kq.biz.KQTimesArrayComInfo;
import com.engine.kq.util.KQDurationCalculatorUtil;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.map.HashedMap;
import weaver.general.Util;

/**
 * 工作日 加班用的计算类
 */
public class OverTimeDurationIndex extends DurationIndex {

  public OverTimeDurationIndex(String name,KQTimesArrayComInfo arrayComInfo,Map<String,Object> dateWorkTimeMap){
    super(name,arrayComInfo,dateWorkTimeMap);
  }

  @Override
  public void handleDuration(ShiftInfoBean shiftInfoBean) {

    String minimumUnit = shiftInfoBean.getMinimumUnit();

    int[] initArrays = arrayComInfo.getInitArr();
    Map<String,Integer> cntMap = handleArray(initArrays,shiftInfoBean);

    if(!cntMap.isEmpty()){
      handleDurationMins(shiftInfoBean,cntMap,minimumUnit);
    }
  }

  /**
   * 根据数组和下标得到分钟数
   * @param initArrays
   * @param shiftInfoBean
   * @return
   */
  private Map<String,Integer> handleArray(int[] initArrays, ShiftInfoBean shiftInfoBean) {
    String splitFromTime = shiftInfoBean.getSplitFromTime();
    String splitToTime = shiftInfoBean.getSplitToTime();
    int flowSplitStartIndex = arrayComInfo.getArrayindexByTimes(splitFromTime);
    int flowSplitEndIndex = arrayComInfo.getArrayindexByTimes(splitToTime);
    String splitDate = shiftInfoBean.getSplitDate();
    String preSplitDate = shiftInfoBean.getPreSplitDate();

    int overMins = 0;
    Map<String,Integer> cntMap = new HashedMap();

//    1、先把流程填充到数组里
    Arrays.fill(initArrays, flowSplitStartIndex, flowSplitEndIndex, 0);
    kqLog.info("OverTimeDurationIndex:flowSplitStartIndex:"+flowSplitStartIndex+":flowSplitEndIndex:"+flowSplitEndIndex+":cnt:"+arrayComInfo.getCnt(initArrays, 0, 1440, 0));

    int finalEndTime = fillNonPreWorkIndex(preSplitDate,initArrays,shiftInfoBean);

//    2、再把工作时段填充到数组里
    fillNonWorkIndex(splitDate,initArrays,shiftInfoBean,finalEndTime);

    // 3、需要排除休息时段（前一天和当天的），所以还需要把休息时段也填充到数组里
    fillNonPreRestIndex(splitDate,initArrays,shiftInfoBean);

    fillNonRestIndex(splitDate,initArrays,shiftInfoBean);

    //在一整天的数组里，先把流程赋值，再用工作时段填充覆盖掉流程，那么未被覆盖的流程时段就是在非工作时段里的
    overMins = arrayComInfo.getCnt(initArrays, 0, 1440, 0);

    cntMap.put("overMins", overMins);
    shiftInfoBean.setD_Mins(Util.getDoubleValue(""+overMins));

    return cntMap;
  }

  /**
   * 排除掉加班里的休息时段
   * @param splitDate
   * @param initArrays
   * @param shiftInfoBean
   */
  private void fillNonRestIndex(String splitDate, int[] initArrays, ShiftInfoBean shiftInfoBean) {
    List<int[]> restIndex = shiftInfoBean.getRestIndex();
    for(int i = 0 ; i < restIndex.size() ; i++){
      int[] restIndexTmp = restIndex.get(i);
      int reststartIndex = restIndexTmp[0];
      int restendIndex = restIndexTmp[1];
      Arrays.fill(initArrays, reststartIndex, restendIndex, -1);
    }
  }

  /**
   * 排除掉前一天加班里的休息时段
   * @param preSplitDate
   * @param initArrays
   * @param shiftInfoBean
   */
  private void fillNonPreRestIndex(String preSplitDate, int[] initArrays, ShiftInfoBean shiftInfoBean) {
    List<int[]> preRestIndex = shiftInfoBean.getPreRestIndex();
    for(int i = 0 ; i < preRestIndex.size() ; i++){
      int[] preRestIndexTmp = preRestIndex.get(i);
      int reststartIndex = preRestIndexTmp[0];
      int restendIndex = preRestIndexTmp[1];
      Arrays.fill(initArrays, reststartIndex, restendIndex, -1);
    }
  }

  /**
   * 根据加班规则重新填充 前一天的加班时长数据
   * @param preSplitDate
   * @param initArrays
   * @param shiftInfoBean
   */
  private int fillNonPreWorkIndex(String preSplitDate, int[] initArrays, ShiftInfoBean shiftInfoBean) {
    int startTime = 0;
    //记录前一天班次跨到今天的最晚时间
    int finalEndTime = 0;
    //这个是跨到今天的工作时段
    List<int[]> preWorkIndex = shiftInfoBean.getPreWorkIndex();
    if(!preWorkIndex.isEmpty()){
      String resourceid = Util.null2String(dateWorkTimeMap.get("resourceid"));
      startTime = KQOvertimeRulesBiz.getStartTime(resourceid,preSplitDate);
      startTime = startTime < 0 ? 0 : startTime;

      //取跨到今天的最后一次下班时间
      int[] workIndexTmp = preWorkIndex.get(preWorkIndex.size()-1);
      //如果设置了最后一次下班后才能加班
      if(startTime > -1){
        if(workIndexTmp != null){
          //workIndexTmp[1]最晚下班时间+startTime
          finalEndTime = workIndexTmp[1]+startTime;
          Arrays.fill(initArrays, 0, finalEndTime, 2);
        }
      }else{
        kqLog.info("OverTimeDurationIndex:fillNonPreWorkIndex:加班起算时间未填写:resourceid:"+resourceid+":preSplitDate:"+preSplitDate+":startTime:"+startTime);
      }
    }
    return finalEndTime;
  }

  /**
   * 根据加班规则重新填充 当天的加班时长数据
   * @param splitDate
   * @param initArrays
   * @param shiftInfoBean
   * @param finalEndTime
   */
  private void fillNonWorkIndex(String splitDate,int[] initArrays,ShiftInfoBean shiftInfoBean,int finalEndTime) {
    int startTime = 0;
    //工作时段的最晚时间
    int finalStartTime = 0;
    List<int[]> workIndex = shiftInfoBean.getWorkIndex();
    List<int[]> workAcrossIndex = shiftInfoBean.getWorkAcrossIndex();
    if(!workIndex.isEmpty()){
      String resourceid = Util.null2String(dateWorkTimeMap.get("resourceid"));
      //加班起算时间是必填项
      startTime = KQOvertimeRulesBiz.getStartTime(resourceid,splitDate);
      startTime = startTime < 0 ? 0 : startTime;
      //如果设置了最后一次下班后才能加班
      if(startTime > -1){
        //最早的上班时间
        int[] workIndexTmp0 = workIndex.get(0);

        //不跨天时段最后一次下班时间
        int[] workIndexTmp = workIndex.get(workIndex.size()-1);
        //跨天时段最后一次下班时间
        int[] workAcrossIndexTmp = workAcrossIndex.get(workAcrossIndex.size()-1);
        //如果这两个值相等，表示不跨天
        if(workIndexTmp[1] == workAcrossIndexTmp[1]){
          finalStartTime = workIndexTmp[1] + startTime;
          if(finalStartTime > 1439){
            //最后一次下班后多久允许加班在第二天
            finalStartTime = 1439;
          }
          Arrays.fill(initArrays, workIndexTmp0[0], finalStartTime, 1);

          kqLog.info("不跨天OverTimeDurationIndex:fillNonWorkIndex:workIndexTmp0[0]:"+workIndexTmp0[0]+":finalStartTime:"+finalStartTime+":startTime:"+startTime+":cnt:"+arrayComInfo.getCnt(initArrays, 0, 1440, 1));

        }else{
          //如果不一致，表示跨天了，最后一次下班时间不在今天在第二天
          //这种情况下，表示今天从最早的上班时间到23:59这段时间都不算加班
          Arrays.fill(initArrays, workIndexTmp0[0], workIndexTmp[1], 1);
          kqLog.info("跨天OverTimeDurationIndex:fillNonWorkIndex:workIndexTmp0[0]:"+workIndexTmp0[0]+":workIndexTmp[1]:"+workIndexTmp[1]+":startTime:"+startTime+":cnt:"+arrayComInfo.getCnt(initArrays, 0, 1440, 1));
        }
      }else{
        kqLog.info("OverTimeDurationIndex:fillNonWorkIndex:加班起算时间未填写:resourceid:"+resourceid+":splitDate:"+splitDate+":startTime:"+startTime);
      }
    }
  }

  /**
   * 根据最终的index生成分钟这时长
   * @param shiftInfoBean
   * @param cntMap
   * @param minimumUnit
   */
  private void handleDurationMins(ShiftInfoBean shiftInfoBean,Map<String,Integer> cntMap,String minimumUnit){
    //计算规则 1-按天请假 2-按半天请假 3-按小时请假 4-按整天请假
    //按照天和小时的可以在这里计算，半天的和整天的单独处理
    if("1".equalsIgnoreCase(minimumUnit)){
      minimumUnit1(shiftInfoBean,cntMap);
    }else if("3".equalsIgnoreCase(minimumUnit)){
      minimumUnit3(shiftInfoBean);
    }
  }

  /**
   * 获取加班单位的工作日日折算时长
   * @param shiftInfoBean
   * @param cntMap
   * @return
   */
  private void minimumUnit1(ShiftInfoBean shiftInfoBean, Map<String,Integer> cntMap) {
    int workmins = shiftInfoBean.getWorkmins();
    //分别得到前一个工作时段的小时数和当前时段的分钟数数
    int overMins = cntMap.get("overMins") != null ? cntMap.get("overMins") : 0;

    double curDays = 0.0;
    double D_Mins = 0.0;

    if(workmins > 0){
      curDays = overMins/(workmins*1.0);
      curDays = curDays > 0.0 ? curDays : 0.0;
      D_Mins = Util.getDoubleValue(""+overMins);
    }
    shiftInfoBean.setDuration(KQDurationCalculatorUtil.getDurationRound(""+(curDays)));
    shiftInfoBean.setD_Mins(D_Mins);
  }

  /**
   * 按小时请假
   * @param shiftInfoBean
   * @return
   */
  private double minimumUnit3(ShiftInfoBean shiftInfoBean) {
    double D_Mins = shiftInfoBean.getD_Mins();
    double hours = D_Mins/60.0;
    hours = hours > 0.0 ? hours : 0.0;
    shiftInfoBean.setDuration(KQDurationCalculatorUtil.getDurationRound(""+(hours)));
    return hours;
  }
}
