package yangtz.cs.liu.campus.vo.time;


import com.ruoyi.common.utils.StringUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import yangtz.cs.liu.campus.domain.time.SchoolTimeRule;
import yangtz.cs.liu.campus.mapper.time.SchoolTimeMapper;
import yangtz.cs.liu.campus.service.time.ISubjectChoose;
import yangtz.cs.liu.campus.service.time.IWeightCalc;

import java.util.*;

@Data
public class ClassScheduling {
    private Map<Integer, GradeInfo> gradeInfoMap;//基础信息           //输入信息,多个年级信息
//    private GradeInfo gradeInfo;//基础信息           //输入信息,单个年级信息
    private List<SchedulePositionInfo> udfFixedSubjectList;          //外部初始化 application主类中赋值了
    private List<SchedulePositionInfo> canNotSubjectList;    //指定位置不能安排某科目
    private Map<Integer, Map<Integer, Map<Integer, Map<Integer, SchedulePositionInfo>>>> scheduleInfos;//课表信息，年级：班级：周天：课节：课程  //最终输出
    private Map<String, Map<Integer, Map<Integer, SchedulePositionInfo>>> teacherSchedule;//老师课程安排  //中间数据
    private Map<Integer, Map<Integer, List<ScheduleClassInfo>>> scheduleClassInfo;//班级课程信息
    private Map<Integer, Map<Integer, Map<Integer, Map<Integer, List<SchedulingProcessInfo>>>>> scheduledInfo;//已经排课位置信息       //中间数据
    private Map<Integer, Integer> scheduledLesson;//已经安排的位置
    private Map<Integer, Map<Integer, Integer>> classFreeSpace;//班级剩余课节数
    private List<String> teacherList;//老师列表
    private Integer gradeCount = 0;//多少个年级
    private Integer classCount = 0;//多少个班级
    private Integer maxDayPerWeek = 0;//最大周天数（所有年级)
    private Integer maxLessonPerDay = 0;//最大节数 （所有年级)
    private Integer continueNum; //最多连课数
    private List<SchoolTimeRule>  schoolTimeRules; //规则
    private Integer grade;  //表示几年级
//    private Integer classNo; //表示几班
    private Integer amLesssonNum;   //上午课程数
    private Integer pmLesssonNum;   //下午课程数
    private Integer nightLesssonNum;   //晚自习课程数
    private Integer maxWeight = 0;
    private List<SchedulePositionInfo> onlyOneChoice;

    public ISubjectChoose iSubjectChoose;//科目自定义规则筛选
    public IWeightCalc iWeightCalc;//科目权重外部因素计算

    @Autowired private SchoolTimeMapper schoolTimeMapper;

    public boolean makeLessonTable() {
        //检查gradeInfo
        if (!this.checkInputGradeInfo(this.gradeInfoMap)) {  //给年级数，班级数，每周几天课，每天几节课赋值
            return false;
        }
        //检查课程是否可以排满
        if (!this.processNullPos(this.gradeInfoMap)) {
            return false;
        }
        //初始化老师课程安排信息   获取所有年级下，班级，所有科目的任课老师列表
        if (!initTeacherList(this.gradeInfoMap)) {
            return false;
        }
        //初始化老师任课信息
        if (!this.initTeacherLesson()) {
            return false;
        }
        //初始化课表信息  classFreeSpace//年级—>班级每个星期的课程数   scheduleInfos//年级—班级-星期-每天的SchedulePositionInfo
        if (!this.initLessonTableInfo(this.gradeInfoMap)) {
            return false;
        }
        //初始化中间排课过程信息   初始化 班级课程信息 和 已排课位置信息
        if (!this.initScheduldInfo(this.gradeInfoMap)) {
            return false;
        }

        this.scheduledLesson = new HashMap<Integer, Integer>();
        this.onlyOneChoice = new ArrayList<SchedulePositionInfo>();
        this.originalArrangeSubject(this.scheduledInfo);  //根据科目attributes进行初步设置
        //优先安排外部设定唯一的科目  //这里的是班会，在application中赋值了,即外部设定的唯一科目
        this.firstSetUdfOnlyOneSubject(this.udfFixedSubjectList);
        this.canNotSetUdfOnlyOneSubject(this.canNotSubjectList);//安排指定位置，和 指定位置不能安排科目
        this.firstSetOnlyChoice();
//        List<SchoolTimeRule> schoolTimeRules = schoolTimeMapper.selectRules();  //获取规则
        //先排早自习
        for (Map.Entry<Integer, GradeInfo> item : this.gradeInfoMap.entrySet()) {
            for (Map.Entry<Integer, ClassInfo> itemItem : item.getValue().getClassInfos().entrySet()) {
                for (Integer weekDay = 0; weekDay < item.getValue().getDayPerWeek(); weekDay++) {
                    Integer lessonNo = 0;
                    if (this.scheduledLesson.get(this.generateKey(item.getKey(), itemItem.getKey(), weekDay, lessonNo)) != null) {
                        continue;//已经排课
                    }  //fetchValidSubject 获取这节课的 可排科目列表，当天科目超过平均数，当天不排课
                    List<SchedulingProcessInfo> lessonValidSubjects = this.fetchValidSubject(item.getKey(), itemItem.getKey(), weekDay, lessonNo);
                    if (lessonValidSubjects.size() == 0) {
                        continue;
                    }

                    this.addScheduldPosition(item.getKey(), itemItem.getKey(), weekDay, lessonNo);
                    this.classFreeSpace.get(item.getKey()).put(itemItem.getKey(), this.classFreeSpace.get(item.getKey()).get(itemItem.getKey()).intValue() - 1);
                    //处理权重
                    this.calcWeights(item.getKey(), itemItem.getKey(), weekDay, lessonNo, lessonValidSubjects,schoolTimeRules);
                    //选择一门课
                    SchedulingProcessInfo selSubject = this.chooseOneSubject(lessonValidSubjects);
                    String subjectTeacher = this.fetchTeacherByKemuAndLesson(item.getKey(), itemItem.getKey(), selSubject.getScheduleClassInfo().getSubjectInfo().getCourseName());
                    //设置课程
                    this.setScheduleTable(item.getKey(), itemItem.getKey(), weekDay, lessonNo, selSubject);
                    //设置预排课信息
                    this.setPreScheduleInfo(item.getKey(), itemItem.getKey(), weekDay, lessonNo, subjectTeacher, selSubject);
                    //如果存在某个位置只有一门课可以安排，则直接安排
                    //this.firstSetOnlyChoice();
                }
            }
        }
        //先排晚自习
        for (Map.Entry<Integer, GradeInfo> item : this.gradeInfoMap.entrySet()) {
            for (Map.Entry<Integer, ClassInfo> itemItem : item.getValue().getClassInfos().entrySet()) {
                for (Integer weekDay = 0; weekDay < item.getValue().getDayPerWeek(); weekDay++) {
                    Integer lessonNo = this.maxLessonPerDay-this.nightLesssonNum;
                    //排课
                        /*
                        1、如果已经安排则跳过
                        2、筛选可排科目
                        3、处理科目权重
                        4、安排课程
                        5、预处理后续课程信息
                         */
                        if (this.scheduledLesson.get(this.generateKey(item.getKey(), itemItem.getKey(), weekDay, lessonNo)) != null) {
                            continue;//已经排课
                        }  //fetchValidSubject 获取这节课的 可排科目列表，当天科目超过平均数，当天不排课
                        List<SchedulingProcessInfo> lessonValidSubjects = this.fetchValidSubject(item.getKey(), itemItem.getKey(), weekDay, lessonNo);
                        if (lessonValidSubjects.size() == 0) {
                            continue;
                        }

                        this.addScheduldPosition(item.getKey(), itemItem.getKey(), weekDay, lessonNo);
                        this.classFreeSpace.get(item.getKey()).put(itemItem.getKey(), this.classFreeSpace.get(item.getKey()).get(itemItem.getKey()).intValue() - 1);
                        //处理权重
                        this.calcWeights(item.getKey(), itemItem.getKey(), weekDay, lessonNo, lessonValidSubjects,schoolTimeRules);
                        //选择一门课
                        SchedulingProcessInfo selSubject = this.chooseOneSubject(lessonValidSubjects);
                        String subjectTeacher = this.fetchTeacherByKemuAndLesson(item.getKey(), itemItem.getKey(), selSubject.getScheduleClassInfo().getSubjectInfo().getCourseName());
                        //设置课程
                        this.setScheduleTable(item.getKey(), itemItem.getKey(), weekDay, lessonNo, selSubject);
                        //设置预排课信息
                        this.setPreScheduleInfo(item.getKey(), itemItem.getKey(), weekDay, lessonNo, subjectTeacher, selSubject);
                        //如果存在某个位置只有一门课可以安排，则直接安排
                        //this.firstSetOnlyChoice();

                    //后一天不能和前一天晚自习重复
                    for(SchoolTimeRule schoolTimeRule : schoolTimeRules){
                        if(schoolTimeRule.getSort().equals("2") && schoolTimeRule.getIsUsed().equals("0")){
                            if(weekDay>=0 && weekDay<this.maxDayPerWeek-1){
                                List<SchedulingProcessInfo> processInfos = this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay+1).get(lessonNo);
                                for(Integer i = 0 ;i<processInfos.size();i++){
                                    SchedulingProcessInfo processInfo = processInfos.get(i);
                                    if (processInfo.getScheduleClassInfo().getSubjectInfo().equals(selSubject.getScheduleClassInfo().getSubjectInfo())) {
                                        this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay+1).get(lessonNo).get(i).setCannotSelReason(4);
                                        this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay+1).get(lessonNo).get(i).setCanSelect(false);
                                    }
                                }
                            }
                        }
                    }

                        //晚自习后面的课程得和晚自习第一节课相同
                            for(Integer i = 1 ;i<this.nightLesssonNum;i++){
                                //设置课程
                                this.setScheduleTable(item.getKey(), itemItem.getKey(), weekDay, lessonNo+i, selSubject);   //只循环到下午结束，晚自习随机分配
                                this.scheduledLesson.put(this.generateKey(item.getKey(), itemItem.getKey(), weekDay, lessonNo+i), 1);  //生成key
                                //设置预排课信息
                                this.setPreScheduleInfo(item.getKey(), itemItem.getKey(), weekDay, lessonNo+i, subjectTeacher, selSubject);
                            }
                }

                //班级课程安排完成后，如果有未排课区域，则做自动调课，保证在没有极端冲突的情况下，把课排满
//                this.autoMicroChangeLesson(item.getKey(), itemItem.getKey());
            }
        }
        //排白天科目
        for (Map.Entry<Integer, GradeInfo> item : this.gradeInfoMap.entrySet()) {
            for (Map.Entry<Integer, ClassInfo> itemItem : item.getValue().getClassInfos().entrySet()) {
                for (Integer weekDay = 0; weekDay < item.getValue().getDayPerWeek(); weekDay++) {
//                    for (Integer lessonNo = 0; lessonNo < item.getValue().getLessonPerDay()-this.nightLesssonNum+1; lessonNo++) { //从第一节课拍到晚自习第一节课
                    for (Integer lessonNo = 1; lessonNo < item.getValue().getLessonPerDay()-this.nightLesssonNum; lessonNo++) { //从第一节课拍到下午最后一节课

                            //排课
                        /*
                        1、如果已经安排则跳过
                        2、筛选可排科目
                        3、处理科目权重
                        4、安排课程
                        5、预处理后续课程信息
                         */
                        if (this.scheduledLesson.get(this.generateKey(item.getKey(), itemItem.getKey(), weekDay, lessonNo)) != null) {
                            continue;//已经排课
                        }

                        //上午，禁止跳课相同，例如第一节和第三节相同，第二节不同
                        for(SchoolTimeRule schoolTimeRule : schoolTimeRules){
                            if(schoolTimeRule.getSort().equals("3") && schoolTimeRule.getIsUsed().equals("0")){
                                if(lessonNo>2 && lessonNo<this.amLesssonNum){  //上午第三节课
                                    List<SchedulingProcessInfo> processInfos = this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo); //上午这节课可排科目
                                    SubjectInfo firstSubject = this.scheduleInfos.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo-1).getSubjectInfo();
                                    for(Integer i = 1;i<lessonNo-1;i++){ //获得上午这节课前面的所有科目
                                        SubjectInfo secondSubject = this.scheduleInfos.get(grade).get(itemItem.getKey()).get(weekDay).get(i).getSubjectInfo();
                                        for(Integer j = 0; j<processInfos.size(); j++){
                                            SubjectInfo chooseSubject = processInfos.get(j).getScheduleClassInfo().getSubjectInfo();
                                            if ((!chooseSubject.equals(firstSubject)) && chooseSubject.equals(secondSubject)) {
                                                this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo).get(j).setCannotSelReason(4);
                                                this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo).get(j).setCanSelect(false);
                                            }
                                        }
                                    }
                                }

                            }
                        }

                        //下午，禁止跳课相同，例如第一节和第三节相同，第二节不同
                        for(SchoolTimeRule schoolTimeRule : schoolTimeRules){
                            if(schoolTimeRule.getSort().equals("4") && schoolTimeRule.getIsUsed().equals("0")){
                                if(lessonNo>this.amLesssonNum+1 && lessonNo<this.amLesssonNum+this.pmLesssonNum){  //下午第三节课
                                    List<SchedulingProcessInfo> processInfos = this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo); //下午这节课可排科目
                                    SubjectInfo firstSubject = this.scheduleInfos.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo-1).getSubjectInfo();
                                    for(Integer i = this.amLesssonNum;i<lessonNo-1;i++){ //获得下午这节课前面的所有科目
                                        SubjectInfo secondSubject = this.scheduleInfos.get(grade).get(itemItem.getKey()).get(weekDay).get(i).getSubjectInfo();
                                        for(Integer j = 0; j<processInfos.size(); j++){
                                            SubjectInfo chooseSubject = processInfos.get(j).getScheduleClassInfo().getSubjectInfo();
                                            if (!chooseSubject.equals(firstSubject) && chooseSubject.equals(secondSubject)) {
                                                this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo).get(j).setCannotSelReason(4);
                                                this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo).get(j).setCanSelect(false);
                                            }
                                        }
                                    }
                                }

                            }
                        }


                        //从第三节课到下午倒数第二节课,连课不能超过2节课
                        if(lessonNo>1 && lessonNo<this.maxLessonPerDay-this.nightLesssonNum){
                            SubjectInfo firstSubject = this.scheduleInfos.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo-2).getSubjectInfo();
                            SubjectInfo secondSubject = this.scheduleInfos.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo-1).getSubjectInfo();
                            List<SchedulingProcessInfo> processInfos = this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo);
                            for(Integer i = 0 ;i<processInfos.size();i++){
                                SubjectInfo subjectInfo = processInfos.get(i).getScheduleClassInfo().getSubjectInfo();
                                if (subjectInfo.equals(firstSubject) && subjectInfo.equals(secondSubject)) {
                                    this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo).get(i).setCannotSelReason(4);
                                    this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(lessonNo).get(i).setCanSelect(false);
                                }
                            }




                        }
                        //fetchValidSubject 获取这节课的 可排科目列表，当天科目超过平均数，当天不排课
                        List<SchedulingProcessInfo> lessonValidSubjects = this.fetchValidSubject(item.getKey(), itemItem.getKey(), weekDay, lessonNo);
//                        if (iSubjectChoose != null) {  //iSubjectChoose 科目自定义筛选规则
//                            List<String> udfSubjects = iSubjectChoose.unSelectSubject(item.getKey(), itemItem.getKey(), weekDay, lessonNo);
//                            //合并两个科目列表
//                            this.mergeValidSubject(lessonValidSubjects, udfSubjects);
//                        }
                        if (lessonValidSubjects.size() == 0) {
                            continue;
                        }

                        this.addScheduldPosition(item.getKey(), itemItem.getKey(), weekDay, lessonNo);
                        this.classFreeSpace.get(item.getKey()).put(itemItem.getKey(), this.classFreeSpace.get(item.getKey()).get(itemItem.getKey()).intValue() - 1);
                        //处理权重
                        this.calcWeights(item.getKey(), itemItem.getKey(), weekDay, lessonNo, lessonValidSubjects,schoolTimeRules);
                        //选择一门课
                        SchedulingProcessInfo selSubject = this.chooseOneSubject(lessonValidSubjects);
                        String subjectTeacher = this.fetchTeacherByKemuAndLesson(item.getKey(), itemItem.getKey(), selSubject.getScheduleClassInfo().getSubjectInfo().getCourseName());
                        //设置课程
                        this.setScheduleTable(item.getKey(), itemItem.getKey(), weekDay, lessonNo, selSubject);
                        //设置预排课信息
                        this.setPreScheduleInfo(item.getKey(), itemItem.getKey(), weekDay, lessonNo, subjectTeacher, selSubject);
                        //如果存在某个位置只有一门课可以安排，则直接安排
                        //this.firstSetOnlyChoice();


                        for(SchoolTimeRule schoolTimeRule : schoolTimeRules){
                            if(schoolTimeRule.getSort().equals("1") && schoolTimeRule.getIsUsed().equals("0")){
                                //上午排课的，下午不能排课
                                if(lessonNo>0 && lessonNo<this.amLesssonNum){  //如果是上午的课
                                    for(Integer pm = this.amLesssonNum; pm<this.maxLessonPerDay - this.nightLesssonNum; pm++){  //下午课循环
                                        List<SchedulingProcessInfo> processInfos = this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(pm); //下午这节课可排科目
                                        for(Integer i = 0; i<processInfos.size(); i++){
                                            SchedulingProcessInfo processInfo = processInfos.get(i);
                                            if (processInfo.getScheduleClassInfo().getSubjectInfo().equals(selSubject.getScheduleClassInfo().getSubjectInfo())) {
                                                this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(pm).get(i).setCannotSelReason(4);
                                                this.scheduledInfo.get(grade).get(itemItem.getKey()).get(weekDay).get(pm).get(i).setCanSelect(false);
                                            }
                                        }
                                    }
                                }

                            }
                        }
                    }
                }

//                //班级课程安排完成后，如果有未排课区域，则做自动调课，保证在没有极端冲突的情况下，把课排满
//                this.autoMicroChangeLesson(item.getKey(), itemItem.getKey());
            }
        }
        //班级课程安排完成后，如果有未排课区域，则做自动调课，保证在没有极端冲突的情况下，把课排满
        this.autoMicroChangeLesson(grade, classCount);


        return true;
    }


    //根据科目attributes进行初步设置
    private void originalArrangeSubject(Map<Integer, Map<Integer, Map<Integer, Map<Integer, List<SchedulingProcessInfo>>>>> scheduledInfo) {
        if (StringUtils.isEmpty(scheduledInfo)) {
            return;
        }
        Map<Integer, Map<Integer, Map<Integer, List<SchedulingProcessInfo>>>> classScheduledInfo = scheduledInfo.get(this.grade);
        if (StringUtils.isEmpty(classScheduledInfo)) {
            return;
        }
        Map<Integer, Map<Integer, List<SchedulingProcessInfo>>> dayScheduledInfo = classScheduledInfo.get(this.classCount);
        if (StringUtils.isEmpty(dayScheduledInfo)) {
            return;
        }
        for(Integer day=0;day<this.maxDayPerWeek;day++){
            Map<Integer, List<SchedulingProcessInfo>> lessonScheduleInfo = dayScheduledInfo.get(day);
            if (StringUtils.isEmpty(lessonScheduleInfo)) {
                return;
            }
            for(Integer lesson=0;lesson<this.maxLessonPerDay;lesson++){
                List<SchedulingProcessInfo> processInfos = lessonScheduleInfo.get(lesson);
                for(SchedulingProcessInfo item : processInfos){   //科目循环
                    Integer attributes = item.getScheduleClassInfo().getSubjectInfo().getAttributes(); //科目类型
                    if (attributes.equals(1)){   //规则1：早晚自习为主课,全天可排
                        item.setCannotSelReason(0);// 4：外部设置不可排，把那节课除了指定的科目外，全设置不可排
                        item.setCanSelect(true);
                    }
                    if(lesson>0 && lesson<this.maxLessonPerDay && attributes.equals(2)){    //规则2：晚自习为主课  除早自习可排
                        item.setCannotSelReason(0);// 4：外部设置不可排，把那节课除了指定的科目外，全设置不可排
                        item.setCanSelect(true);
                    }
                    if(lesson>0 && lesson<(this.maxLessonPerDay-this.nightLesssonNum) && attributes.equals(3)){   //规则3：上下午排课
                        item.setCannotSelReason(0);// 4：外部设置不可排，把那节课除了指定的科目外，全设置不可排
                        item.setCanSelect(true);
                    }
                    if(lesson>=this.amLesssonNum && lesson<(this.maxLessonPerDay-this.nightLesssonNum) && attributes.equals(4)){   //规则4：下午排课
                        item.setCannotSelReason(0);// 4：外部设置不可排，把那节课除了指定的科目外，全设置不可排
                        item.setCanSelect(true);
                    }
                }


            }
        }
//        for (SchedulePositionInfo info : positionInfos) {
//            //设置对应位置的科目    scheduledInfo表示每节课可以排的科目;已经排课位置信息,此时还是初始化数据
//            //每节课可排科目for循环
//            for (SchedulingProcessInfo item : this.scheduledInfo.get(info.getGrade()).get(info.getClassNo()).get(info.getWeekDay()).get(info.getSeqNo())) {
//                if (!(info.getSubjectInfo().getSubjectCode()).equals(item.getScheduleClassInfo().getSubjectInfo().getSubjectCode())) {
//                    item.setCannotSelReason(4);// 4：外部设置不可排，把那节课除了指定的科目外，全设置不可排
//                    item.setCanSelect(false);
//                }
//            }
//
//            //scheduledLesson;//已经安排的位置
//            if (this.scheduledLesson.get(this.generateKey(info.getGrade(), info.getClassNo(), info.getWeekDay(), info.getSeqNo())) == null) {
//                this.setOnlyOneSubjectChoice(info.getGrade(), info.getClassNo(), info.getWeekDay(), info.getSeqNo());
//            }
//        }
    }



    //指定位置 安排某课
    private void firstSetUdfOnlyOneSubject(List<SchedulePositionInfo> positionInfos) {
        if (positionInfos == null) {
            return;
        }
        for (SchedulePositionInfo info : positionInfos) {
            //设置对应位置的科目    scheduledInfo表示每节课可以排的科目;已经排课位置信息,此时还是初始化数据
            //每节课可排科目for循环
            for (SchedulingProcessInfo item : this.scheduledInfo.get(info.getGrade()).get(info.getClassNo()).get(info.getWeekDay()).get(info.getSeqNo())) {
                if (!(info.getSubjectInfo().getCourseId()).equals(item.getScheduleClassInfo().getSubjectInfo().getCourseId())) {
                    item.setCannotSelReason(4);// 4：外部设置不可排，把那节课除了指定的科目外，全设置不可排
                    item.setCanSelect(false);
                }
                if ((info.getSubjectInfo().getCourseId()).equals(item.getScheduleClassInfo().getSubjectInfo().getCourseId())) {
                    item.setCannotSelReason(0);// 4：外部设置不可排，把那节课除了指定的科目外，全设置不可排
                    item.setCanSelect(true);
                }
            }

            //scheduledLesson;//已经安排的位置
            if (this.scheduledLesson.get(this.generateKey(info.getGrade(), info.getClassNo(), info.getWeekDay(), info.getSeqNo())) == null) {
                this.setOnlyOneSubjectChoice(info.getGrade(), info.getClassNo(), info.getWeekDay(), info.getSeqNo());
            }
        }
    }

    //指定位置不能安排
    private void canNotSetUdfOnlyOneSubject(List<SchedulePositionInfo> positionInfos) {
        if (positionInfos == null) {
            return;
        }
        for (SchedulePositionInfo info : positionInfos) {
            //设置对应位置的科目    scheduledInfo表示每节课可以排的科目;已经排课位置信息,此时还是初始化数据
            //每节课可排科目for循环
            for (SchedulingProcessInfo item : this.scheduledInfo.get(info.getGrade()).get(info.getClassNo()).get(info.getWeekDay()).get(info.getSeqNo())) {
                if ((info.getSubjectInfo().getCourseId()).equals(item.getScheduleClassInfo().getSubjectInfo().getCourseId())) {
                    item.setCannotSelReason(4);// 4：外部设置不可排，把那节课除了指定的科目外，全设置不可排
                    item.setCanSelect(false);
                }
            }
            //scheduledLesson;//已经安排的位置
            if (this.scheduledLesson.get(this.generateKey(info.getGrade(), info.getClassNo(), info.getWeekDay(), info.getSeqNo())) == null) {
                this.setOnlyOneSubjectChoice(info.getGrade(), info.getClassNo(), info.getWeekDay(), info.getSeqNo());
            }
        }
    }

    //未安排完的科目
    private List<SchedulingProcessInfo> fetchMicroChangeSubjectCanSelect(Integer grade, Integer classNo, Integer weekDay, Integer lessonNo) {
        List<SchedulingProcessInfo> result = new ArrayList<SchedulingProcessInfo>();
        for (SchedulingProcessInfo item : this.scheduledInfo.get(grade).get(classNo).get(weekDay).get(lessonNo)) {
            if (item.getScheduleClassInfo().getUnUsedCount() > 0) {
                result.add(item);
            }
        }
        return result;
    }

    private boolean isSubjectInScheduleProcessList(SubjectInfo info, List<SchedulingProcessInfo> infos) {
        for (SchedulingProcessInfo item : infos) {
            if (item.getScheduleClassInfo().getSubjectInfo().equals(info)) {
                return true;
            }
        }
        return false;
    }

    private boolean isInfoInScheduleProcessList(SchedulingProcessInfo info, List<SchedulingProcessInfo> infos) {
        for (SchedulingProcessInfo item : infos) {
            if (item.equals(info)) {
                return true;
            }
        }
        return false;
    }

    //此位置可以安排的科目
    //考虑一个老师不给两个半上课则exceptReason=false   不考虑则exceptReason=true
    private List<SchedulingProcessInfo> fetchMicroChangeSubjectValids(Integer grade, Integer classNo, Integer weekDay, Integer lessonNo, boolean exceptReason) {
        List<SchedulingProcessInfo> result = new ArrayList<SchedulingProcessInfo>();
        for (SchedulingProcessInfo item : this.scheduledInfo.get(grade).get(classNo).get(weekDay).get(lessonNo)) {
            if (item.getScheduleClassInfo().getSubjectInfo().getCourseId() == 0) {
                continue;
            }
            Integer reason = item.getCannotSelReason();
            if (reason != 1 || exceptReason) {
                int cntDayLesson = 0;
                for (Integer idx = 0; idx < this.gradeInfoMap.get(grade).getLessonPerDay(); idx++) {
                    if (idx.equals(lessonNo)) {
                        continue;
                    }
                    if (this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(idx).getSubjectInfo() == null) {
                        continue;
                    }
                    if (this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(idx).getSubjectInfo().equals(item.getScheduleClassInfo().getSubjectInfo())) {
                        cntDayLesson++;
                    }
                }
                if (cntDayLesson >= item.getScheduleClassInfo().getTotalCount() / 1.0 / this.gradeInfoMap.get(grade).getDayPerWeek()) {
                    continue;
                }
                result.add(item);
            }
        }
        return result;
    }


    //调换同一班级两个位置的课程
    private boolean changeLesson(Integer grade, Integer classNo, Integer SourceWeekDay, Integer SourceLessonNo, Integer DestWeekDay, Integer DestLessonNo,
                                 SchedulePositionInfo source, SchedulePositionInfo dest) {
        if (source.getSubjectInfo().equals(dest.getSubjectInfo())) {
            return false;
        }
        //获取源位置可以安排的科目列表
        List<SchedulingProcessInfo> sourceCanSelectSubjects = this.fetchMicroChangeSubjectValids(grade, classNo, SourceWeekDay, SourceLessonNo, false);
        //获取目标位置可以安排的科目列表
        List<SchedulingProcessInfo> destCanSelectSubjects = this.fetchMicroChangeSubjectValids(grade, classNo, DestWeekDay, DestLessonNo, false);
        if (SourceWeekDay.equals(DestWeekDay)) {
            for (SchedulingProcessInfo item : this.scheduledInfo.get(grade).get(classNo).get(SourceWeekDay).get(SourceLessonNo)) {
                if (item.getScheduleClassInfo().getSubjectInfo().equals(dest.getSubjectInfo())) {
                    sourceCanSelectSubjects.add(item);
                    break;
                }
            }
        }
        if (sourceCanSelectSubjects.size() <= 0 || destCanSelectSubjects.size() <= 0) {
            return false;
        }
        boolean canChangeDestPos = false;
        boolean canChangeSourcePos = false;
        for (SchedulingProcessInfo subjectS : sourceCanSelectSubjects) {//判断目标位置科目是否可以放在源位置
            if (subjectS.getScheduleClassInfo().getSubjectInfo().equals(dest.getSubjectInfo())) {
                canChangeSourcePos = true;
                break;
            }
        }
        //canChangeSubjects包含item,已经排好的位置可以安排没有安排满的课程
        for (SchedulingProcessInfo subjectD : destCanSelectSubjects) {
            if (subjectD.getScheduleClassInfo().getSubjectInfo().equals(source.getSubjectInfo())) {
                canChangeDestPos = true;
                break;
            }
        }
        if (!canChangeDestPos || !canChangeSourcePos) {
            return false;
        }
        return true;
    }

    //自动微调
    private void autoMicroChangeLesson(Integer grade, Integer classNo) {
        //获取未排完的科目列表   所有遍历找一个空缺位置可以排的科目，且该科目可以排这个未排完的科目，最后匹配不了的，直接排下
        //找到未拍完科目
        List<SchedulingProcessInfo> unFixedSubjects = this.fetchMicroChangeSubjectCanSelect(grade, classNo, 0, 0);

        for(int sub =0 ;sub<unFixedSubjects.size(); sub++){//未排科目循环
            SchedulingProcessInfo schedulingProcessInfo = unFixedSubjects.get(sub);
            SubjectInfo subjectInfo = schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo();  //未排完的科目
            Integer num = schedulingProcessInfo.getScheduleClassInfo().getUnUsedCount();  //该科目未排完科目数
                for(Integer i = 0;i<num;i++){   //该科目下,未排课数循环
//                    if(num == 0){
//                        break;
//                    }
                    for(Integer day = 0; day<this.maxDayPerWeek; day++){
                        if(num == 0){
                            break;
                        }
                        for(Integer lessonNo = 0;lessonNo<this.amLesssonNum+this.pmLesssonNum;lessonNo++){  //找到未排课的 位置
                            if(num == 0){
                                break;
                            }
                            if (this.scheduledLesson.get(this.generateKey(grade, classNo, day, lessonNo)) != null) {
                                continue;
                            }
                            //这个位置所有科目List
                            List<SchedulingProcessInfo> schedulingProcessInfos = this.scheduledInfo.get(grade).get(classNo).get(day).get(lessonNo);
                            for(SchedulingProcessInfo processInfo : schedulingProcessInfos){
                                if(num == 0){
                                    break;
                                }
                                if(processInfo.isCanSelect()){
                                    //空缺位置的可排科目
                                    SubjectInfo canSubject = processInfo.getScheduleClassInfo().getSubjectInfo();
                                    //循环遍历所有 已排课位置
                                    for(Integer day2 = 0; day2<this.maxDayPerWeek; day2++){
                                        if(num == 0){
                                            break;
                                        }
                                        for(Integer lessonNo2 = 1;lessonNo2<this.amLesssonNum+this.pmLesssonNum;lessonNo2++){
                                            if(num == 0){
                                                break;
                                            }
                                            if (this.scheduledLesson.get(this.generateKey(grade, classNo, day2, lessonNo2)) == null) {
                                                continue;
                                            }
                                            SubjectInfo doneSubjectInfo = this.scheduleInfos.get(grade).get(classNo).get(day2).get(lessonNo2).getSubjectInfo(); //遍历位置已经安排的科目
                                            if(canSubject.getCourseId().equals(doneSubjectInfo.getCourseId())){ //空缺可排科目 与 已排位置的科目相同
                                                List<SchedulingProcessInfo> doneSchedulingProcessInfos = this.scheduledInfo.get(grade).get(classNo).get(day2).get(lessonNo2);//已排位置的所有科目List
                                                if(num == 0){
                                                    break;
                                                }
                                                for(SchedulingProcessInfo doneProcessInfo : doneSchedulingProcessInfos){
                                                    //获取已排位置 的 可排科目
                                                    if(doneProcessInfo.isCanSelect()){
                                                        SubjectInfo doneCanSubject = doneProcessInfo.getScheduleClassInfo().getSubjectInfo();
                                                        //已排位置的可排科目 与 未排课科目 相同
                                                        if(doneCanSubject.getCourseId().equals(subjectInfo.getCourseId())){
                                                            //已排位置中安排安排未排科目
                                                           this.scheduleInfos.get(grade).get(classNo).get(day2).get(lessonNo2).setSubjectInfo(subjectInfo);
                                                           //未排科目-1
//                                                            //减少本班剩余课节的freeSpace
//                                                           this.reduceSelfFreeSpaceCount(grade, classNo, day2, lessonNo2, null, null);
//                                                            //减少可排课节数
//                                                           this.reduceSelfCanUseCount(grade, classNo, null, null, null, schedulingProcessInfo);
                                                            unFixedSubjects.get(sub).getScheduleClassInfo().setUnUsedCount(unFixedSubjects.get(sub).getScheduleClassInfo().getUnUsedCount()-1);
                                                            if(unFixedSubjects.get(sub).getScheduleClassInfo().getUnUsedCount() == 0){
//                                                                unFixedSubjects.remove(sub);
                                                                unFixedSubjects.get(sub).setScheduleClassInfo(null);
                                                            }
                                                            //未排课位置 安排 和前面 已排课科目
                                                            this.scheduleInfos.get(grade).get(classNo).get(day).get(lessonNo).setSubjectInfo(doneSubjectInfo);
                                                            this.scheduledLesson.put(this.generateKey(grade, classNo, day, lessonNo), 1);
                                                            num--;
                                                            if(num == 0){
                                                                break;
                                                            }
                                                        }
                                                    }
                                                }

                                            }

                                        }

                                    }
                                }

                            }

                        }
                    }

                }

        }

        //微调后还存在 未排课科目 强制排课
        if(unFixedSubjects.size()>0){
            for(Integer sub =0 ;sub<unFixedSubjects.size(); sub++){
                SchedulingProcessInfo schedulingProcessInfo = unFixedSubjects.get(sub);
                if(StringUtils.isNotNull(schedulingProcessInfo.getScheduleClassInfo())){
                    Integer num = schedulingProcessInfo.getScheduleClassInfo().getUnUsedCount();
                    for(Integer i = 0;i<num;i++){   //该科目下,未排课数循环
                        SubjectInfo subjectInfo = schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo();  //未排完的科目
                        Integer flag = 0;
                        for(Integer day = 0; day<this.maxDayPerWeek; day++){
                            if(flag.equals(num)){
                                break;
                            }
                            for(Integer lessonNo = 1;lessonNo<this.amLesssonNum+this.pmLesssonNum;lessonNo++){  //找到未排课的 位置
                                if (this.scheduledLesson.get(this.generateKey(grade, classNo, day, lessonNo)) != null) {
                                    continue;
                                }
                                this.scheduleInfos.get(grade).get(classNo).get(day).get(lessonNo).setSubjectInfo(subjectInfo);
                                this.scheduledLesson.put(this.generateKey(grade, classNo, day, lessonNo), 1);
                                flag++;
                                if(flag.equals(num)){
                                    break;
                                }
                            }
                        }
                    }
                }

            }



        }


//        for (Integer weekDay = 0; weekDay < this.maxDayPerWeek; weekDay++) {
//            for (Integer lessonNo = 0; lessonNo < this.maxLessonPerDay; lessonNo++) {
//                if (this.scheduledLesson.get(this.generateKey(grade, classNo, weekDay, lessonNo)) != null) {
//                    continue;
//                }
//                //获取未排完的科目列表   所有遍历找一个空缺位置可以排的科目，且该科目可以排这个未排完的科目，最后匹配不了的，直接排下
//                List<SchedulingProcessInfo> unFixedSubjects = this.fetchMicroChangeSubjectCanSelect(grade, classNo, weekDay, lessonNo);
//
//                //遍历科目
//                boolean canBreak = false;
//                for (SchedulingProcessInfo subjectC : unFixedSubjects) {
//                    //遍历预备调换位置（调换下午的课程）
//                    for (Integer weekDay1 = 0; weekDay1 < this.maxDayPerWeek; weekDay1++) {//遍历待替换的位置
//                        for (Integer lessonNo1 = 1; lessonNo1 < this.maxLessonPerDay; lessonNo1++) {
//
//
//                            SchedulePositionInfo source = new SchedulePositionInfo(grade, classNo, weekDay, lessonNo, subjectC.getScheduleClassInfo().getSubjectInfo(),
//                                    this.fetchTeacherByKemuAndLesson(grade, classNo, subjectC.getScheduleClassInfo().getSubjectInfo().getCourseName()));
//                            if (this.changeLesson(grade, classNo, weekDay, lessonNo, weekDay1, lessonNo1,
//                                    source,
//                                    this.scheduleInfos.get(grade).get(classNo).get(weekDay1).get(lessonNo1))) {
//
//                                this.setScheduleTable(grade, classNo, weekDay, lessonNo, this.scheduleInfos.get(grade).get(classNo).get(weekDay1).get(lessonNo1));
//                                this.setScheduleTable(grade, classNo, weekDay1, lessonNo1, source);
//
//                                this.reduceSelfCanUseCount(grade, classNo, weekDay, lessonNo,
//                                        this.fetchTeacherByKemuAndLesson(grade, classNo, subjectC.getScheduleClassInfo().getSubjectInfo().getCourseName())
//                                        , subjectC);
//
//                                canBreak = true;
//                                break;
//                            }
//                        }
//                        if (canBreak) {
//                            break;
//                        }
//                    }
//                }
//            }
//        }
//        //找到未拍完科目
//        List<SchedulingProcessInfo> unFixedSubjects = this.fetchMicroChangeSubjectCanSelect(grade, classNo, 0, 0);
//        //微调后还存在 未排课科目 强制排课
//        if(unFixedSubjects.size()>0){
//            for(Integer sub =0 ;sub<unFixedSubjects.size(); sub++){
//                SchedulingProcessInfo schedulingProcessInfo = unFixedSubjects.get(sub);
//                Integer num = schedulingProcessInfo.getScheduleClassInfo().getUnUsedCount();
//                for(Integer i = 0;i<num;i++){   //该科目下,未排课数循环
//                    SubjectInfo subjectInfo = schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo();  //未排完的科目
//                    for(Integer day = 0; day<this.maxDayPerWeek; day++){
//                        for(Integer lessonNo = 1;lessonNo<this.amLesssonNum+this.pmLesssonNum;lessonNo++){  //找到未排课的 位置
//                            if (this.scheduledLesson.get(this.generateKey(grade, classNo, day, lessonNo)) != null) {
//                                continue;
//                            }
//                            this.scheduleInfos.get(grade).get(classNo).get(day).get(lessonNo).setSubjectInfo(subjectInfo);
//                        }
//                    }
//
//                }
//            }
//
//
//
//        }

    }

    //优先安排只有一门可排的情况
    private void firstSetOnlyChoice() {
        /*
        1、遍历只有一个可选的位置列表
        2、设置课程
         */
        if (this.onlyOneChoice.size() <= 0) {
            return;
        }
        //for (SchedulePositionInfo item : this.onlyOneChoice) {
        SchedulePositionInfo item = this.onlyOneChoice.get(0);
        this.addScheduldPosition(item.getGrade(), item.getClassNo(), item.getWeekDay(), item.getSeqNo());
        SchedulingProcessInfo subject = null;

        String subjectTeacher = this.fetchTeacherByKemuAndLesson(item.getGrade(), item.getClassNo(), item.getSubjectInfo().getCourseName());
        //设置课程
        for (SchedulingProcessInfo info : this.scheduledInfo.get(item.getGrade()).get(item.getClassNo()).get(item.getWeekDay())
                .get(item.getSeqNo())) {
            if (info.getScheduleClassInfo().getSubjectInfo().equals(item.getSubjectInfo())) {
                subject = info;
                this.setScheduleTable(item.getGrade(), item.getClassNo(), item.getWeekDay(), item.getSeqNo(), info);
                break;
            }
        }
        //设置预排课信息
        this.onlyOneChoice.remove(item);
        this.setPreScheduleInfo(item.getGrade(), item.getClassNo(), item.getWeekDay(), item.getSeqNo(), subjectTeacher, subject);
        this.firstSetOnlyChoice();
    }

    //设置预排课过程信息
    private void setPreScheduleInfo(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, String teacher, SchedulingProcessInfo schedulingProcessInfo) {
        /*
        1、减少可排课程的课节数
        2、安排老师课程
        3、处理其他位置可排课程信息
        4、计算每个科目剩余可排课节数
        5、增加已排位置记录
         */
        for (Map.Entry<Integer, Map<Integer, Map<Integer, Map<Integer, SchedulePositionInfo>>>> item : this.scheduleInfos.entrySet()) {
            for (Map.Entry<Integer, Map<Integer, Map<Integer, SchedulePositionInfo>>> itemItem : item.getValue().entrySet()) {
                //1、减少其他班级本位置同老师科目的freeSpace
                if ((item.getKey() > grade) || (item.getKey().equals(grade) && itemItem.getKey() > classNo)) {
                    this.reduceFreeSpaceCount(item.getKey(), itemItem.getKey(), weekDay, lesssonNo, teacher, schedulingProcessInfo);
                }
                //记录不能排课的原因（同老师其他位置上课，导致不能在本节安排）
            }
        }

        //减少本班剩余课节的freeSpace
        this.reduceSelfFreeSpaceCount(grade, classNo, weekDay, lesssonNo, teacher, schedulingProcessInfo);
        //减少可排课节数
        this.reduceSelfCanUseCount(grade, classNo, weekDay, lesssonNo, teacher, schedulingProcessInfo);
        //处理老师课表
        this.recordTeacherSchedule(grade, classNo, weekDay, lesssonNo, teacher, schedulingProcessInfo);
        //处理各个位置科目可以选择情况
        this.processScheduleSubjectInfo(grade, classNo, weekDay, lesssonNo, teacher);
    }

    //处理单个位置可选科目情况
    private void processScheduleSubjectInfo(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, String teacher) {
        for (Map.Entry<Integer, Map<Integer, Map<Integer, Map<Integer, SchedulePositionInfo>>>> item : this.scheduleInfos.entrySet()) {
            for (Map.Entry<Integer, Map<Integer, Map<Integer, SchedulePositionInfo>>> itemItem : item.getValue().entrySet()) {
                for (Map.Entry<Integer, Map<Integer, SchedulePositionInfo>> itemItemItem : itemItem.getValue().entrySet()) {
                    for (Map.Entry<Integer, SchedulePositionInfo> itemItemItemItem : itemItemItem.getValue().entrySet()) {
                        //处理本节课以外的所有位置
                        if (item.getKey().equals(grade) && itemItem.getKey().equals(classNo) &&
                                itemItemItem.getKey().equals(weekDay) && itemItemItemItem.getKey().equals(lesssonNo)) {
                            continue;
                        }
                        //检查科目列表
                        for (SchedulingProcessInfo info : this.scheduledInfo.get(item.getKey()).get(itemItem.getKey())
                                .get(itemItemItem.getKey()).get(itemItemItemItem.getKey())) {
                            //如果本门课此位置不可排 则设置为1.如果可已经拍完，则设置为2
                            if (info.getScheduleClassInfo().getCannotSetPosMap().get(this.generateKey(
                                    item.getKey(), itemItem.getKey(), itemItemItem.getKey(), itemItemItemItem.getKey()
                            )) != null) {
                                info.setCannotSelReason(1);
                                info.setCanSelect(false);
                            }

                            //如果此科目的老师和已经安排的科目一直，则设置position
                            if (weekDay.equals(itemItemItem.getKey()) && lesssonNo.equals(itemItemItemItem.getKey())) {
                                if (teacher.equals(this.fetchTeacherByKemuAndLesson(item.getKey(), itemItem.getKey(), info.getScheduleClassInfo().getSubjectInfo().getCourseName()))) {
                                    info.setPositionInfo(new SchedulePositionInfo(grade, classNo, weekDay, lesssonNo, info.getScheduleClassInfo().getSubjectInfo(), teacher));
                                }
                            }

                            if (info.getCannotSelReason() == 0) {
//                                if (info.getScheduleClassInfo().getUnUsedCount() == 0) {
//                                    info.setCannotSelReason(2);
//                                    info.setCanSelect(false);
//                                }
                                if (info.getScheduleClassInfo().getFreeSpace() <= 0) {//无可排位置
                                    info.setCannotSelReason(3);
                                    info.setCanSelect(false);
                                }
                            }
                        }
                        //如果此位置只有一门课可以选择
                        if (this.scheduledLesson.get(this.generateKey(item.getKey(), itemItem.getKey(), itemItemItem.getKey(), itemItemItemItem.getKey())) == null) {
                            this.setOnlyOneSubjectChoice(item.getKey(), itemItem.getKey(), itemItemItem.getKey(), itemItemItemItem.getKey());
                        }
                    }
                }
            }
        }
    }

    //减少科目可安排课节数
    private void reduceSelfCanUseCount(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, String teacher, SchedulingProcessInfo schedulingProcessInfo) {
        for (ScheduleClassInfo subject : this.scheduleClassInfo.get(grade).get(classNo)) {
            //同老师，则减少可排位置数
            if (subject.getSubjectInfo().equals(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo())) {
                subject.setUnUsedCount(subject.getUnUsedCount() - 1);
            }
        }
    }

    //减少本班可排区间数
    private void reduceSelfFreeSpaceCount(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, String teacher, SchedulingProcessInfo schedulingProcessInfo) {
        for (ScheduleClassInfo subject : this.scheduleClassInfo.get(grade).get(classNo)) {
            //同老师，则减少可排位置数
            if (subject.getCannotSetPosMap().get(this.generateKey(grade, classNo, weekDay, lesssonNo)) == null) {
                subject.setFreeSpace(subject.getFreeSpace() - 1);
            }
        }
    }


    //减少其他班可排区间数
    private void reduceFreeSpaceCount(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, String teacher, SchedulingProcessInfo schedulingProcessInfo) {
        for (ScheduleClassInfo subject : this.scheduleClassInfo.get(grade).get(classNo)) {
            //同老师，则减少可排位置数
            if (teacher.equals(this.fetchTeacherByKemuAndLesson(grade, classNo, subject.getSubjectInfo().getCourseName()))) {
                subject.setFreeSpace(subject.getFreeSpace() - 1);
                subject.getCannotSetPosMap().put(this.generateKey(grade, classNo, weekDay, lesssonNo),
                        new SchedulePositionInfo(grade, classNo, weekDay, lesssonNo, null, null));
            }
        }
    }

    //设置只有一门可选的位置
    private void setOnlyOneSubjectChoice(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo) {
        Integer subjectCount = 0;
        SubjectInfo choice = null;
        for (SchedulingProcessInfo subject : this.scheduledInfo.get(grade).get(classNo).get(weekDay).get(lesssonNo)) {
            if (subject.getCannotSelReason() == 0) {
                choice = subject.getScheduleClassInfo().getSubjectInfo();
                subjectCount++;
            }
        }
        if (subjectCount > 1) {
            return;
        }
        for (SchedulePositionInfo item : this.onlyOneChoice) {
            if (item.getGrade().equals(grade) && item.getClassNo().equals(classNo) && item.getWeekDay().equals(weekDay) && item.getSeqNo().equals(lesssonNo)) {
                //无课可选，则从中移除
                if (subjectCount == 0) {
                    this.onlyOneChoice.remove(item);
                }
                return;
            }
        }
        if (subjectCount == 1) {
            //检查是否已经在列表
            this.onlyOneChoice.add(new SchedulePositionInfo(grade, classNo, weekDay, lesssonNo, choice,
                    this.fetchTeacherByKemuAndLesson(grade, classNo, choice.getCourseName())));
        }
    }

    //老师课表
    private void recordTeacherSchedule(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, String teacher, SchedulingProcessInfo schedulingProcessInfo) {
        this.teacherSchedule.get(teacher).get(weekDay).get(lesssonNo).setGrade(grade);
        this.teacherSchedule.get(teacher).get(weekDay).get(lesssonNo).setClassNo(classNo);
        this.teacherSchedule.get(teacher).get(weekDay).get(lesssonNo).setWeekDay(weekDay);
        this.teacherSchedule.get(teacher).get(weekDay).get(lesssonNo).setSeqNo(lesssonNo);
        this.teacherSchedule.get(teacher).get(weekDay).get(lesssonNo).setSubjectInfo(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo());
    }

    private void addScheduldPosition(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo) {
        this.scheduledLesson.put(this.generateKey(grade, classNo, weekDay, lesssonNo), 1);
    }

    //设置课程
    private void setScheduleTable(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, SchedulingProcessInfo schedulingProcessInfo) {
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setGrade(grade);
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setClassNo(classNo);
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setWeekDay(weekDay);
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setSeqNo(lesssonNo);
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setSubjectInfo(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo());
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setTeacher(this.fetchTeacherByKemuAndLesson(grade, classNo,
                schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo().getCourseName()));
    }

    //设置课程 override
    private void setScheduleTable(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, SchedulePositionInfo schedulePositionInfo) {
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setGrade(grade);
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setClassNo(classNo);
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setWeekDay(weekDay);
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setSeqNo(lesssonNo);
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setSubjectInfo(schedulePositionInfo.getSubjectInfo());
        this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo).setTeacher(schedulePositionInfo.getTeacher());
    }

    //根据权重选择一门课
    private SchedulingProcessInfo chooseOneSubject(List<SchedulingProcessInfo> schedulingProcessInfos) {
        /*
        1、选择最大的权重
        2、获取最大的权重列表
        3、从其中选择一门课
         */
        List<SchedulingProcessInfo> canChooseSubjects = new ArrayList<SchedulingProcessInfo>();
        for (SchedulingProcessInfo item : schedulingProcessInfos) {
            if (item.getWeights().equals(this.maxWeight)) {
                canChooseSubjects.add(item);
            }
        }
        return canChooseSubjects.get(this.fetchRandomInt(canChooseSubjects.size()));  //如果多个科目都满足，则随机选一个
    }

    //获取随机数
    private Integer fetchRandomInt(Integer maxValue) {
        Random r = new Random();
        return r.nextInt(maxValue);
    }

    //计算所有科目的权重
    private void calcWeights(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, List<SchedulingProcessInfo> schedulingProcessInfos,List<SchoolTimeRule> schoolTimeRules) {
        this.maxWeight = 0;
        for (SchedulingProcessInfo item : schedulingProcessInfos) {
            Integer wPlus = this.calcWeight(grade, classNo, weekDay, lesssonNo, schedulingProcessInfos.size(), item,schoolTimeRules);
            item.setWeights(item.getWeights() + wPlus);
            if (item.getWeights() > this.maxWeight) {
                this.maxWeight = item.getWeights();
            }
        }
    }

    //计算每个科目的权重
    private Integer calcWeight(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, Integer subjectCount, SchedulingProcessInfo schedulingProcessInfo,List<SchoolTimeRule> schoolTimeRules) {
        Integer result = 0;
        /*
         * 1、计算上下午主副课权重，课程位置、科目、上下午
         * 2、计算连堂权重          尚未安排的科目数、当前天数、已经安排的科目数
         * 3、计算平均分配规则权重  平均天课节  未安排的平均天课节
         * 4、计算可排位置比重权重             可排位置数量、阶梯权重
         * 5、计算从未安排过的科目权重         科目已经安排的数量
         * 6、计算老师平均安排权重             当天老师课节数、平均课节数
         * 7、计算自定义规则权重
         * */
        //第一节主课权重统一
//        if (lesssonNo < 3) {
//            if (schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo().getAttributes() == 1) {
//                result = WeightDefines.SUBJECT_FIRST_LESSON_WEIGHT_BASE;
//                result+=this.mainSubjectAvgFirstLessson(grade, classNo, weekDay, lesssonNo, schedulingProcessInfo);
//            }
//        }else{
//            result += this.amPmWeight(grade, lesssonNo, schedulingProcessInfo);//上下午权重
            result += this.avgWeekDayWeight(grade, classNo, weekDay, lesssonNo, schedulingProcessInfo);
            result += this.spacePlaceWeight(grade, classNo, weekDay, lesssonNo, subjectCount, schedulingProcessInfo);
//            result += this.unFixedSubjectWeight(schedulingProcessInfo);   //未排课优先
//            result += this.nullSubjectWeight(grade, classNo, weekDay, lesssonNo, schedulingProcessInfo);
//        }
        //一节课和前一天的不同
        for(SchoolTimeRule schoolTimeRule : schoolTimeRules){
            if(schoolTimeRule.getSort().equals("2") && schoolTimeRule.getIsUsed().equals("0")){
                result += this.notSameSubjectWeight(grade, classNo, weekDay, lesssonNo, schedulingProcessInfo);
            }
        }

        result += this.lessonContinueWeight(grade, classNo, weekDay, lesssonNo, schedulingProcessInfo);   //连堂
        if (result < 0 || result > 1000) {
            result = 0;
        }
//        if (iWeightCalc != null) {
//            Integer udfWeight = iWeightCalc.weightCalc(grade, classNo, weekDay, lesssonNo, schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo().getSubjectName());
//            result += udfWeight;
//        }
        return result;
    }

    private Integer mainSubjectAvgFirstLessson(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, SchedulingProcessInfo schedulingProcessInfo) {
        Integer result = 0;
        Integer firstLessonCount = 0;
        for (Integer w = 0; w < weekDay; w++) {
            if (this.scheduleInfos.get(grade).get(classNo).get(w).get(lesssonNo).getSubjectInfo().equals(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo())) {
                firstLessonCount++;
            }
        }
        result -= firstLessonCount * WeightDefines.SUBJECT_FIRST_LESSON_WEIGHT_MICRO;
        return result;

    }

//    private Integer nullSubjectWeight(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, SchedulingProcessInfo schedulingProcessInfo) {
//        Integer result = 0;
//        if (schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo().getSubjectCode().equals("0")) {
//            if (lesssonNo == this.gradeInfoMap.get(grade).getNullPosition() - 1) {
//                result += WeightDefines.SUBJECT_NULL_POSITION;
//            } else {
//                result -= WeightDefines.SUBJECT_NULL_OTHER;
//            }
//        }
//        return result;
//    }

    //同一天不安排同样的课
    private Integer notSameSubjectWeight(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, SchedulingProcessInfo schedulingProcessInfo) {
        Integer result = 0;
        if (weekDay == 0) {
            return result;
        }
        if (this.scheduleInfos.get(grade).get(classNo).get(weekDay - 1).get(lesssonNo).getSubjectInfo() == null) {
            return 0;
        }
        if (lesssonNo == 0 || lesssonNo.equals(this.gradeInfoMap.get(grade).getLessonAtAM())) {
            if (this.scheduleInfos.get(grade).get(classNo).get(weekDay - 1).get(lesssonNo).getSubjectInfo().equals(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo())) {
                result -= WeightDefines.SUBJECT_SEQNO_DIFF;
            }
        }
        return result;
    }

    //从未安排过的科目优先
    private Integer unFixedSubjectWeight(SchedulingProcessInfo schedulingProcessInfo) {
        Integer result = 0;
        if (schedulingProcessInfo.getScheduleClassInfo().getUnUsedCount().equals(schedulingProcessInfo.getScheduleClassInfo().getTotalCount())) {
            result += WeightDefines.SUBJECT_FIRST_FIXED;
        }
        return result;
    }

    //可排位置权重
    private Integer spacePlaceWeight(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, Integer subjectCount, SchedulingProcessInfo schedulingProcessInfo) {
        Integer result = 0;
        Integer unFixedPlaceCount = this.classFreeSpace.get(grade).get(classNo).intValue();
        if (unFixedPlaceCount <= 0) {
            return result;
        }
        double freeSpaceRate = schedulingProcessInfo.getScheduleClassInfo().getFreeSpace() / unFixedPlaceCount;
        if (freeSpaceRate <= 0.8) {
            result += WeightDefines.SUBJECT_FREE_SPACE;
        }
        //剩余课程数大于平均课节数
        if (schedulingProcessInfo.getScheduleClassInfo().getUnUsedCount() > unFixedPlaceCount / 1.0 / this.gradeInfoMap.get(grade).getSubjectInfos().size()) {
            result += WeightDefines.SUBJECT_FREE_SPACE;
        }
        if (schedulingProcessInfo.getScheduleClassInfo().getUnUsedCount() > this.gradeInfoMap.get(grade).getDayPerWeek() - weekDay) {
            result += WeightDefines.SUBJECT_FREE_SPACE * 2;
        }
        return result;
    }

    //平均课节权重
    private Integer avgWeekDayWeight(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, SchedulingProcessInfo schedulingProcessInfo) {
        //最后一天 此权重已经无意义
        if (weekDay + 1 == this.gradeInfoMap.get(grade).getDayPerWeek()) {
            return 0;
        }
        //无课科目
        if (schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo() == null) {
            return 0;
        }
        Integer result = 0;
        //查看当天是否已经安排
        Integer cntDayLesson = 0;
        Integer cntFreeSpaceInDay = 0;
        for (Integer l = 0; l < this.gradeInfoMap.get(grade).getLessonPerDay(); l++) {
            if (this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(l).getSubjectInfo() == null) {
//                for (SchedulingProcessInfo info : this.scheduledInfo.get(grade).get(classNo).get(weekDay).get(l)) {
//                    if (info.getScheduleClassInfo().getSubjectInfo().equals(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo())) {
//                        if (info.getCannotSelReason() == 0) {
//                            cntFreeSpaceInDay++;
//                        }
//                    }
//                }
                continue;
            }
            if (this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(l).getSubjectInfo().equals(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo())) {
                cntDayLesson++;
            }
        }
//        double avgFixed = schedulingProcessInfo.getScheduleClassInfo().getTotalCount() / 1.0 / this.gradeInfoMap.get(grade).getDayPerWeek();
//        double avgFixed = 4;

        if(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo().getAttributes()<3){  //表示为1,2主课
            if (cntDayLesson <= 4) {
                result += WeightDefines.SUBJECT_PER_DAY;
            } else {
                result -= WeightDefines.SUBJECT_PER_DAY;
            }
        }

        if(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo().getAttributes()>2){  //表示为3,4主课
            if (cntDayLesson <= 2) {
                result += WeightDefines.SUBJECT_PER_DAY;
            } else {
                result -= WeightDefines.SUBJECT_PER_DAY;
            }
        }
//        //今天已安排节数和平均节数对比
//        if (cntDayLesson < avgFixed) {
//            result += WeightDefines.SUBJECT_PER_DAY;
//        } else {
//            result -= WeightDefines.SUBJECT_PER_DAY;
//        }
        //todo
        //如果剩余的天数已经不够安排,即剩余课节除以剩余天数大于等于平均课节向上取整

        //if (cntFreeSpaceInDay <= 2)
//        {
//            if (schedulingProcessInfo.getScheduleClassInfo().getUnUsedCount() / 1.0 / (this.gradeInfoMap.get(grade).getDayPerWeek() - weekDay - 1) > Math.ceil(avgFixed)) {
//                result += WeightDefines.SUBJECT_PER_DAY;
//            }
//        }
        return result;
    }

    private Integer lessonContinueWeight(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo, SchedulingProcessInfo schedulingProcessInfo) {
        /*
        1、检查未安排的平均课节数
        2、如果大于等于1，且上一节这一门课，则增加权重
         */
        Integer result = 0;
        if (lesssonNo == 0 || lesssonNo >= this.maxDayPerWeek-this.nightLesssonNum) {
            return result;
        }
        //计算当天本科目已排课节数，如果一排课节数大于等于平均课节数则不处理连堂规则
        double avgFixed = schedulingProcessInfo.getScheduleClassInfo().getTotalCount() / 1.0 / this.gradeInfoMap.get(grade).getDayPerWeek();
//        double avgFixed = 2;  //最多连堂两节课
        if (avgFixed <= 1) {
            return result;
        }
        Integer cntDayLesson = 0;
        for (Integer l = 0; l < lesssonNo; l++) {
            if (this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(l).getSubjectInfo() == null) {
                return 0;
            }
            if (this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(l).getSubjectInfo().equals(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo())) {
                cntDayLesson++;
            }
        }
        if (cntDayLesson >= avgFixed) {
            return result;
        }
        double avgUnFix = schedulingProcessInfo.getScheduleClassInfo().getUnUsedCount() / 1.0 / (this.gradeInfoMap.get(grade).getDayPerWeek() - weekDay);
        if (avgUnFix >= 1) {
            //看上一节是否是这门课   主课连课
            if (this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(lesssonNo - 1).getSubjectInfo().equals(schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo()) && schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo().getAttributes()<=2) {
                result += WeightDefines.SUBJECT_CONTINUE;
            }
        }
        return result;
    }

//    //计算上下午主副课权重
//    private Integer amPmWeight(Integer grade, Integer lesssonNo, SchedulingProcessInfo schedulingProcessInfo) {
//        Integer result = 0;
//        switch (schedulingProcessInfo.getScheduleClassInfo().getSubjectInfo().getAttributes()) {
//            case 1:
//                if (lesssonNo < this.gradeInfoMap.get(grade).getLessonAtAM()) {
//                    result += WeightDefines.SUBJECT_ATTRIBUTES;
//                }
//                break;
//            case 2:
//            case 3:
//                if (lesssonNo >= this.gradeInfoMap.get(grade).getLessonAtAM()) {
//                    result += WeightDefines.SUBJECT_ATTRIBUTES;
//                }
//                break;
//        }
//        return result;
//    }

    //获取可选科目列表
    private List<SchedulingProcessInfo> fetchValidSubject(Integer grade, Integer classNo, Integer weekDay, Integer lesssonNo) {
        List<SchedulingProcessInfo> result = new ArrayList<SchedulingProcessInfo>();
        for (SchedulingProcessInfo si : this.scheduledInfo.get(grade).get(classNo).get(weekDay).get(lesssonNo)) {
            //检查老师是否在其他班任课
            if (si.getCannotSelReason() == 0 && si.getScheduleClassInfo().getUnUsedCount()>0) {
                //检查当天次节课已经上了的次数，如果次数大于平均数  则不拍此科目
                Integer cntDayLesson = 0;
                for (Integer idx = 0; idx < lesssonNo; idx++) {
                    if (this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(idx).getSubjectInfo() != null) {
                        if (this.scheduleInfos.get(grade).get(classNo).get(weekDay).get(idx).getSubjectInfo().equals(si.getScheduleClassInfo().getSubjectInfo())) {
                            cntDayLesson++;
                        }
                    }
                }
                if(si.getScheduleClassInfo().getSubjectInfo().getAttributes()<=2 && cntDayLesson>4){  //主课1,2只能连三节课
                    continue;
                }
                if(si.getScheduleClassInfo().getSubjectInfo().getAttributes()>2 && cntDayLesson>2){  //主课1,2只能连2节课
                    continue;
                }
//
//                if (cntDayLesson / 1.0 >= si.getScheduleClassInfo().getTotalCount() / 1.0 / this.gradeInfoMap.get(grade).getDayPerWeek()) {
//                    continue;
//                }
                result.add(si);
            }
        }
        return result;
    }

    private List<SchedulingProcessInfo> mergeValidSubject(List<SchedulingProcessInfo> s1, List<String> s2) {
        for (SchedulingProcessInfo item : s1) {
            for (String kk : s2) {
                if (item.getScheduleClassInfo().getSubjectInfo().equals(kk)) {
                    s1.remove(item);
                }
            }
        }
        return s1;
    }

    private String fetchTeacherByKemuAndLesson(Integer grade, Integer classNo, String subject) {
        for (Map.Entry<SubjectInfo, String> item : this.gradeInfoMap.get(grade).getClassInfos().get(classNo).getSubjectTeachers().entrySet()) {
            if (item.getKey().getCourseName().equals(subject)) {
                return item.getValue();
            }
        }
        return null;
    }

    //生成位置唯一key，为方便搜索
    private Integer generateKey(Integer grade, Integer classs, Integer weekDay, Integer lessonNo) {
        return (int) ((grade + 1) * Math.pow(10, 6) + (classs + 1) * Math.pow(10, 4) + (weekDay + 1) * Math.pow(10, 2) + lessonNo + 1);
    }

    //检查gradeInfo的信息
    private boolean checkInputGradeInfo(Map<Integer, GradeInfo> gradeInfo) {
        if (gradeInfo.size() <= 0) {
            return false;
        }
        for (Map.Entry<Integer, GradeInfo> item : gradeInfo.entrySet()) {
            this.gradeCount++;
            this.grade = item.getKey();
            this.classCount += item.getValue().getClassCount();
            if (item.getValue().getDayPerWeek() > this.maxDayPerWeek) {
                this.maxDayPerWeek = item.getValue().getDayPerWeek();
            }
            if (item.getValue().getLessonPerDay() > this.maxLessonPerDay) {
                this.maxLessonPerDay = item.getValue().getLessonPerDay();
            }
            this.amLesssonNum = item.getValue().getLessonAtAM();
            this.pmLesssonNum = item.getValue().getLessonAtPM();
            this.nightLesssonNum = item.getValue().getLessonPerDay() - item.getValue().getLessonAtAM() - item.getValue().getLessonAtPM();
        }
        return true;
    }


    //检查课程是否可以排满
    private boolean processNullPos(Map<Integer, GradeInfo> gradeInfo) {
        if (gradeInfo.size() <= 0) {
            return false;
        }

        for (Map.Entry<Integer, GradeInfo> item : gradeInfo.entrySet()) {  //年级循环
            Integer TotalCount = 0;
            for (SubjectInfo info : item.getValue().getSubjectInfos()) {
                TotalCount += info.getSubjectCount();  //把所有科目的课程节数加起来
            }
            //TotalCount为一星期所有科目节数，后面为一星期所有节数
            if (TotalCount < item.getValue().getDayPerWeek() * item.getValue().getLessonPerDay()) {
                //自习 课程id设置为 0
                SubjectInfo si = new SubjectInfo(0, "自习", 2,
                        item.getValue().getDayPerWeek() * item.getValue().getLessonPerDay() - TotalCount);
                item.getValue().getSubjectInfos().add(si);//添加科目名为无课的科目
                //为无课科目添加老师，无课科目所有老师不同，规则为 “wk01010101”
                for (Map.Entry<Integer, ClassInfo> entry : item.getValue().getClassInfos().entrySet()) {
                    entry.getValue().getSubjectTeachers().put(si, "无");
                }
            }
            if(TotalCount > item.getValue().getDayPerWeek() * item.getValue().getLessonPerDay()){
                return false;
            }
        }
        return true;
    }

    //获取老师列表
    private boolean initTeacherList(Map<Integer, GradeInfo> gradeInfo) {
        this.teacherList = new ArrayList<String>();
        for (Map.Entry<Integer, GradeInfo> item : gradeInfo.entrySet()) {
            if (item.getValue().getClassInfos().size() <= 0) {  //判断年级下是否有班级
                return false;
            }
            for (Map.Entry<Integer, ClassInfo> cc : item.getValue().getClassInfos().entrySet()) {
                if (cc.getValue().getSubjectTeachers().size() <= 0) {  //判断班级下是否有任课老师
                    return false;
                }
                for (Map.Entry<SubjectInfo, String> ss : cc.getValue().getSubjectTeachers().entrySet()) {
                    if (!this.teacherList.contains(ss.getValue())) { //判断 teacherList 是否含有该老师
                        this.teacherList.add(ss.getValue());  //不含则添加
                    }
                }
            }
        }
        return true;
    }

    //初始化老师课程安排信息
    private boolean initTeacherLesson() {
        teacherSchedule = new HashMap<String, Map<Integer, Map<Integer, SchedulePositionInfo>>>();
        //先遍历老师
        for (String teacher : this.teacherList) {
            Map<Integer, Map<Integer, SchedulePositionInfo>> item = new HashMap<Integer, Map<Integer, SchedulePositionInfo>>();
            for (Integer weekDay = 0; weekDay < this.maxDayPerWeek; weekDay++) {
                Map<Integer, SchedulePositionInfo> itemItem = new HashMap<Integer, SchedulePositionInfo>();
                for (Integer lessonNo = 0; lessonNo < this.maxLessonPerDay; lessonNo++) {
                    SchedulePositionInfo itemItemItem = new SchedulePositionInfo(0, 0, weekDay, lessonNo, null, teacher);
                    itemItem.put(lessonNo, itemItemItem);
                }
                item.put(weekDay, itemItem);
            }
            this.teacherSchedule.put(teacher, item);
        }
        return true;
    }


    //初始化课表信息
    private boolean initLessonTableInfo(Map<Integer, GradeInfo> gradeInfo) {
        this.scheduleInfos = new HashMap<Integer, Map<Integer, Map<Integer, Map<Integer, SchedulePositionInfo>>>>(); //课表信息
        this.classFreeSpace = new HashMap<Integer, Map<Integer, Integer>>();  //班级剩余课程
        for (Map.Entry<Integer, GradeInfo> item : gradeInfo.entrySet()) {
            Map<Integer, Map<Integer, Map<Integer, SchedulePositionInfo>>> grade = new HashMap<Integer, Map<Integer, Map<Integer, SchedulePositionInfo>>>();
            Map<Integer, Integer> classFS = new HashMap<Integer, Integer>();
            for (Map.Entry<Integer, ClassInfo> itemItem : item.getValue().getClassInfos().entrySet()) {
                Map<Integer, Map<Integer, SchedulePositionInfo>> classs = new HashMap<Integer, Map<Integer, SchedulePositionInfo>>();
                classFS.put(itemItem.getKey(), item.getValue().getDayPerWeek() * item.getValue().getLessonPerDay());
                for (Integer weekDay = 0; weekDay < item.getValue().getDayPerWeek(); weekDay++) {
                    Map<Integer, SchedulePositionInfo> weekLesson = new HashMap<Integer, SchedulePositionInfo>();
                    for (Integer lessonNo = 0; lessonNo < item.getValue().getLessonPerDay(); lessonNo++) {
                        SchedulePositionInfo schedulePositionInfo = new SchedulePositionInfo(item.getKey(), itemItem.getKey(), weekDay, lessonNo, null, null);
                        weekLesson.put(lessonNo, schedulePositionInfo);
                    }
                    classs.put(weekDay, weekLesson);
                }
                grade.put(itemItem.getKey(), classs);
            }
            //下面两个全为 空值
            this.classFreeSpace.put(item.getKey(), classFS); //年级—>班级每个星期的课程数
            this.scheduleInfos.put(item.getKey(), grade); //年级—班级-星期-每天的SchedulePositionInfo
        }
//        System.out.println(this.classFreeSpace);
//        System.out.println(this.scheduleInfos);
        return true;
    }

    //初始化排课中间过程数据
    private boolean initScheduldInfo(Map<Integer, GradeInfo> gradeInfo) {
        this.scheduledInfo = new HashMap<Integer, Map<Integer, Map<Integer, Map<Integer, List<SchedulingProcessInfo>>>>>();
        this.scheduleClassInfo = new HashMap<Integer, Map<Integer, List<ScheduleClassInfo>>>();
        for (Map.Entry<Integer, GradeInfo> item : gradeInfo.entrySet()) {
            Map<Integer, Map<Integer, Map<Integer, List<SchedulingProcessInfo>>>> grade = new HashMap<Integer, Map<Integer, Map<Integer, List<SchedulingProcessInfo>>>>();//课节信息
            Map<Integer, List<ScheduleClassInfo>> gradeClass = new HashMap<Integer, List<ScheduleClassInfo>>();//班级信息
            for (Map.Entry<Integer, ClassInfo> itemItem : item.getValue().getClassInfos().entrySet()) {
                Map<Integer, Map<Integer, List<SchedulingProcessInfo>>> classs = new HashMap<Integer, Map<Integer, List<SchedulingProcessInfo>>>();//课节信息
                List<ScheduleClassInfo> classInfo = new ArrayList<ScheduleClassInfo>();//班级信息
                Integer idx = 0;
                //
                for (Map.Entry<SubjectInfo, String> subject : itemItem.getValue().getSubjectTeachers().entrySet()) {
                    Map<Integer, SchedulePositionInfo> positionInfoMap = new HashMap<Integer, SchedulePositionInfo>();
                    ScheduleClassInfo classSubject = new ScheduleClassInfo(subject.getKey(), subject.getKey().getSubjectCount(), subject.getKey().getSubjectCount(),
                            item.getValue().getDayPerWeek() * item.getValue().getLessonPerDay(), positionInfoMap);//班级科目列表
                    classInfo.add(idx, classSubject);
                    idx++;
                }
                gradeClass.put(itemItem.getKey(), classInfo);
                for (Integer weekDay = 0; weekDay < item.getValue().getDayPerWeek(); weekDay++) {
                    Map<Integer, List<SchedulingProcessInfo>> weekLesson = new HashMap<Integer, List<SchedulingProcessInfo>>();
                    for (Integer lessonNo = 0; lessonNo < item.getValue().getLessonPerDay(); lessonNo++) {
                        List<SchedulingProcessInfo> schedulingProcessInfos = new ArrayList<SchedulingProcessInfo>();
                        Integer idx1 = 0;
                        for (Map.Entry<SubjectInfo, String> subject : itemItem.getValue().getSubjectTeachers().entrySet()) {
                            SchedulingProcessInfo schedulingProcessInfo = new SchedulingProcessInfo(classInfo.get(idx1), WeightDefines.WEIGHT_BASE, false, 4);
                            schedulingProcessInfos.add(schedulingProcessInfo);
                            idx1++;
                        }
                        weekLesson.put(lessonNo, schedulingProcessInfos);
                    }
                    classs.put(weekDay, weekLesson);
                }
                grade.put(itemItem.getKey(), classs);
            }
            this.scheduledInfo.put(item.getKey(), grade); //年级-班级-一星期-每天可排的科目的 已排课位置信息 SchedulingProcessInfo
            this.scheduleClassInfo.put(item.getKey(), gradeClass); //年级-班级-每个班级的课程信息 scheduleClassInfo
        }
        return true;
    }
}
