package com.xhkjedu.sexam.service.report;

import com.alibaba.fastjson.JSON;
import com.xhkjedu.sexam.config.ConfigKey;
import com.xhkjedu.sexam.mapper.exam.EBaseMapper;
import com.xhkjedu.sexam.mapper.exam.EClassMapper;
import com.xhkjedu.sexam.mapper.paperstudent.EPaperStudentMapper;
import com.xhkjedu.sexam.mapper.report.ERbaseMapper;
import com.xhkjedu.sexam.mapper.report.EReportGenerateMapper;
import com.xhkjedu.sexam.mapper.report.ERrankMapper;
import com.xhkjedu.sexam.mapper.report.ERsubjectMapper;
import com.xhkjedu.sexam.mapper.reportclass.ERclassActionMapper;
import com.xhkjedu.sexam.mapper.reportclass.ERclassMapper;
import com.xhkjedu.sexam.mapper.reportclass.ERclassRankMapper;
import com.xhkjedu.sexam.mapper.reportstu.ERstudentActionMapper;
import com.xhkjedu.sexam.mapper.reportstu.ERstudentMapper;
import com.xhkjedu.sexam.mapper.system.UserMapper;
import com.xhkjedu.sexam.model.exam.EBase;
import com.xhkjedu.sexam.model.exam.EClass;
import com.xhkjedu.sexam.model.report.ERbase;
import com.xhkjedu.sexam.model.report.ERrank;
import com.xhkjedu.sexam.model.report.ERsubject;
import com.xhkjedu.sexam.model.reportclass.ERclass;
import com.xhkjedu.sexam.model.reportclass.ERclassAction;
import com.xhkjedu.sexam.model.reportclass.ERclassQuestion;
import com.xhkjedu.sexam.model.reportclass.ERclassRank;
import com.xhkjedu.sexam.model.reportstu.ERstudent;
import com.xhkjedu.sexam.model.reportstu.ERstudentAction;
import com.xhkjedu.sexam.utils.ConvertUtil;
import com.xhkjedu.sexam.utils.ExamUtil;
import com.xhkjedu.sexam.vo.report.EClassActionVo;
import com.xhkjedu.sexam.vo.report.ERPaperVo;
import com.xhkjedu.utils.N_Utils;
import com.xhkjedu.vo.system.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * @author ywx
 * @classname EReportGenerateService
 * @description 考试报告生成
 * 人数： 指定范围下考生人数
 * 占比： 指定范围下考生人数/全部学生*100%
 * @date 2022/8/8 10:04
 **/
@Service
@Slf4j
public class EReportGenerateService {
    @Resource
    private EReportGenerateMapper eReportGenerateMapper;
    @Resource
    private EClassMapper eClassMapper;
    @Resource
    private EPaperStudentMapper ePaperStudentMapper;
    @Resource
    private EBaseMapper eBaseMapper;
    @Resource
    private ERbaseMapper eRbaseMapper;
    @Resource
    private ERstudentMapper eRstudentMapper;
    @Resource
    private ERsubjectMapper eRsubjectMapper;
    @Resource
    private ERclassMapper eRclassMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private ERrankMapper eRrankMapper;
    @Resource
    private ERclassRankMapper eRclassRankMapper;
    @Resource
    private ERclassActionMapper eRclassActionMapper;
    @Resource
    private ERstudentActionMapper eRstudentActionMapper;
    @Resource
    private ConvertUtil convertUtil;
    @Resource
    private EReportGenerateQuestionService eReportGenerateQuestionService;

    //生成考试报告
    //基本原则：最低分均不包括0分。班次、校次、四率一平均根据参数计算；
    //分数等级统计、分数分段统计、临界生对比（0分全部参与计算）
    //优秀、学困生对比（根据报告设置参数计算）
    @Transactional(rollbackFor = Exception.class)
    public void generateExamReport(Integer examid, Integer createid) throws Exception {

        //生成前先删除以前的考试报告
        eReportGenerateMapper.deleteExamReport(examid);
        //学生上次考试排名及目标
        List<ERstudent> stuRankGoals = eReportGenerateMapper.listStuRankAndGoal(examid);

        List<Map> classes = eClassMapper.listByExamId(examid);
        EBase base = eBaseMapper.selectByPrimaryKey(examid);
        Integer exammode = base.getExammode();
        List<Map> subjects = eReportGenerateMapper.listSubject(examid, exammode);
        if(N_Utils.isListEmpty(subjects)) throw new Exception("没有结束的科目");
        List<ERPaperVo> papers = new ArrayList<>();
        Map<String, String> subjectMap = new HashMap<>();
        Map<String, ERPaperVo> paperMap = new HashMap<>();
        List<Integer> epids = new ArrayList<>();
        for (Map subject : subjects) {
            String subjectid = subject.get("subjectid").toString();
            String subjectname = subject.get("subjectname").toString();
            ERPaperVo p = new ERPaperVo();
            p.setSubjectid(subjectid);
            p.setPscore((Double) subject.get("pscore"));
            papers.add(p);
            subjectMap.put(subjectid, subjectname);
            paperMap.put(subjectid, p);
            epids.add((Integer) subject.get("epid"));
        }
        int classnum = classes.size();
        int stunum = classes.stream().mapToInt(m -> (int) m.get("classnum")).sum();
        int subjectnum = subjects.size();

        String subjectid;
        String subjectname;

        List<ERstudent> schoolStudents = new ArrayList<>();//学校学生成绩
        List<ERstudent> schoolSubjectStudents = new ArrayList<>();//学校科目学生成绩
        List<ERstudent> classStudents = new ArrayList<>();//班级学生成绩
        List<ERstudent> classSubjectStudents = new ArrayList<>();//班级科目学生成绩
        Map<String, Integer> schoolStuRank = new HashMap<>();//学校学生分数排名
        Map<String, Integer> schoolSubStuRank = new HashMap<>();//学校科目学生分数排名
        Map<String, Integer> classStuRank = new HashMap<>();//班级学生分数排名
        Map<String, Integer> classSubStuRank = new HashMap<>();//班级科目学生分数排名
        Integer stuzero = base.getStuzero();
        List<ERstudent> students = ePaperStudentMapper.listByExamId(examid, epids);
        int sknum = students.stream().filter(l -> l.getSstate() == 2).map(l -> l.getStudentid()).distinct().collect(Collectors.toList()).size();
        Map<Integer, List<ERstudent>> schoolCollect = students.stream().collect(Collectors.groupingBy(s -> s.getStudentid()));
        for (Map.Entry<Integer, List<ERstudent>> entry : schoolCollect.entrySet()) {
            Integer studentid = entry.getKey();
            ERstudent cs = new ERstudent();
            List<ERstudent> list = entry.getValue();
            cs.setClassid(list.get(0).getClassid());
            cs.setStudentid(studentid);
            cs.setScore(list.stream().mapToDouble(s -> s.getScore()).sum());
            cs.setSstate(list.stream().max(Comparator.comparing(ERstudent::getSstate)).get().getSstate());
            schoolStudents.add(cs);
        }
        Map<Integer, List<ERstudent>> cCollect = students.stream().collect(Collectors.groupingBy(s -> s.getClassid()));
        for (Map.Entry<Integer, List<ERstudent>> entry : cCollect.entrySet()) {
            Integer classid = entry.getKey();
            subjectid = "zf";
            subjectname = "总分";
            List<ERstudent> studentList = entry.getValue();

            Map<Integer, List<ERstudent>> sCollect = studentList.stream().collect(Collectors.groupingBy(s -> s.getStudentid()));
            List<ERstudent> rstudents = new ArrayList<>();
            for (Map.Entry<Integer, List<ERstudent>> csEntry : sCollect.entrySet()) {
                ERstudent cs = new ERstudent();
                cs.setExamid(examid);
                cs.setClassid(classid);
                cs.setStudentid(csEntry.getKey());
                cs.setSubjectid(subjectid);
                cs.setSubjectname(subjectname);
                cs.setScore(csEntry.getValue().stream().mapToDouble(s -> s.getScore()).sum());
                rstudents.add(cs);
            }
            setRank(rstudents, classStuRank, 3);//班级学生分数排名
            classStudents.addAll(rstudents);
            Map<String, List<ERstudent>> subCollect = studentList.stream().collect(Collectors.groupingBy(s -> s.getSubjectid()));
            for (Map.Entry<String, List<ERstudent>> ssEntry : subCollect.entrySet()) {
                subjectid = ssEntry.getKey();
                subjectname = subjectMap.get(subjectid);
                studentList = ssEntry.getValue();
                rstudents = new ArrayList<>();
                for (ERstudent cs : studentList) {
                    cs.setSubjectname(subjectname);
                    rstudents.add(cs);
                }
                setRank(rstudents, classSubStuRank, 4);//班级科目学生分数排名
                classSubjectStudents.addAll(rstudents);
            }
        }

        List<ERstudent> schoolStudents2;//参与统计学生列表
        if (stuzero.equals(0)) {//0分学生不参与统计
            schoolStudents2 = schoolStudents.stream().filter(s -> s.getScore() > 0).collect(Collectors.toList());
        } else {
            schoolStudents2 = schoolStudents;
        }
        DoubleSummaryStatistics schoolStatistics = schoolStudents2.stream().filter(s -> s.getScore() > 0).mapToDouble(s -> s.getScore()).summaryStatistics();
        double schoolStatisticsMax = N_Utils.handleInfinity(schoolStatistics.getMax());
        double schoolStatisticsAverage = N_Utils.formatDouble(schoolStatistics.getAverage(), 2);
        //最低分均不包括0分
        double schoolStatisticsMin = N_Utils.handleInfinity(schoolStudents.stream().filter(s -> s.getScore() > 0).mapToDouble(s -> s.getScore()).summaryStatistics().getMin());
        if (N_Utils.isListEmpty(students)) {
            schoolStatisticsMax = 0;
            schoolStatisticsMin = 0;
            schoolStatisticsAverage = 0;
        }

        ERbase rbase = new ERbase();
        rbase.setExamid(examid);
        rbase.setClassnum(classnum);
        rbase.setStunum(stunum);
        rbase.setMissnum(stunum - sknum);//所有科目缺考才计算（缺考人数=计划人数-实考人数）
        rbase.setSubjectnum(subjectnum);
        rbase.setMaxscore(schoolStatisticsMax);
        rbase.setAvgscore(schoolStatisticsAverage);
        rbase.setMixscore(schoolStatisticsMin);
        eRbaseMapper.insertSelective(rbase);
        Map<String, List<ERstudent>> subCollect = students.stream().collect(Collectors.groupingBy(s -> s.getSubjectid()));
        List<ERsubject> subjectList = new ArrayList<>();//考试报告科目情况
        List<ERclass> classList = new ArrayList<>();//考试报告班级情况
        setSubject(examid, stunum, "zf", "总分", subjectList, classList, schoolStudents
                , papers.stream().mapToDouble(p -> p.getPscore()).sum(), stuzero);
        for (Map.Entry<String, List<ERstudent>> ssEntry : subCollect.entrySet()) {
            subjectid = ssEntry.getKey();
            subjectname = subjectMap.get(subjectid);
            List<ERstudent> list = ssEntry.getValue();
            Map<Integer, List<ERstudent>> sCollect = list.stream().collect(Collectors.groupingBy(s -> s.getStudentid()));
            List<ERstudent> rstudents = new ArrayList<>();
            for (Map.Entry<Integer, List<ERstudent>> csEntry : sCollect.entrySet()) {
                ERstudent cs = new ERstudent();
                cs.setClassid(0);
                cs.setStudentid(csEntry.getKey());
                cs.setSubjectid(subjectid);
                cs.setSubjectname(subjectname);
                cs.setScore(csEntry.getValue().stream().mapToDouble(s -> s.getScore()).sum());
                cs.setSstate(csEntry.getValue().get(0).getSstate());
                rstudents.add(cs);
            }
            setRank(rstudents, schoolSubStuRank, 2);//学校科目学生分数排名
            schoolSubjectStudents.addAll(rstudents);
            ERPaperVo rp = paperMap.get(subjectid);
            Double allscore = rp.getPscore();//满分
            setSubject(examid, stunum, subjectid, subjectname, subjectList, classList, list, allscore, stuzero);
        }

        setClassAvgRank(classList);//班级科目平均分排名
        if (N_Utils.isListNotEmpty(classList)) eRclassMapper.insertList(classList);
        if (N_Utils.isListNotEmpty(subjectList)) eRsubjectMapper.insertList(subjectList);
        setRank(schoolStudents, schoolStuRank, 1);//学校学生分数排名

        Map<String, ERclass> rclassMap = classList.stream().collect(Collectors.toMap(c -> (c.getClassid() + "_" + c.getSubjectid()), c -> c));
        Map<String, Double> bzcMap = subjectList.stream().collect(Collectors.toMap(ERsubject::getSubjectid, ERsubject::getBzc));
        for (ERstudent cs : classStudents) {
            Integer studentid = cs.getStudentid();
            cs.setClassrank(classStuRank.get(cs.getClassid() + "_" + studentid));
            ERclass rclass = rclassMap.get(cs.getClassid() + "_" + cs.getSubjectid());
            cs.setClassmaxscore(rclass.getClassmaxscore());
            cs.setClassavgscore(rclass.getClassavgscore());
            Integer schoolrank = schoolStuRank.get(studentid.toString());
            cs.setSchoolrank(schoolrank);
            cs.setSchoolmaxscore(rclass.getSchoolmaxscore());
            cs.setSchoolavgscore(rclass.getSchoolavgscore());
            setStuGoal(stuRankGoals, cs, schoolrank);//设置学生目标
            Double bzc = bzcMap.get(cs.getSubjectid());
            cs.setBzscore(ExamUtil.standardScore(cs.getScore(), cs.getSchoolavgscore(), bzc));//学生标准分
        }
        if (N_Utils.isListNotEmpty(classStudents)) eRstudentMapper.insertList(classStudents);
        for (ERstudent cs : classSubjectStudents) {
            Integer studentid = cs.getStudentid();
            Integer classid = cs.getClassid();
            subjectid = cs.getSubjectid();
            cs.setClassrank(classSubStuRank.get(classid + "_" + subjectid + "_" + studentid));
            ERclass rclass = rclassMap.get(classid + "_" + subjectid);
            cs.setClassmaxscore(rclass.getClassmaxscore());
            cs.setClassavgscore(rclass.getClassavgscore());
            Integer schoolrank = schoolSubStuRank.get(subjectid + "_" + studentid);
            cs.setSchoolrank(schoolrank);
            cs.setZfSchoolRank(schoolStuRank.get(studentid.toString()));
            cs.setSchoolmaxscore(rclass.getSchoolmaxscore());
            cs.setSchoolavgscore(rclass.getSchoolavgscore());
            setStuGoal(stuRankGoals, cs, schoolrank);//设置学生目标
            Double bzc = bzcMap.get(subjectid);
            cs.setBzscore(ExamUtil.standardScore(cs.getScore(), cs.getSchoolavgscore(), bzc));//学生标准分
        }
        if (N_Utils.isListNotEmpty(classSubjectStudents)) eRstudentMapper.insertList(classSubjectStudents);
        eReportGenerateQuestionService.setClassQuestion(examid, subjects, classes,base);//题型试题
        Map<Integer, String> userMap = new HashMap<>();//用户姓名map
        Map<Integer, String> userMap2 = new HashMap<>();//用户账号_姓名map
        if (N_Utils.isListNotEmpty(students)) {
            List<Integer> userids = students.stream().map(ERstudent::getStudentid).distinct().collect(Collectors.toList());
            List<UserVo> users = userMapper.listNameByUserIds(userids);
            userMap = users.stream().collect(Collectors.toMap(UserVo::getUserid, UserVo::getUsername));
            userMap2 = users.stream().collect(Collectors.toMap(UserVo::getUserid, u -> u.getLoginname() + "_" + u.getUsername()));
        }
        List<ERstudent> classSubjectStudents2;//参与统计学生列表
        if (stuzero.equals(0)) {//0分学生不参与统计
            classSubjectStudents2 = classSubjectStudents.stream().filter(s -> s.getScore() > 0).collect(Collectors.toList());
        } else {
            classSubjectStudents2 = classSubjectStudents;
        }
        setClassGradeRankAll(examid, stunum, papers, classSubjectStudents, createid, userMap);//班级等级分布
        setClassGradeRank(examid, stunum, papers, classSubjectStudents2, setRrank(5), createid, userMap);//班级等级分布--优困生

        setAction(examid, userMap);//行为分析
        eBaseMapper.updateExamState(examid,3);
        if(ConfigKey.examHaspdf){
            htmlToPdf(examid, classes, schoolStudents, userMap2);//考试报告html转pdf
        }
    }

    /**
     * @Description 考试报告html转pdf
     * @Param [examid, classes, schoolStudents, userMap]
     * @Author ywx
     * @Date 2023/2/14 11:29
     * @return void
     **/
    @Async
    public void htmlToPdf(Integer examid, List<Map> classes, List<ERstudent> schoolStudents, Map<Integer, String> userMap) {
        eBaseMapper.clearExamPdf(examid);//清空考试报告
        String savefolder = eReportGenerateMapper.getSaveFolder(examid);
        Map map = new HashMap();
        map.put("savefolder", savefolder);
        map.put("examid", examid);
        map.put("type", 1);
        map.put("filename", "school_" + examid);
        convertUtil.htmlToPdf(map);
        List<String> subjectids = eReportGenerateMapper.listSubjectIdByExamId(examid);//获取考试科目id列表
        for (Map c : classes) {
            map.put("type", 2);
            Object classid = c.get("classid");
            map.put("classid", classid);
            map.put("filename", "class_" + classid);
            convertUtil.htmlToPdf(map);
            for (String subjectid : subjectids) {
                map.put("type", 5);//单科目班级pdf
                map.put("subjectid", subjectid);
                map.put("filename", "class_" + classid + "_" + subjectid);
                convertUtil.htmlToPdf(map);
            }
        }
        for (ERstudent s : schoolStudents) {
            Integer classid = s.getClassid();
            Integer studentid = s.getStudentid();
            map.put("savefolder", savefolder + "/" + classid);
            map.put("type", 3);
            map.put("classid", classid);
            map.put("studentid", studentid);
            map.put("filename", userMap.get(studentid));
            convertUtil.htmlToPdf(map);
        }
    }

    /**
     * @Description 考试报告html转pdf
     * @Param [examid]
     * @Author ywx
     * @Date 2023/2/28 16:45
     * @return void
     **/
    @Async("asyncPoolTaskExecutor")
    public void htmlToPdf(Integer examid) {
        eBaseMapper.clearExamPdf(examid);//清空考试报告
        List<ERstudent> students = eReportGenerateMapper.listStudentByExamId(examid);//考试学生列表
        String savefolder = eReportGenerateMapper.getSaveFolder(examid);
        Map map = new HashMap();
        map.put("savefolder", savefolder);
        map.put("examid", examid);
        map.put("type", 1);
        map.put("filename", "school_" + examid);
        convertUtil.htmlToPdf(map);
        List<Integer> classids = students.stream().map(s -> s.getClassid()).distinct().collect(Collectors.toList());
        List<String> subjectids = eReportGenerateMapper.listSubjectIdByExamId(examid);//获取考试科目id列表
        for (Integer classid : classids) {
            map.put("type", 2);
            map.put("classid", classid);
            map.put("filename", "class_" + classid);
            convertUtil.htmlToPdf(map);
            for (String subjectid : subjectids) {
                map.put("type", 5);//单科目班级pdf
                map.put("subjectid", subjectid);
                map.put("filename", "class_" + classid + "_" + subjectid);
                convertUtil.htmlToPdf(map);
            }
        }
        for (ERstudent s : students) {
            Integer classid = s.getClassid();
            Integer studentid = s.getStudentid();
            map.put("savefolder", savefolder + "/" + classid);
            map.put("type", 3);
            map.put("classid", classid);
            map.put("studentid", studentid);
            map.put("filename", s.getStudentname());
            convertUtil.htmlToPdf(map);
        }
    }

    //科目统计
    private void setSubject(Integer examid, Integer fbstunum, String subjectid, String subjectname, List<ERsubject> subjectList,
                            List<ERclass> classList, List<ERstudent> list, Double allscore, Integer stuzero) {
        double yxscore = ExamUtil.mul(allscore, 0.85);//优秀分
        double lhscore = ExamUtil.mul(allscore, 0.7);//良好分
        double jgscore = ExamUtil.mul(allscore, 0.6);//及格分
        double dfscore = ExamUtil.mul(allscore, 0.4);//低分

        List<ERstudent> list2;//参与统计学生列表
        if (stuzero.equals(0)) {//0分学生不参与统计
            list2 = list.stream().filter(s -> s.getScore() > 0).collect(Collectors.toList());
        } else {
            list2 = list;
        }

        DoubleSummaryStatistics statistics = list2.stream().mapToDouble(s -> s.getScore()).summaryStatistics();
        double maxscore = N_Utils.handleInfinity(statistics.getMax());
        double minscore = N_Utils.handleInfinity(list.stream().mapToDouble(s -> s.getScore()).summaryStatistics().getMin());
        double avgscore = N_Utils.formatDouble(statistics.getAverage(), 2);
        if (N_Utils.isListEmpty(list)) {
            maxscore = 0;
            minscore = 0;
            avgscore = 0;
        }
        ERsubject rs = new ERsubject();
        rs.setExamid(examid);
        rs.setSubjectid(subjectid);
        rs.setSubjectname(subjectname);
        rs.setScore(allscore);
        rs.setMaxscore(maxscore);
        rs.setMinscore(minscore);
        rs.setAvgscore(avgscore);
        int stunum = list2.size();//参与统计学生人数
        int yxnum = list2.stream().filter(l -> l.getScore().compareTo(yxscore) != -1)
                .collect(Collectors.toList()).size();
        int lhnum = list2.stream().filter(l -> l.getScore().compareTo(lhscore) != -1)
                .collect(Collectors.toList()).size();
        int jgnum = list2.stream().filter(l -> l.getScore().compareTo(jgscore) != -1)
                .collect(Collectors.toList()).size();
        int dfnum = list2.stream().filter(l -> l.getScore().compareTo(dfscore) != 1)
                .collect(Collectors.toList()).size();
        rs.setYxrate(N_Utils.getIntegerDivideAndMulitiply(yxnum, stunum));
        rs.setLhrate(N_Utils.getIntegerDivideAndMulitiply(lhnum, stunum));
        rs.setJgrate(N_Utils.getIntegerDivideAndMulitiply(jgnum, stunum));
        rs.setDfrate(N_Utils.getIntegerDivideAndMulitiply(dfnum, stunum));
        List<Double> scores = list.stream().map(l -> l.getScore()).collect(Collectors.toList());
        double qkbzc = ExamUtil.standardDiviation(scores);
        rs.setBzc(qkbzc);
        int sknum = list.stream().filter(l -> l.getSstate() == 2)
                .map(l -> l.getStudentid()).distinct().collect(Collectors.toList()).size();
        rs.setStunum(sknum);//实考人数
        rs.setMissnum(fbstunum - sknum);//缺考人数=计划人数-实考人数
        subjectList.add(rs);

        Map<Integer, List<ERstudent>> claCollect = list.stream().collect(Collectors.groupingBy(s -> s.getClassid()));
        for (Map.Entry<Integer, List<ERstudent>> entry : claCollect.entrySet()) {
            Integer classid = entry.getKey();
            List<ERstudent> rstudentList = entry.getValue();
            List<ERstudent> rstudentList2;//参与统计学生列表
            if (stuzero.equals(0)) {//0分学生不参与统计
                rstudentList2 = rstudentList.stream().filter(s -> s.getScore() > 0).collect(Collectors.toList());
            } else {
                rstudentList2 = rstudentList;
            }
            DoubleSummaryStatistics claStatistics = rstudentList2.stream().mapToDouble(s -> s.getScore()).summaryStatistics();
            double clamaxscore = N_Utils.handleInfinity(claStatistics.getMax());
            double claminscore = N_Utils.handleInfinity(rstudentList.stream().mapToDouble(s -> s.getScore()).summaryStatistics().getMin());
            double claavgscore = N_Utils.formatDouble(claStatistics.getAverage(), 2);
            if (N_Utils.isListEmpty(list)) {
                clamaxscore = 0;
                claminscore = 0;
                claavgscore = 0;
            }

            ERclass rc = new ERclass();
            rc.setQkbzc(qkbzc);
            rc.setExamid(examid);
            rc.setClassid(classid);
            rc.setSubjectid(subjectid);
            rc.setSubjectname(subjectname);
            rc.setAllscore(allscore);
            rc.setClassmaxscore(clamaxscore);
            rc.setClassminscore(claminscore);
            rc.setClassavgscore(claavgscore);
            rc.setSchoolmaxscore(maxscore);
            rc.setSchoolavgscore(N_Utils.formatDouble(statistics.getAverage(), 2));
            sknum = rstudentList.stream().filter(l -> l.getSstate() == 2)
                    .map(l -> l.getStudentid()).distinct().collect(Collectors.toList()).size();
            rc.setStunum(sknum);//实考人数
            rc.setMissnum(rstudentList.size() - sknum);//缺考人数=计划人数-实考人数
            scores = rstudentList.stream().map(l -> l.getScore()).collect(Collectors.toList());
            stunum = rstudentList2.size();//参与统计学生人数
            yxnum = rstudentList2.stream().filter(l -> l.getScore().compareTo(yxscore) != -1)
                    .collect(Collectors.toList()).size();
            lhnum = rstudentList2.stream().filter(l -> l.getScore().compareTo(lhscore) != -1)
                    .collect(Collectors.toList()).size();
            jgnum = rstudentList2.stream().filter(l -> l.getScore().compareTo(jgscore) != -1)
                    .collect(Collectors.toList()).size();
            dfnum = rstudentList2.stream().filter(l -> l.getScore().compareTo(dfscore) != 1)
                    .collect(Collectors.toList()).size();
            rc.setYxrate(N_Utils.getIntegerDivideAndMulitiply(yxnum, stunum));
            rc.setLhrate(N_Utils.getIntegerDivideAndMulitiply(lhnum, stunum));
            rc.setJgrate(N_Utils.getIntegerDivideAndMulitiply(jgnum, stunum));
            rc.setDfrate(N_Utils.getIntegerDivideAndMulitiply(dfnum, stunum));
            rc.setBzc(ExamUtil.standardDiviation(scores));
            classList.add(rc);
        }
    }

    //班级科目平均分排名
    private void setClassAvgRank(List<ERclass> classList) {
        Map<String, Integer> classSubRank = new HashMap<>();
        Map<String, List<ERclass>> collect = classList.stream().collect(Collectors.groupingBy(c -> c.getSubjectid()));
        for (Map.Entry<String, List<ERclass>> centry : collect.entrySet()) {
            List<Map.Entry<Double, List<ERclass>>> gslist2 = centry.getValue().stream()
                    .collect(Collectors.groupingBy(ERclass::getClassavgscore)).entrySet()
                    .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
            Integer index = 1;
            for (Map.Entry<Double, List<ERclass>> entry : gslist2) {
                for (ERclass rc : entry.getValue()) {
                    classSubRank.put(rc.getClassid() + "_" + rc.getSubjectid(), index);
                }
                index = index + entry.getValue().size();
            }
        }
        for (ERclass rc : classList) {
            rc.setClassavgscorerank(classSubRank.get(rc.getClassid() + "_" + rc.getSubjectid()));
        }
    }

    //行为分析
    private void setAction(Integer examid, Map<Integer, String> userMap) {
        List<ERstudentAction> studentActions = new ArrayList<>();
        List<ERclassAction> classActions = new ArrayList<>();
        //违纪行为
        List<Map> bads = eReportGenerateMapper.listBadActionByExamId(examid);
        Integer actiontype = 1;
        setActions(examid, studentActions, classActions, bads, actiontype, userMap);
        //优秀试卷
        List<Map> goods = eReportGenerateMapper.listGoodActionByExamId(examid);
        actiontype = 2;
        setActions(examid, studentActions, classActions, goods, actiontype, userMap);

        //违规试卷
        List<Map> badques = eReportGenerateMapper.listBadQuesActionByExamId(examid);
        actiontype = 3;
        setActions(examid, studentActions, classActions, badques, actiontype, userMap);

        if (N_Utils.isListEmpty(studentActions)) return;
        if (N_Utils.isListNotEmpty(studentActions)) eRstudentActionMapper.insertList(studentActions);
        if (N_Utils.isListNotEmpty(classActions)) eRclassActionMapper.insertList(classActions);
    }

    //处理行为数据
    private void setActions(Integer examid
            , List<ERstudentAction> studentActions, List<ERclassAction> classActions
            , List<Map> actions, Integer actiontype, Map<Integer, String> userMap) {
        if (N_Utils.isListNotEmpty(actions)) {
            //班级行为分析
            Map<Integer, List<Map>> ccollect = actions.stream().collect(Collectors.groupingBy(s -> (Integer) s.get("classid")
                    , LinkedHashMap::new, Collectors.toList()));
            for (Map.Entry<Integer, List<Map>> entry : ccollect.entrySet()) {
                List<Map> subjects = new ArrayList<>();
                Map<String, List<Map>> scollect = entry.getValue().stream().collect(Collectors.groupingBy(s -> s.get("subjectid").toString()
                        , LinkedHashMap::new, Collectors.toList()));
                for (Map.Entry<String, List<Map>> sentry : scollect.entrySet()) {
                    String subjectid = sentry.getKey();
                    int znum = actions.stream().filter(s -> s.get("subjectid").equals(subjectid))
                            .collect(Collectors.toList()).size();//总人数
                    List<Map> list = sentry.getValue();
                    Map subject = new HashMap();
                    subject.put("subjectid", subjectid);
                    subject.put("subjectname", list.get(0).get("subjectname"));
                    int num = list.size();
                    subject.put("num", num);
                    subject.put("nrate", N_Utils.getIntegerDivideAndMulitiply(num, znum));
                    List<Map> students = new ArrayList<>();
                    for (Map s : list) {
                        Map stu = new HashMap();
                        Integer studentid = (Integer) s.get("studentid");
                        stu.put("studentid", studentid);
                        stu.put("num", s.get("num"));
                        stu.put("studentname", userMap.get(studentid));
                        students.add(stu);
                    }
                    subject.put("students", students);
                    subjects.add(subject);
                }
                ERclassAction ca = new ERclassAction();
                ca.setClassid(entry.getKey());
                ca.setExamid(examid);
                ca.setActiontype(actiontype);
                String subjectjson = JSON.toJSONString(subjects);
                ca.setSubjectjson(subjectjson);
                classActions.add(ca);
            }

            //学生行为分析
            Map<Integer, List<Map>> collect = actions.stream().collect(Collectors.groupingBy(s -> (Integer) s.get("studentid")
                    , LinkedHashMap::new, Collectors.toList()));
            for (Map.Entry<Integer, List<Map>> entry : collect.entrySet()) {
                List<Map> list = entry.getValue();
                Map sq = list.get(0);
                ERstudentAction sa = new ERstudentAction();
                sa.setClassid((Integer) sq.get("classid"));
                sa.setStudentid(entry.getKey());
                sa.setExamid(examid);
                sa.setActiontype(actiontype);
                for (Map s : list) {
                    s.remove("classid");
                    s.remove("studentid");
                }
                String subjectjson = JSON.toJSONString(list);
                sa.setSubjectjson(subjectjson);
                studentActions.add(sa);
            }
        }
    }

    //班级等级分布
    private void setClassGradeRankAll(Integer examid, Integer stunum, List<ERPaperVo> papers, List<ERstudent> students
            , Integer createid, Map<Integer, String> userMap) {
        setClassGradeRank(examid, stunum, papers, students, setRrank(1), createid, userMap);//班级等级分布--等级
        setClassGradeRank(examid, stunum, papers, students, setRrank(2), createid, userMap);//班级等级分布--分数段
        setClassGradeRank(examid, stunum, papers, students, setRrank(3), createid, userMap);//班级等级分布--临界分
        setClassGradeRank(examid, stunum, papers, students, setRrank(4), createid, userMap);//班级等级分布--临界名次
    }

    //等级初始值设置
    private List<ERrank> setRrank(Integer ranktype) {
        List<ERrank> rranks = new ArrayList<>();
        ERrank rrank;
        if (ranktype == 1) {//等级（A[85%~100%],B[70%~85%),C[60%~70%),D[40%~60%),E[0%~40%)）
            rrank = new ERrank();
            rrank.setRanktype(ranktype);
            rrank.setRankname("A");
            rrank.setMaxscore(1.0);
            rrank.setMinscore(0.85);
            rranks.add(rrank);

            rrank = new ERrank();
            rrank.setRanktype(ranktype);
            rrank.setRankname("B");
            rrank.setMaxscore(0.85);
            rrank.setMinscore(0.7);
            rranks.add(rrank);

            rrank = new ERrank();
            rrank.setRanktype(ranktype);
            rrank.setRankname("C");
            rrank.setMaxscore(0.7);
            rrank.setMinscore(0.6);
            rranks.add(rrank);

            rrank = new ERrank();
            rrank.setRanktype(ranktype);
            rrank.setRankname("D");
            rrank.setMaxscore(0.6);
            rrank.setMinscore(0.4);
            rranks.add(rrank);

            rrank = new ERrank();
            rrank.setRanktype(ranktype);
            rrank.setRankname("E");
            rrank.setMaxscore(0.4);
            rrank.setMinscore(0.0);
            rranks.add(rrank);
        } else if (ranktype == 2) {//分数段（10分/段）
            rrank = new ERrank();
            rrank.setRanktype(ranktype);
            rrank.setLinescore(10);
            rranks.add(rrank);
        } else if (ranktype == 3) {//临界分（临界分：总分*80%，浮动分：5分）
            rrank = new ERrank();
            rrank.setRanktype(ranktype);
            rrank.setFloatscore(5);
            rranks.add(rrank);
        } else if (ranktype == 4) {//临界名次（临界名次10，浮动名次5）
            rrank = new ERrank();
            rrank.setRanktype(ranktype);
            rrank.setLinescore(10);
            rrank.setFloatscore(5);
            rranks.add(rrank);
        } else if (ranktype == 5) {//优困生年级前/后（10名）
            rrank = new ERrank();
            rrank.setRanktype(ranktype);
            rrank.setLinescore(10);
            rrank.setFloatscore(10);
            rranks.add(rrank);
        }
        return rranks;
    }

    //班级等级分布
    public void setClassGradeRank(Integer examid, Integer fbstunum, List<ERPaperVo> papers, List<ERstudent> students
            , List<ERrank> rranks, Integer createid, Map<Integer, String> userMap) {
        Map<String, Double> scoreMap = papers.stream().collect(Collectors.toMap(p -> p.getSubjectid(), p -> p.getPscore()));//考试总分
        Double pscore;//试卷总分
        Double zfscore = papers.stream().mapToDouble(p -> p.getPscore()).sum();//考试总分
        List<ERstudent> cstudents = new ArrayList<>();//班级学生
        Map<String, List<ERstudent>> cscollect = students.stream().collect(
                Collectors.groupingBy(s -> s.getClassid() + "_" + s.getStudentid()));
        setStuScore(cscollect, cstudents);
        //总分统计
        Map<Integer, List<ERstudent>> zfcollect = cstudents.stream().collect(
                Collectors.groupingBy(s -> s.getClassid()));
        //全部班级统计
        Map<String, List<ERstudent>> qbbjcollect = students.stream().collect(
                Collectors.groupingBy(s -> s.getSubjectid()));

        List<ERrank> rrankList = new ArrayList<>();//考试报告等级
        List<ERclassRank> rclassRankList = new ArrayList<>();//考试报告班级统计
        ERrank eRrank = rranks.get(0);
        Integer ranktype = eRrank.getRanktype();
        if (ranktype == 1) {//等级（A[85%~100%],B[70%~85%),C[60%~70%),D[40%~60%),E[0%~40%)）
            for (ERrank rank : rranks) {
                Double maxrate = rank.getMaxscore();
                Double minrate = rank.getMinscore();
                //总分统计
                double zfmaxscore = ExamUtil.mul(maxrate, zfscore);
                double zfminscore = ExamUtil.mul(minrate, zfscore);
                ERrank rr = new ERrank();
                String rankname = rank.getRankname();
                rr.setRanktype(ranktype);
                rr.setRankname(rankname);
                rr.setMaxscore(zfmaxscore);
                rr.setMinscore(zfminscore);
                rr.setSubjectid("zf");
                String zfrankrange = getRankRange(zfmaxscore, zfminscore);
                List<ERstudent> collect;
                if (rr.getRankname().equals("A")) {
                    zfrankrange = zfrankrange + "]";
                    collect = cstudents.stream().filter(
                            s -> s.getScore().compareTo(zfminscore) != -1
                    ).collect(Collectors.toList());
                } else {
                    zfrankrange = zfrankrange + ")";
                    collect = cstudents.stream().filter(
                            s -> s.getScore().compareTo(zfminscore) != -1 && s.getScore().compareTo(zfmaxscore) == -1
                    ).collect(Collectors.toList());
                }
                setDjTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, "zf", 0, cstudents);
                for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                    Integer classid = entry.getKey();
                    String subjectid = "zf";
                    List<ERstudent> list = entry.getValue();
                    setDjTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, subjectid, classid, list);
                }
                Integer maxrank = null;
                Integer minrank = null;
                if (N_Utils.isListNotEmpty(collect)) {
                    maxrank = collect.stream().max(Comparator.comparing(ERstudent::getZfSchoolRank)).get().getSchoolrank();
                    minrank = collect.stream().min(Comparator.comparing(ERstudent::getZfSchoolRank)).get().getSchoolrank();
                }
                rr.setLinescore(maxrank);
                rr.setFloatscore(minrank);
                rrankList.add(rr);

                //分科统计
                for (ERPaperVo paper : papers) {
                    String subjectid = paper.getSubjectid();
                    ERrank rrank = new ERrank();
                    rrank.setRanktype(ranktype);
                    rrank.setRankname(rankname);
                    rrank.setSubjectid(subjectid);
                    pscore = scoreMap.get(subjectid);
                    double maxscore = ExamUtil.mul(maxrate, pscore);
                    double minscore = ExamUtil.mul(minrate, pscore);
                    rrank.setMaxscore(maxscore);
                    rrank.setMinscore(minscore);
                    String rankrange = getRankRange(maxscore, minscore);
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    if (rankname.equals("A")) {
                        rankrange = rankrange + "]";
                        collect = list.stream().filter(
                                s -> s.getScore().compareTo(minscore) != -1
                        ).collect(Collectors.toList());
                    } else {
                        rankrange = rankrange + ")";
                        collect = list.stream().filter(
                                s -> s.getScore().compareTo(minscore) != -1 && s.getScore().compareTo(maxscore) == -1
                        ).collect(Collectors.toList());
                    }

                    //全部班级统计
                    Integer classid = 0;
                    setDjTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, subjectid, classid, list);
                    maxrank = null;
                    minrank = null;
                    if (N_Utils.isListNotEmpty(collect)) {
                        maxrank = collect.stream().max(Comparator.comparing(ERstudent::getSchoolrank)).get().getSchoolrank();
                        minrank = collect.stream().min(Comparator.comparing(ERstudent::getSchoolrank)).get().getSchoolrank();
                    }
                    rrank.setLinescore(maxrank);
                    rrank.setFloatscore(minrank);
                    rrankList.add(rrank);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setDjTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, subjectid, classid, list);
                    }
                }
            }
        } else if (ranktype == 2) {//分数段（10分/段）
            Integer linescore = eRrank.getLinescore();
            //总分统计
            Integer gnum = ExamUtil.divUp(zfscore, linescore);
            for (Integer i = 1; i <= gnum; i++) {
                ERrank rrank = new ERrank();
                rrank.setRanktype(ranktype);
                double maxscore = ExamUtil.mul(i, linescore);
                double minscore = ExamUtil.mul(i - 1, linescore);
                if (maxscore > zfscore) {
                    maxscore = zfscore;
                }
                rrank.setMaxscore(maxscore);
                rrank.setMinscore(minscore);
                String rankrange = getRankRange(maxscore, minscore);
                if (i == gnum) {
                    rankrange = rankrange + "]";
                } else {
                    rankrange = rankrange + ")";
                }
                rrank.setRankname(rankrange);
                rrank.setSubjectid("zf");
                rrankList.add(rrank);

                setFdTj(examid, fbstunum, userMap, rclassRankList, gnum, i, rrank, rankrange, 0, cstudents);
                for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                    Integer classid = entry.getKey();
                    String subjectid = "zf";
                    List<ERstudent> list = entry.getValue();
                    setFdTj(examid, fbstunum, userMap, rclassRankList, gnum, i, rrank, rankrange, classid, list);
                }
            }

            //分科统计
            for (ERPaperVo paper : papers) {
                String subjectid = paper.getSubjectid();
                pscore = scoreMap.get(subjectid);
                Integer cnum = ExamUtil.divUp(pscore, linescore);
                for (Integer i = 1; i <= cnum; i++) {
                    ERrank rrank = new ERrank();
                    rrank.setSubjectid(subjectid);
                    rrank.setRanktype(ranktype);
                    rrank.setSubjectid(subjectid);
                    double maxscore = ExamUtil.mul(i, linescore);
                    double minscore = ExamUtil.mul(i - 1, linescore);
                    if (maxscore > pscore) {
                        maxscore = pscore;
                    }
                    rrank.setMaxscore(maxscore);
                    rrank.setMinscore(minscore);
                    String rankrange = getRankRange(maxscore, minscore);
                    if (i == cnum) {
                        rankrange = rankrange + "]";
                    } else {
                        rankrange = rankrange + ")";
                    }
                    rrank.setRankname(rankrange);
                    rrankList.add(rrank);

                    //全部班级统计
                    Integer classid = 0;
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    setFdTj(examid, fbstunum, userMap, rclassRankList, cnum, i, rrank, rankrange, classid, list);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setFdTj(examid, fbstunum, userMap, rclassRankList, cnum, i, rrank, rankrange, classid, list);
                    }
                }
            }
        } else {
            Integer lscore = eRrank.getLinescore();
            if (ranktype == 3) {//临界分（临界分：总分*80%，浮动分：5分）
                Integer linescore = lscore;
                Integer floatscore = eRrank.getFloatscore();
                ERrank rr = new ERrank();
                rr.setRanktype(ranktype);
                //总分统计
                if (N_Utils.isEmptyInteger(linescore)) linescore = (int) (ExamUtil.mul(zfscore, 0.8));
                double zfmaxscore = ExamUtil.add(linescore, floatscore);
                double zfminscore = ExamUtil.sub(linescore, floatscore);
                if (zfmaxscore > zfscore) zfmaxscore = zfscore;
                if (zfminscore < 0) zfminscore = 0;
                rr.setMaxscore(zfmaxscore);
                rr.setMinscore(zfminscore);
                rr.setLinescore(linescore);
                rr.setFloatscore(floatscore);
                String zfrankrange = getRankRange(zfmaxscore, zfminscore) + "]";
                rr.setRankname(zfrankrange);
                rr.setSubjectid("zf");
                rrankList.add(rr);

                setLjfTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, 0, "zf", cstudents);
                for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                    Integer classid = entry.getKey();
                    String subjectid = "zf";
                    List<ERstudent> list = entry.getValue();
                    setLjfTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, classid, subjectid, list);
                }

                //分科统计
                for (ERPaperVo paper : papers) {
                    String subjectid = paper.getSubjectid();
                    ERrank rrank = new ERrank();
                    rrank.setRanktype(ranktype);
                    rrank.setSubjectid(subjectid);
                    pscore = scoreMap.get(subjectid);
                    linescore = lscore;
                    if (N_Utils.isEmptyInteger(linescore)) linescore = (int) (ExamUtil.mul(pscore, 0.8));
                    double maxscore = ExamUtil.add(linescore, floatscore);
                    double minscore = ExamUtil.sub(linescore, floatscore);
                    if (maxscore > pscore) maxscore = pscore;
                    if (minscore < 0) minscore = 0;
                    rrank.setMaxscore(maxscore);
                    rrank.setMinscore(minscore);
                    rrank.setLinescore(linescore);
                    rrank.setFloatscore(floatscore);
                    String rankrange = getRankRange(maxscore, minscore) + "]";
                    rrank.setRankname(rankrange);
                    rrankList.add(rrank);

                    //全部班级统计
                    Integer classid = 0;
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    setLjfTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, classid, subjectid, list);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setLjfTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, classid, subjectid, list);
                    }
                }
            } else if (ranktype == 4) {//临界名次（临界名次10，浮动名次5）
                Integer linescore = lscore;
                Integer floatscore = eRrank.getFloatscore();
                ERrank rr = new ERrank();
                rr.setRanktype(ranktype);
                //总分统计
                double zfmaxscore = ExamUtil.sub(linescore, floatscore);//最高名次
                double zfminscore = ExamUtil.add(linescore, floatscore);//最低名次
                if (zfmaxscore < 1) zfmaxscore = 1;//最高名次为1
                int zfstunum = (int) students.stream().map(s -> s.getStudentid()).distinct().count();//学生数量
                if (zfminscore > zfstunum) zfminscore = zfstunum;//最低名次=学生数量
                rr.setMaxscore(zfmaxscore);
                rr.setMinscore(zfminscore);
                rr.setLinescore(linescore);
                rr.setFloatscore(floatscore);
                String zfrankrange = getRankRange(zfmaxscore, zfminscore) + "]";
                rr.setRankname(zfrankrange);
                rr.setSubjectid("zf");
                rrankList.add(rr);

                setLjmcTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, 0, "zf", cstudents);
                for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                    Integer classid = entry.getKey();
                    String subjectid = "zf";
                    List<ERstudent> list = entry.getValue();
                    setLjmcTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, classid, subjectid, list);
                }

                //分科统计
                for (ERPaperVo paper : papers) {
                    String subjectid = paper.getSubjectid();
                    double maxscore = ExamUtil.sub(linescore, floatscore);//最高名次
                    double minscore = ExamUtil.add(linescore, floatscore);//最低名次
                    if (maxscore < 1) maxscore = 1;//最高名次为1
                    Integer stunum = students.size();//学生数量
                    if (minscore > stunum) minscore = stunum;//最低名次=学生数量
                    ERrank rrank = new ERrank();
                    rrank.setRanktype(ranktype);
                    rrank.setSubjectid(subjectid);
                    rrank.setMaxscore(maxscore);
                    rrank.setMinscore(minscore);
                    rrank.setLinescore(linescore);
                    rrank.setFloatscore(floatscore);
                    String rankrange = getRankRange(maxscore, minscore) + "]";
                    rrank.setRankname(rankrange);
                    rrankList.add(rrank);

                    //全部班级统计
                    Integer classid = 0;
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    setLjmcTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, classid, subjectid, list);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setLjmcTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, classid, subjectid, list);
                    }
                }
            } else if (ranktype == 5) {//优困生
                Integer linescore = lscore;
                Integer floatscore = eRrank.getFloatscore();
                ERrank rr = new ERrank();
                rr.setRanktype(ranktype);
                rr.setLinescore(linescore);
                rr.setFloatscore(floatscore);
                String rankrange = getRankRange(floatscore, linescore) + "]";
                String rankname = "优困生";
                rr.setRankname(rankname);
                //总分统计
                rr.setSubjectid("zf");
                rrankList.add(rr);
                rr.setMaxscore(getMaxScore(cstudents, floatscore));
                setYksTj(examid, fbstunum, rclassRankList, rr, rankrange, 0, "zf", cstudents);
                for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                    Integer classid = entry.getKey();
                    String subjectid = "zf";
                    List<ERstudent> list = entry.getValue();
                    rr.setMaxscore(getMaxScore(list, floatscore));
                    setYksTj(examid, fbstunum, rclassRankList, rr, rankrange, classid, subjectid, list);
                }
                rr.setMaxscore(null);

                //分科统计
                for (ERPaperVo paper : papers) {
                    String subjectid = paper.getSubjectid();
                    ERrank rrank = new ERrank();
                    rrank.setRanktype(ranktype);
                    rrank.setRankname(rankname);
                    rrank.setLinescore(linescore);
                    rrank.setFloatscore(floatscore);
                    rrank.setSubjectid(subjectid);
                    rrankList.add(rrank);
                    //全部班级统计
                    Integer classid = 0;
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    rrank.setMaxscore(getMaxScore(list, floatscore));
                    setYksTj(examid, fbstunum, rclassRankList, rrank, rankrange, classid, subjectid, list);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setYksTj(examid, fbstunum, rclassRankList, rrank, rankrange, classid, subjectid, list);
                    }
                    rrank.setMaxscore(null);
                }
            }
        }

        int timestamp = N_Utils.getSecondTimestamp();
        rrankList.forEach(r -> {
            r.setExamid(examid);
            r.setCreateid(createid);
            r.setCreatetime(timestamp);
        });
        if (N_Utils.isListNotEmpty(rrankList)) eRrankMapper.insertList(rrankList);
        saveClassRank(rclassRankList, ranktype);//保存考试报告班级等级分布
    }

    //保存考试报告班级等级分布
    private void saveClassRank(List<ERclassRank> rclassRankList, Integer ranktype) {
        if (N_Utils.isListEmpty(rclassRankList)) return;
        if (ranktype == 3 || ranktype == 4) {
            Map<String, List<ERclassRank>> collect = rclassRankList.stream().collect(
                    Collectors.groupingBy(r -> r.getSubjectid(), LinkedHashMap::new, Collectors.toList()));
            for (Map.Entry<String, List<ERclassRank>> entry : collect.entrySet()) {
                Integer znum = 0;//范围内总人数
                List<ERclassRank> rankList = entry.getValue();
                for (int i = 0; i < rankList.size(); i++) {
                    ERclassRank r = rankList.get(i);
                    if (i == 0) {
                        r.setSturate(100.0);
                        znum = r.getStunum();
                    } else {
                        r.setSturate(N_Utils.getIntegerDivideAndMulitiply(r.getStunum(), znum));
                    }
                }
            }
        } else if (ranktype == 5) {
            Map<String, List<ERclassRank>> collect = rclassRankList.stream().collect(
                    Collectors.groupingBy(r -> r.getSubjectid(), LinkedHashMap::new, Collectors.toList()));
            for (Map.Entry<String, List<ERclassRank>> entry : collect.entrySet()) {
                Integer qznum = 0;//前X名总人数
                Integer hznum = 0;//后X名总人数
                List<ERclassRank> rankList = entry.getValue();
                for (int i = 0; i < rankList.size(); i++) {
                    ERclassRank r = rankList.get(i);
                    List<Map> list = JSON.parseArray(r.getStujson(), Map.class);
                    Map q = new HashMap();
                    Map h = new HashMap();
                    if (N_Utils.isListNotEmpty(list)) {
                        q = list.get(0);
                        h = list.get(1);
                    }
                    if (i == 0) {
                        if (N_Utils.isListEmpty(list)) continue;
                        qznum = (Integer) q.get("stunum");
                        hznum = (Integer) h.get("stunum");
                        q.put("sturate", 100);
                        h.put("sturate", 100);
                    } else {
                        q.put("sturate", N_Utils.getIntegerDivideAndMulitiply((Integer) q.get("stunum"), qznum));
                        h.put("sturate", N_Utils.getIntegerDivideAndMulitiply((Integer) h.get("stunum"), hznum));
                    }
                    r.setStujson(JSON.toJSONString(list));
                }
            }
        }
        eRclassRankMapper.insertList(rclassRankList);
    }

    //单科校次
    private void setSchoolRank(List<ERstudent> students, Map<Integer, Integer> rank) {
        List<Map.Entry<Double, List<ERstudent>>> gslist2 = students.stream()
                .collect(Collectors.groupingBy(ERstudent::getScore)).entrySet()
                .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
        Integer index = 1;
        for (Map.Entry<Double, List<ERstudent>> entry : gslist2) {
            for (ERstudent cgs : entry.getValue()) {
                Integer studentid = cgs.getStudentid();
                rank.put(studentid, index);
                cgs.setSchoolrank(index);
                cgs.setZfSchoolRank(index);
                cgs.setClassrank(index);
            }
            index = index + entry.getValue().size();
        }
    }

    //单科等级分布
    //分数等级统计、分数分段统计、临界生对比（0分全部参与计算）
    //优秀、学困生对比（根据报告设置参数计算）
    public void setSubjectRank(Integer examid, String subjectid, Integer createid, List<ERrank> rranks, Integer ranktype) {
        Integer stuzero = eBaseMapper.getStuZeroByExamId(examid);
        Double pscore = eReportGenerateMapper.getScoreByExamAndSubjectId(examid, subjectid);//获取试卷分数
        List<ERstudent> allStudents = ePaperStudentMapper.listByExamAndSubjectId(examid, subjectid);//考试试卷学生
        List<ERstudent> students;
        if (stuzero.equals(0) && ranktype.equals(5)) {//0分学生不参与统计
            students = allStudents.stream().filter(s -> s.getScore() > 0).collect(Collectors.toList());
        } else {
            students = allStudents;
        }
        List<Integer> userids = students.stream().map(ERstudent::getStudentid).distinct().collect(Collectors.toList());
        Integer fbstunum = userids.size();//获取考试发布学生数量
        List<UserVo> users = userMapper.listNameByUserIds(userids);
        Map<Integer, String> userMap = users.stream().collect(Collectors.toMap(UserVo::getUserid, UserVo::getUsername));
        List<ERstudent> cstudents = new ArrayList<>();//班级学生
        Map<String, List<ERstudent>> cscollect = students.stream().collect(
                Collectors.groupingBy(s -> s.getClassid() + "_" + s.getStudentid()));
        setStuScore(cscollect, cstudents);
        //总分统计
        Map<Integer, List<ERstudent>> zfcollect = cstudents.stream().collect(
                Collectors.groupingBy(s -> s.getClassid()));

        //排名
        Map<Integer, Integer> schoolStuRank = new HashMap<>();//学校学生分数排名
        setSchoolRank(cstudents, schoolStuRank);//学校学生分数排名
        for (ERstudent cs : students) {
            Integer studentid = cs.getStudentid();
            Integer schoolrank = schoolStuRank.get(studentid);
            cs.setSchoolrank(schoolrank);
            cs.setZfSchoolRank(schoolrank);
            cs.setClassrank(schoolrank);
        }

        //全部班级统计
        Map<String, List<ERstudent>> qbbjcollect = students.stream().collect(
                Collectors.groupingBy(s -> s.getSubjectid()));

        List<ERrank> rrankList = new ArrayList<>();//考试报告等级
        List<ERclassRank> rclassRankList = new ArrayList<>();//考试报告班级统计
        ERrank eRrank = rranks.get(0);
        if (ranktype == 1) {//等级（A[85%~100%],B[70%~85%),C[60%~70%),D[40%~60%),E[0%~40%)）
            for (ERrank rank : rranks) {
                Double maxscore = rank.getMaxscore();
                Double minscore = rank.getMinscore();
                String rankname = rank.getRankname();
                if ("zf".equals(subjectid)) {
                    //总分统计
                    ERrank rr = new ERrank();
                    rr.setRanktype(ranktype);
                    rr.setRankname(rankname);
                    rr.setMaxscore(maxscore);
                    rr.setMinscore(minscore);
                    rr.setSubjectid("zf");
                    String zfrankrange = getRankRange(maxscore, minscore);
                    List<ERstudent> collect;
                    if (rr.getRankname().equals("A")) {
                        zfrankrange = zfrankrange + "]";
                        collect = cstudents.stream().filter(
                                s -> s.getScore().compareTo(minscore) != -1
                        ).collect(Collectors.toList());
                    } else {
                        zfrankrange = zfrankrange + ")";
                        collect = cstudents.stream().filter(
                                s -> s.getScore().compareTo(minscore) != -1 && s.getScore().compareTo(maxscore) == -1
                        ).collect(Collectors.toList());
                    }
                    setDjTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, subjectid, 0, cstudents);
                    for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                        Integer classid = entry.getKey();
                        List<ERstudent> list = entry.getValue();
                        setDjTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, subjectid, classid, list);
                    }
                    Integer maxrank = null;
                    Integer minrank = null;
                    if (N_Utils.isListNotEmpty(collect)) {
                        maxrank = collect.stream().max(Comparator.comparing(ERstudent::getSchoolrank)).get().getSchoolrank();
                        minrank = collect.stream().min(Comparator.comparing(ERstudent::getSchoolrank)).get().getSchoolrank();
                    }
                    rr.setLinescore(maxrank);
                    rr.setFloatscore(minrank);
                    rrankList.add(rr);
                } else {
                    //分科统计
                    ERrank rrank = new ERrank();
                    rrank.setRanktype(ranktype);
                    rrank.setRankname(rankname);
                    rrank.setSubjectid(subjectid);
                    rrank.setMaxscore(maxscore);
                    rrank.setMinscore(minscore);
                    String rankrange = getRankRange(maxscore, minscore);
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    List<ERstudent> collect;
                    if (rankname.equals("A")) {
                        rankrange = rankrange + "]";
                        collect = list.stream().filter(
                                s -> s.getScore().compareTo(minscore) != -1
                        ).collect(Collectors.toList());
                    } else {
                        rankrange = rankrange + ")";
                        collect = list.stream().filter(
                                s -> s.getScore().compareTo(minscore) != -1 && s.getScore().compareTo(maxscore) == -1
                        ).collect(Collectors.toList());
                    }

                    //全部班级统计
                    Integer classid = 0;
                    setDjTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, subjectid, classid, list);
                    Integer maxrank = null;
                    Integer minrank = null;
                    if (N_Utils.isListNotEmpty(collect)) {
                        maxrank = collect.stream().max(Comparator.comparing(ERstudent::getSchoolrank)).get().getSchoolrank();
                        minrank = collect.stream().min(Comparator.comparing(ERstudent::getSchoolrank)).get().getSchoolrank();
                    }
                    rrank.setLinescore(maxrank);
                    rrank.setFloatscore(minrank);
                    rrankList.add(rrank);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setDjTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, subjectid, classid, list);
                    }
                }
            }
        } else if (ranktype == 2) {//分数段（10分/段）
            Integer linescore = eRrank.getLinescore();
            if ("zf".equals(subjectid)) {
                //总分统计
                Integer gnum = ExamUtil.divUp(pscore, linescore);
                for (Integer i = 1; i <= gnum; i++) {
                    ERrank rrank = new ERrank();
                    rrank.setRanktype(ranktype);
                    double maxscore = ExamUtil.mul(i, linescore);
                    double minscore = ExamUtil.mul(i - 1, linescore);
                    if (maxscore > pscore) {
                        maxscore = pscore;
                    }
                    rrank.setMaxscore(maxscore);
                    rrank.setMinscore(minscore);
                    String rankrange = getRankRange(maxscore, minscore);
                    if (i == gnum) {
                        rankrange = rankrange + "]";
                    } else {
                        rankrange = rankrange + ")";
                    }
                    rrank.setRankname(rankrange);
                    rrank.setSubjectid("zf");
                    rrankList.add(rrank);

                    setFdTj(examid, fbstunum, userMap, rclassRankList, gnum, i, rrank, rankrange, 0, cstudents);
                    for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                        Integer classid = entry.getKey();
                        List<ERstudent> list = entry.getValue();
                        setFdTj(examid, fbstunum, userMap, rclassRankList, gnum, i, rrank, rankrange, classid, list);
                    }
                }
            } else {
                //分科统计
                Integer cnum = ExamUtil.divUp(pscore, linescore);
                for (Integer i = 1; i <= cnum; i++) {
                    ERrank rrank = new ERrank();
                    rrank.setSubjectid(subjectid);
                    rrank.setRanktype(ranktype);
                    rrank.setSubjectid(subjectid);
                    double maxscore = ExamUtil.mul(i, linescore);
                    double minscore = ExamUtil.mul(i - 1, linescore);
                    if (maxscore > pscore) {
                        maxscore = pscore;
                    }
                    rrank.setMaxscore(maxscore);
                    rrank.setMinscore(minscore);
                    String rankrange = getRankRange(maxscore, minscore);
                    if (i == cnum) {
                        rankrange = rankrange + "]";
                    } else {
                        rankrange = rankrange + ")";
                    }
                    rrank.setRankname(rankrange);
                    rrankList.add(rrank);

                    //全部班级统计
                    Integer classid = 0;
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    setFdTj(examid, fbstunum, userMap, rclassRankList, cnum, i, rrank, rankrange, classid, list);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setFdTj(examid, fbstunum, userMap, rclassRankList, cnum, i, rrank, rankrange, classid, list);
                    }
                }
            }
        } else {
            Integer lscore = eRrank.getLinescore();
            if (ranktype == 3) {//临界分（临界分：总分*80%，浮动分：5分）
                Integer linescore = lscore;
                Integer floatscore = eRrank.getFloatscore();
                ERrank rr = new ERrank();
                rr.setRanktype(ranktype);
                if ("zf".equals(subjectid)) {
                    //总分统计
                    if (N_Utils.isEmptyInteger(linescore)) linescore = (int) (ExamUtil.mul(pscore, 0.8));
                    double zfmaxscore = ExamUtil.add(linescore, floatscore);
                    double zfminscore = ExamUtil.sub(linescore, floatscore);
                    if (zfmaxscore > pscore) zfmaxscore = pscore;
                    if (zfminscore < 0) zfminscore = 0;
                    rr.setMaxscore(zfmaxscore);
                    rr.setMinscore(zfminscore);
                    rr.setLinescore(linescore);
                    rr.setFloatscore(floatscore);
                    String zfrankrange = getRankRange(zfmaxscore, zfminscore) + "]";
                    rr.setRankname(zfrankrange);
                    rr.setSubjectid("zf");
                    rrankList.add(rr);

                    setLjfTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, 0, subjectid, cstudents);
                    for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                        Integer classid = entry.getKey();
                        List<ERstudent> list = entry.getValue();
                        setLjfTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, classid, subjectid, list);
                    }
                } else {
                    //分科统计
                    ERrank rrank = new ERrank();
                    rrank.setRanktype(ranktype);
                    rrank.setSubjectid(subjectid);
                    linescore = lscore;
                    if (N_Utils.isEmptyInteger(linescore)) linescore = (int) (ExamUtil.mul(pscore, 0.8));
                    double maxscore = ExamUtil.add(linescore, floatscore);
                    double minscore = ExamUtil.sub(linescore, floatscore);
                    if (maxscore > pscore) maxscore = pscore;
                    if (minscore < 0) minscore = 0;
                    rrank.setMaxscore(maxscore);
                    rrank.setMinscore(minscore);
                    rrank.setLinescore(linescore);
                    rrank.setFloatscore(floatscore);
                    String rankrange = getRankRange(maxscore, minscore) + "]";
                    rrank.setRankname(rankrange);
                    rrankList.add(rrank);

                    //全部班级统计
                    Integer classid = 0;
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    setLjfTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, classid, subjectid, list);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setLjfTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, classid, subjectid, list);
                    }
                }

            } else if (ranktype == 4) {//临界名次（临界名次10，浮动名次5）
                Integer linescore = lscore;
                Integer floatscore = eRrank.getFloatscore();
                ERrank rr = new ERrank();
                rr.setRanktype(ranktype);
                if ("zf".equals(subjectid)) {
                    //总分统计
                    double zfmaxscore = ExamUtil.sub(linescore, floatscore);//最高名次
                    double zfminscore = ExamUtil.add(linescore, floatscore);//最低名次
                    if (zfmaxscore < 1) zfmaxscore = 1;//最高名次为1
                    int zfstunum = (int) students.stream().map(s -> s.getStudentid()).distinct().count();//学生数量
                    if (zfminscore > zfstunum) zfminscore = zfstunum;//最低名次=学生数量
                    rr.setMaxscore(zfmaxscore);
                    rr.setMinscore(zfminscore);
                    rr.setLinescore(linescore);
                    rr.setFloatscore(floatscore);
                    String zfrankrange = getRankRange(zfmaxscore, zfminscore) + "]";
                    rr.setRankname(zfrankrange);
                    rr.setSubjectid("zf");
                    rrankList.add(rr);

                    setLjmcTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, 0, subjectid, cstudents);
                    for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                        Integer classid = entry.getKey();
                        List<ERstudent> list = entry.getValue();
                        setLjmcTj(examid, fbstunum, userMap, rclassRankList, rr, zfrankrange, classid, subjectid, list);
                    }
                } else {
                    //分科统计
                    double maxscore = ExamUtil.sub(linescore, floatscore);//最高名次
                    double minscore = ExamUtil.add(linescore, floatscore);//最低名次
                    if (maxscore < 1) maxscore = 1;//最高名次为1
                    Integer stunum = students.size();//学生数量
                    if (minscore > stunum) minscore = stunum;//最低名次=学生数量
                    ERrank rrank = new ERrank();
                    rrank.setRanktype(ranktype);
                    rrank.setSubjectid(subjectid);
                    rrank.setMaxscore(maxscore);
                    rrank.setMinscore(minscore);
                    rrank.setLinescore(linescore);
                    rrank.setFloatscore(floatscore);
                    String rankrange = getRankRange(maxscore, minscore) + "]";
                    rrank.setRankname(rankrange);
                    rrankList.add(rrank);

                    //全部班级统计
                    Integer classid = 0;
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    setLjmcTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, classid, subjectid, list);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setLjmcTj(examid, fbstunum, userMap, rclassRankList, rrank, rankrange, classid, subjectid, list);
                    }
                }

            } else if (ranktype == 5) {//优困生
                Integer linescore = lscore;
                Integer floatscore = eRrank.getFloatscore();
                ERrank rr = new ERrank();
                rr.setRanktype(ranktype);
                rr.setLinescore(linescore);
                rr.setFloatscore(floatscore);
                String rankrange = getRankRange(floatscore, linescore) + "]";
                String rankname = "优困生";
                rr.setRankname(rankname);
                if ("zf".equals(subjectid)) {
                    //总分统计
                    rr.setSubjectid("zf");
                    rrankList.add(rr);
                    rr.setMaxscore(getMaxScore(cstudents, floatscore));
                    setYksTj(examid, fbstunum, rclassRankList, rr, rankrange, 0, subjectid, cstudents);
                    for (Map.Entry<Integer, List<ERstudent>> entry : zfcollect.entrySet()) {
                        Integer classid = entry.getKey();
                        List<ERstudent> list = entry.getValue();
                        //rr.setMaxscore(getMaxScore(list, floatscore));
                        setYksTj(examid, fbstunum, rclassRankList, rr, rankrange, classid, subjectid, list);
                    }
                    rr.setMaxscore(null);
                } else {
                    //分科统计
                    ERrank rrank = new ERrank();
                    rrank.setRanktype(ranktype);
                    rrank.setRankname(rankname);
                    rrank.setLinescore(linescore);
                    rrank.setFloatscore(floatscore);
                    rrank.setSubjectid(subjectid);
                    rrankList.add(rrank);
                    //全部班级统计
                    Integer classid = 0;
                    List<ERstudent> list = listStudentBySubjectId(subjectid, qbbjcollect);
                    rrank.setMaxscore(getMaxScore(list, floatscore));
                    setYksTj(examid, fbstunum, rclassRankList, rrank, rankrange, classid, subjectid, list);

                    //班级科目统计
                    Map<Integer, List<ERstudent>> ccollect = students.stream().filter(s -> s.getSubjectid().equals(subjectid))
                            .collect(Collectors.groupingBy(s -> s.getClassid()));
                    for (Map.Entry<Integer, List<ERstudent>> entry : ccollect.entrySet()) {
                        classid = entry.getKey();
                        list = entry.getValue();
                        setYksTj(examid, fbstunum, rclassRankList, rrank, rankrange, classid, subjectid, list);
                    }
                    rrank.setMaxscore(null);
                }
            }
        }

        int timestamp = N_Utils.getSecondTimestamp();
        rrankList.forEach(r -> {
            r.setExamid(examid);
            r.setCreateid(createid);
            r.setCreatetime(timestamp);
        });
        if (N_Utils.isListNotEmpty(rrankList)) eRrankMapper.insertList(rrankList);
        saveClassRank(rclassRankList, ranktype);//保存考试报告班级等级分布
    }

    //等级分类范围
    private String getRankRange(double maxscore, double minscore) {
        return "[" + ExamUtil.doubleToStr(minscore) + "," + ExamUtil.doubleToStr(maxscore);
    }

    //获取科目学生
    private List<ERstudent> listStudentBySubjectId(String subjectid, Map<String, List<ERstudent>> qbbjcollect) {
        List<ERstudent> list = qbbjcollect.get(subjectid);
        if (list == null) list = new ArrayList<>();
        return list;
    }

    //获取最高分
    private Double getMaxScore(List<ERstudent> cstudents, Integer linescore) {
        if(N_Utils.isListEmpty(cstudents)) return 0.0;
        List<Double> cScore = cstudents.stream().map(s -> s.getScore()).distinct().sorted().collect(Collectors.toList());
        int rnum = cScore.size();//排名数量
        if (linescore > rnum) linescore = rnum;
        Double maxscore = cScore.get(linescore - 1);
        return maxscore;
    }

    //考试报告--优困生统计
    private void setYksTj(Integer examid, Integer gstunum, List<ERclassRank> rclassRankList, ERrank rrank,
                          String rankrange, Integer classid, String subjectid, List<ERstudent> list) {
        ERclassRank cr = new ERclassRank();
        cr.setExamid(examid);
        cr.setClassid(classid);
        cr.setSubjectid(subjectid);
        cr.setRanktype(rrank.getRanktype());
        cr.setRankname(rrank.getRankname());

        Integer rank = rrank.getLinescore();//年级前rank名
        Double maxscore = rrank.getMaxscore();//年级后rank名最高分

        List<ERstudent> list2 = list.stream().filter(s -> s.getSchoolrank().compareTo(rank) != 1).collect(Collectors.toList());
        List<ERstudent> list3 = list.stream().filter(s -> s.getScore().compareTo(maxscore) != 1).collect(Collectors.toList());

        cr.setRankrange(rankrange);
        int stuqnum = list2.size();
        int stuhnum = list3.size();
        //int stunum = stuqnum + stuhnum;

        //cr.setStunum(stunum);
        //cr.setSturate(N_Utils.getIntegerDivideAndMulitiply(stunum, gstunum));
        List<Map> students = new ArrayList<>();
        Map q = new HashMap();
        q.put("stunum", stuqnum);
        //q.put("sturate", N_Utils.getIntegerDivideAndMulitiply(stuqnum, gstunum));
        students.add(q);
        Map h = new HashMap();
        h.put("stunum", stuhnum);
        //h.put("sturate", N_Utils.getIntegerDivideAndMulitiply(stuhnum, gstunum));
        students.add(h);
        String stujson = JSON.toJSONString(students);
        cr.setStujson(stujson);
        rclassRankList.add(cr);
    }

    //考试报告--临界名次统计
    private void setLjmcTj(Integer examid, Integer gstunum, Map<Integer, String> userMap,
                           List<ERclassRank> rclassRankList, ERrank rrank,
                           String rankrange, Integer classid, String subjectid, List<ERstudent> list) {
        ERclassRank cr = new ERclassRank();
        cr.setExamid(examid);
        cr.setClassid(classid);
        cr.setSubjectid(subjectid);
        cr.setRanktype(rrank.getRanktype());
        cr.setRankname(rrank.getRankname());
        List<ERstudent> list2;

        Integer finalMinscore = rrank.getMinscore().intValue();
        Integer finalMaxscore = rrank.getMaxscore().intValue();
        if (subjectid.equals("zf")) {//总分统计
            list2 = list.stream().filter(s -> s.getZfSchoolRank().compareTo(finalMinscore) != 1
                    && s.getZfSchoolRank().compareTo(finalMaxscore) != -1).collect(Collectors.toList());
        } else if (classid == 0) {//全部班级统计
            list2 = list.stream().filter(s -> s.getSchoolrank().compareTo(finalMinscore) != 1
                    && s.getClassrank().compareTo(finalMaxscore) != -1).collect(Collectors.toList());
        } else {//班级科目统计
            list2 = list.stream().filter(s -> s.getClassrank().compareTo(finalMinscore) != 1
                    && s.getClassrank().compareTo(finalMaxscore) != -1).collect(Collectors.toList());
        }

        cr.setRankrange(rankrange);
        int stunum = list2.size();
        cr.setStunum(stunum);
        //cr.setSturate(N_Utils.getIntegerDivideAndMulitiply(stunum, gstunum));
        setStudentName(list2, userMap);
        String stujson = stuJson(list2);
        cr.setStujson(stujson);
        rclassRankList.add(cr);
    }

    //考试报告--临界分统计
    private void setLjfTj(Integer examid, Integer gstunum, Map<Integer, String> userMap,
                          List<ERclassRank> rclassRankList, ERrank rrank,
                          String rankrange, Integer classid, String subjectid, List<ERstudent> list) {
        ERclassRank cr = new ERclassRank();
        cr.setExamid(examid);
        cr.setClassid(classid);
        cr.setSubjectid(subjectid);
        cr.setRanktype(rrank.getRanktype());
        cr.setRankname(rrank.getRankname());
        List<ERstudent> list2;

        double finalMinscore = rrank.getMinscore();
        double finalMaxscore = rrank.getMaxscore();
        list2 = list.stream().filter(s -> s.getScore().compareTo(finalMinscore) != -1
                && s.getScore().compareTo(finalMaxscore) != 1).collect(Collectors.toList());
        cr.setRankrange(rankrange);
        int stunum = list2.size();
        cr.setStunum(stunum);
        //cr.setSturate(N_Utils.getIntegerDivideAndMulitiply(stunum, gstunum));
        setStudentName(list2, userMap);
        String stujson = stuJson(list2);
        cr.setStujson(stujson);
        rclassRankList.add(cr);
    }

    //考试报告--分段统计
    private void setFdTj(Integer examid, Integer gstunum, Map<Integer, String> userMap,
                         List<ERclassRank> rclassRankList, Integer gnum,
                         Integer i, ERrank rrank, String rankrange, Integer classid, List<ERstudent> list) {
        ERclassRank gr = new ERclassRank();
        gr.setExamid(examid);
        gr.setClassid(classid);
        gr.setSubjectid(rrank.getSubjectid());
        gr.setRanktype(rrank.getRanktype());
        gr.setRankname(rrank.getRankname());
        List<ERstudent> list2;

        double finalMinscore = rrank.getMinscore();
        double finalMaxscore = rrank.getMaxscore();
        if (i == gnum) {
            list2 = list.stream().filter(s -> s.getScore().compareTo(finalMinscore) != -1).collect(Collectors.toList());
        } else {
            list2 = list.stream().filter(s -> s.getScore().compareTo(finalMinscore) != -1
                    && s.getScore().compareTo(finalMaxscore) == -1).collect(Collectors.toList());
        }
        gr.setRankrange(rankrange);
        int stunum = list2.size();
        gr.setStunum(stunum);
        gr.setSturate(N_Utils.getIntegerDivideAndMulitiply(stunum, gstunum));
        setStudentName(list2, userMap);
        String stujson = stuJson(list2);
        gr.setStujson(stujson);
        rclassRankList.add(gr);
    }

    //考试报告--等级统计
    private void setDjTj(Integer examid, Integer gstunum, Map<Integer, String> userMap,
                         List<ERclassRank> rclassRankList, ERrank rrank,
                         String rankrange, String subjectid, Integer classid, List<ERstudent> list) {
        String rankname = rrank.getRankname();
        ERclassRank cr = new ERclassRank();
        cr.setExamid(examid);
        cr.setClassid(classid);
        cr.setSubjectid(subjectid);
        cr.setRanktype(rrank.getRanktype());
        cr.setRankname(rankname);
        List<ERstudent> list2;
        double finalMinscore = rrank.getMinscore();
        double finalMaxscore = rrank.getMaxscore();
        if (rankname.equals("A")) {
            list2 = list.stream().filter(s -> s.getScore().compareTo(finalMinscore) != -1).collect(Collectors.toList());
        } else {
            list2 = list.stream().filter(s -> s.getScore().compareTo(finalMinscore) != -1
                    && s.getScore().compareTo(finalMaxscore) == -1).collect(Collectors.toList());
        }
        cr.setRankrange(rankrange);
        int stunum = list2.size();
        cr.setStunum(stunum);
        cr.setSturate(N_Utils.getIntegerDivideAndMulitiply(stunum, gstunum));
        setStudentName(list2, userMap);
        String stujson = stuJson(list2);
        cr.setStujson(stujson);
        rclassRankList.add(cr);
    }

    //学生名单
    private String stuJson(List<ERstudent> list2) {
        List<Map> students = new ArrayList<>();
        for (ERstudent rstudent : list2) {
            Map s = new HashMap();
            s.put("studentname", rstudent.getStudentname());
            s.put("schoolrank", rstudent.getSchoolrank());
            s.put("score", rstudent.getScore());
            students.add(s);
        }
        return JSON.toJSONString(students);
    }

    //学生姓名处理
    private void setStudentName(List<ERstudent> list, Map<Integer, String> userMap) {
        list.forEach(s -> s.setStudentname(userMap.get(s.getStudentid())));
    }

    //计算学生分值
    private void setStuScore(Map<String, List<ERstudent>> gcollect, List<ERstudent> cstudents) {
        for (Map.Entry<String, List<ERstudent>> entry : gcollect.entrySet()) {
            List<ERstudent> list = entry.getValue();
            ERstudent rstudent = list.get(0);
            ERstudent rs = new ERstudent();
            rs.setClassid(rstudent.getClassid());
            rs.setSubjectid(rstudent.getSubjectid());
            rs.setStudentid(rstudent.getStudentid());
            rs.setClassrank(rstudent.getClassrank());
            rs.setSchoolrank(rstudent.getSchoolrank());
            rs.setZfSchoolRank(rstudent.getZfSchoolRank());
            rs.setScore(list.stream().mapToDouble(s -> s.getScore()).sum());
            cstudents.add(rs);
        }
    }

    //设置学生目标
    private void setStuGoal(List<ERstudent> stuRankGoals, ERstudent cs, Integer schoolrank) {
        String goalparam = "0.2";
        ERstudent rg = stuRankGoals.stream().filter(s -> s.getStudentid().equals(cs.getStudentid())
                && s.getSubjectid().equals(cs.getSubjectid())).findFirst().orElse(null);
        Integer goal = cs.getSchoolrank();
        Integer nextgoal = ExamUtil.getUserGroupGoalByParam(schoolrank, goalparam);
        Integer classrankpre = 0;
        if (rg != null) {
            goal = rg.getNextgoal();
            classrankpre = rg.getClassrank() - cs.getClassrank();
        }
        cs.setClassrankpre(classrankpre);
        cs.setGoal(goal);
        cs.setNextgoal(nextgoal);
    }

    //分数排名
    private void setRank(List<ERstudent> students, Map<String, Integer> rank, Integer code) {
        List<Map.Entry<Double, List<ERstudent>>> gslist2 = students.stream()
                                                                   .collect(Collectors.groupingBy(ERstudent::getScore)).entrySet()
                                                                   .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
        Integer index = 1;
        String key;
        for (Map.Entry<Double, List<ERstudent>> entry : gslist2) {
            for (ERstudent cgs : entry.getValue()) {
                Integer studentid = cgs.getStudentid();
                Integer classid = cgs.getClassid();
                String subjectid = cgs.getSubjectid();
                if (code == 1) {//学校学生
                    key = studentid.toString();
                } else if (code == 2) {//学校科目学生
                    key = subjectid + "_" + studentid;
                } else if (code == 3) {//班级学生
                    key = classid + "_" + studentid;
                } else {//班级科目学生
                    key = classid + "_" + subjectid + "_" + studentid;
                }
                rank.put(key, index);
            }
            index = index + entry.getValue().size();
        }
    }

    //处理班级试题作答详情和满分
    public void handleAnswerjson() {
        List<ERclassQuestion> list = eReportGenerateMapper.listAnswerJson();//获取未处理的学生作答情况
        List<Integer> examids = list.stream().map(l -> l.getExamid()).distinct().collect(Collectors.toList());
        List<EClass> classes = eReportGenerateMapper.listClassByExamIds(examids);//获取考试班级集合
        Map<String, Integer> classMap = classes.stream().collect(Collectors.toMap(
                c -> c.getExamid() + "_" + c.getClassid(), c -> c.getClassnum()));
        List<Future> futureList = new ArrayList<>();//来记录任务的完成情况，完成线程间的通信
        for (ERclassQuestion q : list) {
            Future<Boolean> future = updateClassQuestion(classMap, q);
            futureList.add(future);
        }

        ExamUtil.isAllDone(futureList);//线程是否执行完
    }

    //处理单个班级试题
    @Async("asyncPoolTaskExecutor")
    public Future<Boolean> updateClassQuestion(Map<String, Integer> classMap, ERclassQuestion q) {
        if (N_Utils.isEmptyInteger(q.getEptqid())) {
            Integer fullscorenum = eReportGenerateMapper.getFullscorenum(q);
            q.setFullscorenum(fullscorenum);
        }
        Integer stunum = classMap.get(q.getExamid() + "_" + q.getClassid());
        Map<String, Map> dafbmap = new HashMap<>();//答案分布
        Map<String, List<Map>> answer = JSON.parseObject(q.getAnswerjson(), Map.class);
        for (Map.Entry<String, List<Map>> entry : answer.entrySet()) {
            String key = entry.getKey();
            List<Map> students = entry.getValue();
            int num = students.size();
            Map dafb = new HashMap();
            dafb.put("students", students);
            dafb.put("num", num);
            dafb.put("numrate", N_Utils.getIntegerDivideAndMulitiply(num, stunum));
            dafbmap.put(key, dafb);
        }
        q.setAnswerjson(JSON.toJSONString(dafbmap));
        eReportGenerateMapper.updateClassQuestion(q);
        return new AsyncResult<>(true);
    }

    //处理学生违规试卷分析
    public void updateClassStuAction(){
        //获取所有违规试卷分析学生作答情况(已生成报告考试)
        List<EClassActionVo> list = eReportGenerateMapper.listBadQuesExam();
        if(N_Utils.isListNotEmpty(list)){

            Map<Integer,List<EClassActionVo>> exammap = list.stream().collect(Collectors.groupingBy(EClassActionVo::getExamid));
            for(Map.Entry<Integer,List<EClassActionVo>> map : exammap.entrySet()){
                //获取该次考试actiontype=3是否生成，如果已经生成，则跳过
                List<ERclassAction> action3 = eReportGenerateMapper.listBadQuesExam3(map.getKey());
                if(N_Utils.isListEmpty(action3)){

                    List<ERclassAction> cactlist = new ArrayList<>();
                    List<ERstudentAction> sactlist = new ArrayList<>();

                    //获取每次考试的情况
                    List<EClassActionVo> examlist = map.getValue();//包含每个班级每个学科

                    //每个科目下学生
                    Map<String,List<EClassActionVo>> subjectmap = examlist.stream().collect(Collectors.groupingBy(EClassActionVo::getSubjectid));

                    //每个班级下学生
                    Map<Integer,List<EClassActionVo>> classmap = examlist.stream().collect(Collectors.groupingBy(EClassActionVo::getClassid));

                    for(Map.Entry<Integer,List<EClassActionVo>> cmap : classmap.entrySet()){

                        List<Map> subjectlist = new ArrayList<>();
                        //班级下学科情况
                        Map<String,List<EClassActionVo>> csmap = cmap.getValue().stream().collect(Collectors.groupingBy(EClassActionVo::getSubjectid));
                        for(Map.Entry<String,List<EClassActionVo>> submap : csmap.entrySet()){
                            List<EClassActionVo> stuques = submap.getValue();
                            Map subject = new HashMap();
                            subject.put("subjectid",submap.getKey());
                            subject.put("subjectname", stuques.get(0).getSubjectname());
                            int num = submap.getValue().size();
                            Double nrate =  N_Utils.getIntegerDivideAndMulitiply(num, subjectmap.get(submap.getKey()).size());
                            subject.put("num",num);
                            subject.put("nrate",nrate);
                            List<Map> students = new ArrayList<>();
                            for(EClassActionVo s : stuques){
                                Map stu = new HashMap();
                                stu.put("studentid", s.getStudentid());
                                stu.put("num", s.getNum());
                                stu.put("studentname", s.getStudentname());
                                students.add(stu);
                            }
                            subject.put("students",students);
                            subjectlist.add(subject);
                        }

                        //计算班级情况
                        ERclassAction rclassAction = new ERclassAction();
                        rclassAction.setExamid(map.getKey());
                        rclassAction.setClassid(cmap.getKey());
                        rclassAction.setActiontype(3);
                        rclassAction.setSubjectjson(JSON.toJSONString(subjectlist));
                        cactlist.add(rclassAction);
                    }

                    //按照学生分组保存
                    Map<Integer,List<EClassActionVo>> stumap = examlist.stream().collect(Collectors.groupingBy(EClassActionVo::getStudentid));
                    for(Map.Entry<Integer,List<EClassActionVo>> sbm : stumap.entrySet()){
                        List<EClassActionVo> subs = sbm.getValue();
                        List<Map> stusubs = new ArrayList<>();
                        for(EClassActionVo c : subs){
                            Map stusub = new HashMap();
                            stusub.put("subjectid",c.getSubjectid());
                            stusub.put("subjectname",c.getSubjectname());
                            stusub.put("num",c.getNum());
                            stusubs.add(stusub);
                        }

                        ERstudentAction rstudentAction = new ERstudentAction();
                        rstudentAction.setExamid(map.getKey());
                        rstudentAction.setClassid(subs.get(0).getClassid());
                        rstudentAction.setStudentid(sbm.getKey());
                        rstudentAction.setActiontype(3);
                        rstudentAction.setSubjectjson(JSON.toJSONString(stusubs));
                        sactlist.add(rstudentAction);
                    }

                    if(N_Utils.isListNotEmpty(cactlist)){
                        eRclassActionMapper.insertList(cactlist);
                        eRstudentActionMapper.insertList(sactlist);
                    }

                }

            }

        }
    }

    //题型、试题、知识点
    @Transactional(rollbackFor = Exception.class)
    public void saveClassQuestions(Integer examid) throws Exception {
        List<Map> classes = eClassMapper.listByExamId(examid);
        Integer exammode = eReportGenerateMapper.getExamModeById(examid);
        List<Map> subjects = eReportGenerateMapper.listSubject(examid, exammode);
        EBase base = eBaseMapper.selectByPrimaryKey(examid);
        eReportGenerateQuestionService.setClassQuestion(examid, subjects, classes, base);

    }


}
