package com.bs.mes.schedule;

import cn.hutool.core.date.DateUtil;
import com.ximai.mes.pro.domain.task.WorkorderScheduleParams;
import com.ximai.mes.pro.schedule.*;
import com.ximai.mes.pro.schedule.impl.BaoshenScheduleAlgorithmAdapter;
import com.ximai.mes.pro.schedule.strategy.EquipmentSelectionStrategyImpl;
import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import org.junit.Test;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;


public class BaoshenScheduleAlgorithmAdapterTest {

    @Test
    public void schedule(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource = new AlgorithmDataSource1();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                Assert.assertEquals(jobs.size(),2);
                Assert.assertEquals(Duration.ofHours(8), jobs.get(0).getTasks().get(0).getScheduledStartedTime());
                //120+47+准备工时1分钟（取整分钟）
                Assert.assertEquals(Duration.ofHours(8).plus(Duration.ofHours(2)).plus(Duration.ofMinutes(48)),
                        jobs.get(0).getTasks().get(0).getScheduledEndedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledEndedTime(), jobs.get(0).getTasks().get(1).getScheduledStartedTime());
                //+17分钟
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledStartedTime().plus(Duration.ofMinutes(17)),
                        jobs.get(0).getTasks().get(1).getScheduledEndedTime());

                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledEndedTime(), jobs.get(1).getTasks().get(0).getScheduledStartedTime());
                //跨中班\及隔开班次,22-05-05 12:00 - 22-05-05 13:30 || 22-05-05 17:00 - 22-05-06 08:00
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledEndedTime().plus(Duration.ofHours(16)).plus(Duration.ofMinutes(30))
                                .plus(Duration.ofMinutes(400)
                                        .plus(Duration.ofMinutes(1))),//跨3个班次，准备时间+3分钟
                        jobs.get(1).getTasks().get(0).getScheduledEndedTime());
            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }

    @Test
    public void schedule2(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource2 = new AlgorithmDataSource2();
        baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource2);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                //JOB1
                Assert.assertEquals(jobs.size(),2);
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledStartedTime(), Duration.ofHours(8));
                Assert.assertEquals(Duration.ofHours(8).plus(Duration.ofMinutes(85)), jobs.get(0).getTasks().get(0).getScheduledEndedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledEndedTime(), jobs.get(0).getTasks().get(1).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledStartedTime().plus(Duration.ofMinutes(9)),
                        jobs.get(0).getTasks().get(1).getScheduledEndedTime());
                //JOB2
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledEndedTime(), jobs.get(1).getTasks().get(0).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(1).getTasks().get(0).getScheduledStartedTime().plus(Duration.ofMinutes(9)),
                        jobs.get(1).getTasks().get(0).getScheduledEndedTime());
                Assert.assertEquals(jobs.get(1).getTasks().get(0).getScheduledEndedTime(), jobs.get(1).getTasks().get(1).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(1).getTasks().get(1).getScheduledStartedTime().plus(Duration.ofMinutes(9)),
                        jobs.get(1).getTasks().get(1).getScheduledEndedTime());
            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }

    //任务需求日期不一致情况
    @Test
    public void schedule3(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource = new AlgorithmDataSource3();
        baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                Assert.assertEquals(jobs.size(),2);
                Assert.assertEquals(4,jobs.get(0).getTasks().size());
                Assert.assertEquals(3, jobs.get(1).getTasks().size());
                //job1时间验证
                //task1
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledStartedTime(), Duration.ofHours(8));
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        jobs.get(0).getTasks().get(0).getScheduledEndedTime());
                //task2
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledEndedTime(),
                        jobs.get(0).getTasks().get(1).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledStartedTime().plus(Duration.ofMinutes(90)),
                        jobs.get(0).getTasks().get(1).getScheduledEndedTime());
                //task3
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledEndedTime(),
                        jobs.get(0).getTasks().get(2).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(2).getScheduledStartedTime()
                                .plus(Duration.ofHours(16))//累加3个班次的间隔时长12-13:30，17:30-隔天8点
                                .plus(Duration.ofHours(5)),
                        jobs.get(0).getTasks().get(2).getScheduledEndedTime());
                //task4
                Assert.assertEquals(jobs.get(0).getTasks().get(2).getScheduledEndedTime(),
                        jobs.get(0).getTasks().get(3).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(3).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        jobs.get(0).getTasks().get(3).getScheduledEndedTime());

                //job2时间验证
                Assert.assertEquals(jobs.get(1).getTasks().get(0).getScheduledStartedTime(), Duration.ofHours(8));
                Assert.assertEquals(jobs.get(1).getTasks().get(0).getScheduledStartedTime().plus(Duration.ofHours(1)),
                        jobs.get(1).getTasks().get(0).getScheduledEndedTime());

                Assert.assertEquals(jobs.get(1).getTasks().get(0).getScheduledEndedTime(),
                        jobs.get(1).getTasks().get(1).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(1).getTasks().get(1).getScheduledStartedTime().plus(Duration.ofMinutes(30)),
                        jobs.get(1).getTasks().get(1).getScheduledEndedTime());

                Assert.assertEquals(jobs.get(1).getTasks().get(1).getScheduledEndedTime(),
                        jobs.get(1).getTasks().get(2).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(1).getTasks().get(2).getScheduledStartedTime()
                                .plus(Duration.ofHours(2)),
                        jobs.get(1).getTasks().get(2).getScheduledEndedTime());

            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }

    @Test
    public void schedule4(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource = new AlgorithmDataSource4();
        baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                Assert.assertEquals(jobs.size(),1);
                Assert.assertEquals(4,jobs.get(0).getTasks().size());
                List<Task> job1TaskList = jobs.get(0).getTasks();
                //task1
                Assert.assertEquals(Duration.ofHours(8), job1TaskList.get(0).getScheduledStartedTime());
                Assert.assertEquals(job1TaskList.get(0).getScheduledEndedTime(),
                        job1TaskList.get(0).getScheduledStartedTime().plus(Duration.ofHours(2)));
                //task2
                //拆分成了2个子任务
                Assert.assertEquals(2, job1TaskList.get(1).getSplitTask().size());
                Assert.assertEquals(Duration.ofHours(13).plus(Duration.ofMinutes(30)),
                        job1TaskList.get(1).getScheduledStartedTime());
                Assert. assertEquals(job1TaskList.get(1).getScheduledStartedTime().plus(Duration.ofHours(4)),
                        job1TaskList.get(1).getScheduledEndedTime());
                //task3
                Assert.assertEquals(Duration.ofHours(24+8),
                        job1TaskList.get(2).getScheduledStartedTime());
                Assert.assertEquals(job1TaskList.get(2).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        jobs.get(0).getTasks().get(2).getScheduledEndedTime());
                //task4
                Assert.assertEquals(job1TaskList.get(2).getScheduledEndedTime(),
                        job1TaskList.get(3).getScheduledStartedTime());
                Assert.assertEquals(job1TaskList.get(3).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        job1TaskList.get(3).getScheduledEndedTime());

            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }

    //测试产能不足、延期状态数据
    @Test
    public void schedule5(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource = new AlgorithmDataSource5();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                Assert.assertEquals(jobs.size(),2);
                Assert.assertEquals(jobs.get(0).getScheduleStatus(), ScheduleStatus.Delay);
                Assert.assertEquals(jobs.get(1).getScheduleStatus(), ScheduleStatus.InadequateTime);

                Assert.assertEquals(Duration.ofHours(8), jobs.get(0).getTasks().get(0).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        jobs.get(0).getTasks().get(0).getScheduledEndedTime());
                //task2
                Assert.assertEquals(Duration.ofHours(32),//5号不存在日历
                        jobs.get(0).getTasks().get(1).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        jobs.get(0).getTasks().get(1).getScheduledEndedTime());
                //test3
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledEndedTime(),
                        jobs.get(0).getTasks().get(2).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(2).getScheduledStartedTime().plus(Duration.ofHours(1)),
                        jobs.get(0).getTasks().get(2).getScheduledEndedTime());

                //job2
                List<Task> job2Task = jobs.get(1).getTasks();
                Assert.assertEquals(Duration.ofHours(10), job2Task.get(0).getScheduledStartedTime());
                Assert.assertEquals(job2Task.get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        job2Task.get(0).getScheduledEndedTime());

                Assert.assertEquals(job2Task.get(0).getScheduledEndedTime().plus(Duration.ofHours(22)), job2Task.get(1).getScheduledStartedTime());
                Assert.assertEquals(job2Task.get(1).getScheduledStartedTime().plus(Duration.ofHours(6)).plus(Duration.ofMinutes(90)),
                        job2Task.get(1).getScheduledEndedTime());
                Assert.assertEquals(job2Task.get(2).getScheduleStatus(), ScheduleStatus.InadequateTime);
                Assert.assertEquals(job2Task.get(3).getScheduleStatus(), ScheduleStatus.UnScheduled);



            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }

    //外协工序测试
    @Test
    public void scheduleOutsourcing(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource = new AlgorithmDataSourceOutsourcing();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                Assert.assertEquals(jobs.size(),2);
                Assert.assertEquals(jobs.get(0).getScheduleStatus(), ScheduleStatus.Delay);
                Assert.assertEquals(jobs.get(1).getScheduleStatus(), ScheduleStatus.Delay);
                //job1
                List<Task> jobTask = jobs.get(0).getTasks();

                //task1
                Assert.assertEquals(Duration.ofHours(0), jobs.get(0).getTasks().get(0).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledStartedTime().plus(Duration.ofDays(3)),
                        jobs.get(0).getTasks().get(0).getScheduledEndedTime());
                //task2
                Assert.assertEquals(Duration.ofDays(3).plusHours(8),
                        jobs.get(0).getTasks().get(1).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        jobs.get(0).getTasks().get(1).getScheduledEndedTime());
                //test3
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledEndedTime(),
                        jobs.get(0).getTasks().get(2).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(2).getScheduledStartedTime().plus(Duration.ofHours(1)),
                        jobs.get(0).getTasks().get(2).getScheduledEndedTime());

                //job2
                List<Task> job2Task = jobs.get(1).getTasks();
                Assert.assertEquals(Duration.ofHours(8), job2Task.get(0).getScheduledStartedTime());
                Assert.assertEquals(job2Task.get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        job2Task.get(0).getScheduledEndedTime());

                Assert.assertEquals(job2Task.get(0).getScheduledEndedTime(), job2Task.get(1).getScheduledStartedTime());
                Assert.assertEquals(job2Task.get(1).getScheduledStartedTime().plus(Duration.ofDays(3)),
                        job2Task.get(1).getScheduledEndedTime());

                Assert.assertEquals(jobTask.get(2).getScheduledEndedTime(), job2Task.get(2).getScheduledStartedTime());
                Assert.assertEquals(job2Task.get(2).getScheduledStartedTime().plus(Duration.ofHours(1)),
                        job2Task.get(2).getScheduledEndedTime());

                Assert.assertEquals(jobTask.get(3).getScheduledEndedTime(), job2Task.get(3).getScheduledStartedTime());
                Assert.assertEquals(job2Task.get(3).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        job2Task.get(3).getScheduledEndedTime());


            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }


    //固化时间测试
    @Test
    public void scheduleCuringTime(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource = new AlgorithmDataSourceCuringTime();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                Assert.assertEquals(jobs.size(),2);
                Assert.assertEquals(ScheduleStatus.Delay, jobs.get(0).getScheduleStatus());
                Assert.assertEquals(ScheduleStatus.Delay, jobs.get(1).getScheduleStatus());

                //job1
                List<Task> jobTask = jobs.get(0).getTasks();
                //task1
                Assert.assertEquals(Duration.ofHours(8), jobs.get(0).getTasks().get(0).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        jobs.get(0).getTasks().get(0).getScheduledEndedTime());
                //task2 拆分为成了2个作业单元
                Assert.assertEquals(2, jobTask.get(1).getSplitTask().size());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledEndedTime().plusMinutes(25),
                        jobTask.get(1).getSplitTask().get(0).getScheduledStartedTime());
                Assert.assertEquals(Duration.ofHours(17).plusMinutes(30),
                        jobTask.get(1).getSplitTask().get(0).getScheduledEndedTime());

                Assert.assertEquals(Duration.ofDays(1).plusHours(8),
                        jobTask.get(1).getSplitTask().get(1).getScheduledStartedTime());
                Assert.assertEquals(jobTask.get(1).getSplitTask().get(1).getScheduledStartedTime().plus(Duration.ofHours(2).plusMinutes(25)),
                        jobTask.get(1).getSplitTask().get(1).getScheduledEndedTime());

                //test3
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledEndedTime(),
                        jobs.get(0).getTasks().get(2).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(2).getScheduledStartedTime().plus(Duration.ofHours(1)),
                        jobs.get(0).getTasks().get(2).getScheduledEndedTime());

                //job2
                List<Task> job2Task = jobs.get(1).getTasks();
                Assert.assertEquals(Duration.ofHours(10), job2Task.get(0).getScheduledStartedTime());
                Assert.assertEquals(job2Task.get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        job2Task.get(0).getScheduledEndedTime());

                Assert.assertEquals(jobTask.get(1).getSplitTask().get(1).getScheduledEndedTime(),
                        job2Task.get(1).getScheduledStartedTime());
                //上个排产任务5-6 10:25结束
                Assert.assertEquals(job2Task.get(1).getScheduledStartedTime().plusHours(2)
                                .plusMinutes(90),//中午休息1小时30分
                        job2Task.get(1).getScheduledEndedTime());
            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }


    //转间时间测试
    @Test
    public void scheduleTransferTime(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource = new AlgorithmDataSourceTransferTime();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                Assert.assertEquals(jobs.size(),2);
                Assert.assertEquals(ScheduleStatus.Delay, jobs.get(0).getScheduleStatus());
                Assert.assertEquals(ScheduleStatus.Delay, jobs.get(1).getScheduleStatus());

                //job1
                List<Task> jobTask = jobs.get(0).getTasks();
                //task1
                Assert.assertEquals(Duration.ofHours(8), jobs.get(0).getTasks().get(0).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        jobs.get(0).getTasks().get(0).getScheduledEndedTime());
                //task2 拆分为成了2个作业单元
                Assert.assertEquals(2, jobTask.get(1).getSplitTask().size());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledEndedTime().plusMinutes(25),
                        jobTask.get(1).getSplitTask().get(0).getScheduledStartedTime());
                Assert.assertEquals(Duration.ofHours(17).plusMinutes(30),
                        jobTask.get(1).getSplitTask().get(0).getScheduledEndedTime());

                Assert.assertEquals(Duration.ofDays(1).plusHours(8),
                        jobTask.get(1).getSplitTask().get(1).getScheduledStartedTime());
                Assert.assertEquals(jobTask.get(1).getSplitTask().get(1).getScheduledStartedTime().plus(Duration.ofHours(2).plusMinutes(25)),
                        jobTask.get(1).getSplitTask().get(1).getScheduledEndedTime());

                //test3
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledEndedTime(),
                        jobs.get(0).getTasks().get(2).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(2).getScheduledStartedTime().plus(Duration.ofHours(1)),
                        jobs.get(0).getTasks().get(2).getScheduledEndedTime());

                //job2
                List<Task> job2Task = jobs.get(1).getTasks();
                Assert.assertEquals(Duration.ofHours(10), job2Task.get(0).getScheduledStartedTime());
                Assert.assertEquals(job2Task.get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        job2Task.get(0).getScheduledEndedTime());

                Assert.assertEquals(jobTask.get(1).getSplitTask().get(1).getScheduledEndedTime(),
                        job2Task.get(1).getScheduledStartedTime());
                //上个排产任务5-6 10:25结束
                Assert.assertEquals(job2Task.get(1).getScheduledStartedTime().plusHours(2)
                                .plusMinutes(90),//中午休息1小时30分
                        job2Task.get(1).getScheduledEndedTime());
            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }



    //转间混合固化时间测试
    @Test
    public void scheduleTransferTimeAndCuringTime(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource = new AlgorithmDataSourceTransferTimeAndCuringTime();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                Assert.assertEquals(jobs.size(),2);
                Assert.assertEquals(ScheduleStatus.Delay, jobs.get(0).getScheduleStatus());
                Assert.assertEquals(ScheduleStatus.Delay, jobs.get(1).getScheduleStatus());

                //job1
                List<Task> jobTask = jobs.get(0).getTasks();
                //task1
                Assert.assertEquals(Duration.ofHours(8), jobs.get(0).getTasks().get(0).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        jobs.get(0).getTasks().get(0).getScheduledEndedTime());
                //task2 拆分为成了2个作业单元
                Assert.assertEquals(2, jobTask.get(1).getSplitTask().size());
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledEndedTime().plusMinutes(25),
                        jobTask.get(1).getSplitTask().get(0).getScheduledStartedTime());
                Assert.assertEquals(Duration.ofHours(17).plusMinutes(30),
                        jobTask.get(1).getSplitTask().get(0).getScheduledEndedTime());

                Assert.assertEquals(Duration.ofDays(1).plusHours(8),
                        jobTask.get(1).getSplitTask().get(1).getScheduledStartedTime());
                Assert.assertEquals(jobTask.get(1).getSplitTask().get(1).getScheduledStartedTime().plus(Duration.ofHours(2).plusMinutes(25)),
                        jobTask.get(1).getSplitTask().get(1).getScheduledEndedTime());

                //test3
                Assert.assertEquals(jobs.get(0).getTasks().get(1).getScheduledEndedTime(),
                        jobs.get(0).getTasks().get(2).getScheduledStartedTime());
                Assert.assertEquals(jobs.get(0).getTasks().get(2).getScheduledStartedTime().plus(Duration.ofHours(1)),
                        jobs.get(0).getTasks().get(2).getScheduledEndedTime());

                //job2
                List<Task> job2Task = jobs.get(1).getTasks();
                Assert.assertEquals(Duration.ofHours(10), job2Task.get(0).getScheduledStartedTime());
                Assert.assertEquals(job2Task.get(0).getScheduledStartedTime().plus(Duration.ofHours(2)),
                        job2Task.get(0).getScheduledEndedTime());

                Assert.assertEquals(jobTask.get(1).getSplitTask().get(1).getScheduledEndedTime(),
                        job2Task.get(1).getScheduledStartedTime());
                //上个排产任务5-6 10:25结束
                Assert.assertEquals(job2Task.get(1).getScheduledStartedTime().plusHours(2)
                                .plusMinutes(90),//中午休息1小时30分
                        job2Task.get(1).getScheduledEndedTime());
            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }

    //时间验证
    @Test
    public void scheduleTimeValidate(){
        LocalDateTime scheduleStartDate = LocalDateTime.now().with(LocalTime.MIN).withYear(2022).withMonth(5).withDayOfMonth(5);
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        AlgorithmDataSource algorithmDataSource = new AlgorithmDataTimeSpace();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(new EquipmentSelectionStrategyImpl());
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(new AlgorithmResultProcess() {
            @Override
            public void execute(LocalDateTime scheduleStartDate, List<Job> jobs) {
                jobPrint(jobs, scheduleStartDate);
                Assert.assertEquals(jobs.size(),1);
                Assert.assertEquals(ScheduleStatus.Delay, jobs.get(0).getScheduleStatus());

                //job1
                List<Task> jobTask = jobs.get(0).getTasks();
                //task1
                //日历占用，从10点25分开始
                Assert.assertEquals(Duration.ofHours(10).plusMinutes(25), jobs.get(0).getTasks().get(0).getScheduledStartedTime());
                //总生产6小时，跨时间段，10：25-12：00=95分 13:30-17:30=240分 隔天08:00-25=25分 总6小时=7200*3/60=360分
                //第1工序单件加工时间3秒
                //第一时间段95/360*7200=1899，剩余时间5301*3/60=266(分钟取整)
                //第二时间段240/(266)*5301=4782，剩余时间519*3/60=26(分钟取整)
                //第三时间段耗时=直接取26分钟
                Assert.assertEquals(jobs.get(0).getTasks().get(0).getScheduledStartedTime().plusHours(13)
                                .plusMinutes(35).plusHours(8)
                                .plusMinutes(25),//跨时间段计算多出一分钟
                        jobs.get(0).getTasks().get(0).getScheduledEndedTime());
            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(scheduleStartDate, null);
    }

    /*
     * 数据源1，验证工序时间是否连续排产，
     * 不同工单相同工序时间是否连续排产
     */
    public class AlgorithmDataSource1 implements AlgorithmDataSource{
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"包装-1","排版-1"},
                    new String[]{"包装","排版"},
                    new Long[]{1l,2l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();
            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(10000),
                    new String[]{"包装", "排版"},
                    new Long[]{1l,2l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofMillis(100)},
                    new Duration[]{Duration.ofSeconds(1), Duration.ZERO});

            Job job2 = buildJob(2l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(8000),
                    new String[]{"包装"},
                    new Long[]{1l},
                    new Duration[]{Duration.ofSeconds(3)},
                    new Duration[]{Duration.ofSeconds(1)});

            rst.add(job);
            rst.add(job2);
            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            rst.add(buildWorkingCalendar(resources.get(0), schedulingStartedDate,
                    "22-05-05 08:00","22-05-05 12:00"));
            rst.add(buildWorkingCalendar(resources.get(0), schedulingStartedDate,
                    "22-05-05 13:30","22-05-05 17:00"));
            rst.add(buildWorkingCalendar(resources.get(0), schedulingStartedDate,
                    "22-05-06 08:00","22-05-06 12:00"));
            rst.add(buildWorkingCalendar(resources.get(0), schedulingStartedDate,
                    "22-05-06 13:30","22-05-06 17:00"));
            //设备2
            rst.add(buildWorkingCalendar(resources.get(1), schedulingStartedDate,
                    "22-05-05 08:00","22-05-05 12:00"));
            rst.add(buildWorkingCalendar(resources.get(1), schedulingStartedDate,
                    "22-05-05 13:30","22-05-05 17:00"));
            rst.add(buildWorkingCalendar(resources.get(1), schedulingStartedDate,
                    "22-05-06 08:00","22-05-06 12:00"));
            rst.add(buildWorkingCalendar(resources.get(1), schedulingStartedDate,
                    "22-05-06 13:30","22-05-06 17:00"));
            return rst;
        }
    }



    /*
     * 数据源2，验证工序时间是否连续排产，
     * 不同工单相同工序时间是否连续排产
     */
    public class AlgorithmDataSource2 implements AlgorithmDataSource{
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"包装-1","排版-1"},
                    new String[]{"包装","排版"},
                    new Long[]{1l,2l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();

            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(5000),
                    new String[]{"包装", "排版"},
                    new Long[]{1l,2l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofMillis(100)},
                    new Duration[]{Duration.ofSeconds(1), Duration.ZERO});

            Job job2 = buildJob(2l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(5000),
                    new String[]{"包装", "排版"},
                    new Long[]{1l,2l},
                    new Duration[]{Duration.ofMillis(100), Duration.ofMillis(100)},
                    new Duration[]{Duration.ZERO, Duration.ZERO});

            rst.add(job);
            rst.add(job2);

            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            rst.add(buildWorkingCalendar(resources.get(0), schedulingStartedDate,
                    "22-05-05 08:00","22-05-05 12:00"));
            rst.add(buildWorkingCalendar(resources.get(0), schedulingStartedDate,
                    "22-05-05 13:30","22-05-05 17:00"));
            rst.add(buildWorkingCalendar(resources.get(0), schedulingStartedDate,
                    "22-05-06 08:00","22-05-06 12:00"));
            rst.add(buildWorkingCalendar(resources.get(0), schedulingStartedDate,
                    "22-05-06 13:30","22-05-06 17:00"));
            //设备排版
            rst.add(buildWorkingCalendar(resources.get(1), schedulingStartedDate,
                    "22-05-05 08:00","22-05-05 12:00"));
            rst.add(buildWorkingCalendar(resources.get(1), schedulingStartedDate,
                    "22-05-05 13:30","22-05-05 17:00"));
            rst.add(buildWorkingCalendar(resources.get(1), schedulingStartedDate,
                    "22-05-06 08:00","22-05-06 12:00"));
            rst.add(buildWorkingCalendar(resources.get(1), schedulingStartedDate,
                    "22-05-06 13:30","22-05-06 17:00"));
            return rst;
        }

    }

    /*
     * 数据源3，是否会占用上个任务空闲时间段，工单2包装是否会使用工单1未占用的前置包装加工产能
     * 工单1工艺：排版(DTA)-柔版印刷-冷切-包装(8-12 ~ 13.30-17.30)
     * 工单2工艺：吹膜-封切-包装(8-12 ~ 13.30-17.30)
     * 工单1时长，需求日期=05-06，排版2H-柔版印刷1.5H-冷切5H-包装2H，
     * 工单2时长，需求日期=05-06，吹膜1H-封切0.5H，包装2H
     */
    public class AlgorithmDataSource3 implements AlgorithmDataSource{
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"排版(DTA)-1","冷切-1","包装-1","柔版印刷-1","吹膜-1","封切-1"},
                    new String[]{"排版(DTA)","冷切","包装","柔版印刷","吹膜","封切"},
                    new Long[]{1l,2l,3l,4l,5l,6l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();
            LocalDateTime demandDate =  LocalDateTime.now().withYear(2022).withMonth(5).withDayOfMonth(6).with(LocalTime.MIN);

            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofMillis(750), Duration.ofMillis(2500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            Job job2 = buildJob(2l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(5000),
                    new String[]{"吹膜", "封切", "包装"},
                    new Long[]{5l,6l,3l},
                    new Duration[]{Duration.ofMillis(720), Duration.ofMillis(360), Duration.ofMillis(1440)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO});

            rst.add(job);
            rst.add(job2);
            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            for(int i=0;i<6;i++){
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 08:00","22-05-05 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 13:30","22-05-05 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 08:00","22-05-06 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 13:30","22-05-06 17:30"));
            }
            return rst;
        }

    }


    /*
     * 数据源4，单任务多设备可选情况，且单设备产能不足
     * 工单1工艺：排版(DTA)-柔版印刷-冷切-包装(8-12 ~ 13.30-17.30)
     * 工单1时长，需求日期=05-06，排版2H-柔版印刷6H-冷切1H-包装2H
     * 柔版印刷工序2台设备支持加工，2台设备都只排4小时产能
     */
    public class AlgorithmDataSource4 implements AlgorithmDataSource {
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"排版(DTA)-1","冷切-1","包装-1","柔版印刷-1","柔版印刷-2"},
                    new String[]{"排版(DTA)","冷切","包装","柔版印刷","柔版印刷"},
                    new Long[]{1l,2l,3l,4l,4l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();
            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofMillis(2900), Duration.ofSeconds(1), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            rst.add(job);
            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            for(int i=0;i<3;i++){
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 08:00","22-05-05 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 13:30","22-05-05 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 08:00","22-05-06 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 13:30","22-05-06 17:30"));
            }
            rst.add(buildWorkingCalendar(resources.get(3), schedulingStartedDate,
                    "22-05-05 13:30","22-05-05 17:30"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-05 13:30","22-05-05 17:30"));
            return rst;
        }
    }

    /*
     * 数据源5，测试产能不足、延期状态数据
     * 工单工艺：排版(DTA)-柔版印刷-冷切-包装(8-12 ~ 13.30-17.30)
     * 工单1时长，需求日期=05-05，排版2H-柔版印刷2H-冷切1H-包装2H（延期状态数据）
     * 工单2时长，需求日期=05-06，排版2H-柔版印刷12H-冷切1H-包装2H（产能不足，柔板5号没排产能）
     */
    public class AlgorithmDataSource5 implements AlgorithmDataSource {
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"排版(DTA)-1","冷切-1","包装-1","柔版印刷-1","柔版印刷-2"},
                    new String[]{"排版(DTA)","冷切","包装","柔版印刷","柔版印刷"},
                    new Long[]{1l,2l,3l,4l,4l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();
            LocalDateTime demandDate = LocalDateTime.now().withYear(2022).withMonth(5).withDayOfMonth(5).with(LocalTime.MIN);

            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofSeconds(1), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            Job job2 = buildJob(2l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofSeconds(3), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            rst.add(job);
            rst.add(job2);
            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            for(int i=0;i<3;i++){
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 08:00","22-05-05 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 13:30","22-05-05 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 08:00","22-05-06 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 13:30","22-05-06 17:30"));
            }
            rst.add(buildWorkingCalendar(resources.get(3), schedulingStartedDate,
                    "22-05-06 08:00","22-05-06 12:00"));
            rst.add(buildWorkingCalendar(resources.get(3), schedulingStartedDate,
                    "22-05-06 13:30","22-05-06 17:30"));
            rst.add(buildWorkingCalendar(resources.get(3), schedulingStartedDate,
                    "22-05-07 08:00","22-05-07 12:00"));
            rst.add(buildWorkingCalendar(resources.get(3), schedulingStartedDate,
                    "22-05-07 13:30","22-05-07 17:30"));
            return rst;
        }
    }


    //外协工序测试数据源
    public class AlgorithmDataSourceOutsourcing implements AlgorithmDataSource {
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"排版(DTA)-1","冷切-1","包装-1","柔版印刷-1","柔版印刷-2"},
                    new String[]{"排版(DTA)","冷切","包装","柔版印刷","柔版印刷"},
                    new Long[]{1l,2l,3l,4l,4l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();
            LocalDateTime demandDate = LocalDateTime.now().withYear(2022).withMonth(5).withDayOfMonth(5).with(LocalTime.MIN);

            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)-1", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofSeconds(1), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            Job job2 = buildJob(2l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷-1", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofSeconds(3), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            rst.add(job);
            rst.add(job2);
            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            for(int i=0;i<4;i++){
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 08:00","22-05-05 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 13:30","22-05-05 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 08:00","22-05-06 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 13:30","22-05-06 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-07 08:00","22-05-07 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-07 13:30","22-05-07 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-08 08:00","22-05-08 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-08 13:30","22-05-08 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-09 08:00","22-05-09 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-09 13:30","22-05-09 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-10 08:00","22-05-10 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-10 13:30","22-05-10 17:30"));
            }
            return rst;
        }
    }

    //固化时间测试数据源
    public class AlgorithmDataSourceCuringTime implements AlgorithmDataSource {
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"排版(DTA)-1@25","冷切-1","包装-1","柔版印刷-1@45","柔版印刷-2"},
                    new String[]{"排版(DTA)","冷切","包装","柔版印刷","柔版印刷"},
                    new Long[]{1l,2l,3l,4l,4l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();
            LocalDateTime demandDate = LocalDateTime.now().withYear(2022).withMonth(5).withDayOfMonth(5).with(LocalTime.MIN);

            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofSeconds(4), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            Job job2 = buildJob(2l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofMillis(1000), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            rst.add(job);
            rst.add(job2);
            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            for(int i=0;i<4;i++){
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 08:00","22-05-05 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 13:30","22-05-05 17:30"));
                if(i!=3) {
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-06 08:00", "22-05-06 12:00"));
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-06 13:30", "22-05-06 17:30"));
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-07 08:00", "22-05-07 12:00"));
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-07 13:30", "22-05-07 17:30"));
                }
            }
            //柔版印2刷添加日历
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-06 08:00","22-05-06 12:00"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-06 13:30","22-05-06 17:30"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-07 08:00","22-05-07 12:00"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-07 13:30","22-05-07 17:30"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-08 08:00","22-05-08 12:00"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-08 13:30","22-05-08 17:30"));
            return rst;
        }
    }

    //转间时间测试数据源
    public class AlgorithmDataSourceTransferTime implements AlgorithmDataSource {
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"排版(DTA)-1@@25","冷切-1","包装-1","柔版印刷-1@@45","柔版印刷-2"},
                    new String[]{"排版(DTA)","冷切","包装","柔版印刷","柔版印刷"},
                    new Long[]{1l,2l,3l,4l,4l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();
            LocalDateTime demandDate = LocalDateTime.now().withYear(2022).withMonth(5).withDayOfMonth(5).with(LocalTime.MIN);

            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofSeconds(4), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            Job job2 = buildJob(2l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofMillis(1000), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            rst.add(job);
            rst.add(job2);
            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            for(int i=0;i<4;i++){
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 08:00","22-05-05 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 13:30","22-05-05 17:30"));
                if(i!=3) {
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-06 08:00", "22-05-06 12:00"));
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-06 13:30", "22-05-06 17:30"));
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-07 08:00", "22-05-07 12:00"));
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-07 13:30", "22-05-07 17:30"));
                }
            }

            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-06 08:00","22-05-06 12:00"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-06 13:30","22-05-06 17:30"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-07 08:00","22-05-07 12:00"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-07 13:30","22-05-07 17:30"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-08 08:00","22-05-08 12:00"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-08 13:30","22-05-08 17:30"));
            return rst;
        }
    }

    //转间混合固化时间测试数据源
    public class AlgorithmDataSourceTransferTimeAndCuringTime implements AlgorithmDataSource {
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"排版(DTA)-1@25@25","冷切-1","包装-1","柔版印刷-1@35@45","柔版印刷-2"},
                    new String[]{"排版(DTA)","冷切","包装","柔版印刷","柔版印刷"},
                    new Long[]{1l,2l,3l,4l,4l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();
            LocalDateTime demandDate = LocalDateTime.now().withYear(2022).withMonth(5).withDayOfMonth(5).with(LocalTime.MIN);

            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofSeconds(4), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            Job job2 = buildJob(2l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(1), Duration.ofMillis(1000), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            rst.add(job);
            rst.add(job2);
            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            for(int i=0;i<4;i++){
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 08:00","22-05-05 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 13:30","22-05-05 17:30"));
                if(i!=3) {
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-06 08:00", "22-05-06 12:00"));
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-06 13:30", "22-05-06 17:30"));
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-07 08:00", "22-05-07 12:00"));
                    rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                            "22-05-07 13:30", "22-05-07 17:30"));
                }
            }

            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-06 08:00","22-05-06 12:00"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-06 13:30","22-05-06 17:30"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-07 08:00","22-05-07 12:00"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-07 13:30","22-05-07 17:30"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-08 08:00","22-05-08 12:00"));
            rst.add(buildWorkingCalendar(resources.get(4), schedulingStartedDate,
                    "22-05-08 13:30","22-05-08 17:30"));
            return rst;
        }
    }

    //时间间隔测试
    public class AlgorithmDataTimeSpace implements AlgorithmDataSource {
        @Override
        public List<Resource> getResource(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams) {
            return buildEquipment(
                    new String[]{"排版(DTA)-1@25","冷切-1","包装-1","柔版印刷-1@45","柔版印刷-2"},
                    new String[]{"排版(DTA)","冷切","包装","柔版印刷","柔版印刷"},
                    new Long[]{1l,2l,3l,4l,4l});
        }

        @Override
        public List<Job> getJob(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams, List<Resource> resources) {
            List<Job> rst = new ArrayList<Job>();
            LocalDateTime demandDate = LocalDateTime.now().withYear(2022).withMonth(5).withDayOfMonth(5).with(LocalTime.MIN);

            Job job = buildJob(1l, schedulingStartedDate, "2022-05-06 00:00", BigDecimal.valueOf(7200),
                    new String[]{"排版(DTA)", "柔版印刷", "冷切", "包装"},
                    new Long[]{1l,4l,2l,3l},
                    new Duration[]{Duration.ofSeconds(3), Duration.ofSeconds(1), Duration.ofMillis(500), Duration.ofSeconds(1)},
                    new Duration[]{Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO});

            rst.add(job);
            return rst;
        }

        @Override
        public List<Calendar> getCalendar(LocalDateTime schedulingStartedDate, List<WorkorderScheduleParams> workorderScheduleParams,List<Resource> resources) {
            List<Calendar> rst = new ArrayList<Calendar>();
            for(int i=0;i<4;i++){
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 08:00","22-05-05 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-05 13:30","22-05-05 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 08:00", "22-05-06 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-06 13:30", "22-05-06 17:30"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-07 08:00", "22-05-07 12:00"));
                rst.add(buildWorkingCalendar(resources.get(i), schedulingStartedDate,
                        "22-05-07 13:30", "22-05-07 17:30"));
            }
            //占用日历
            Calendar.OccupiedCalendar alg_CalendarItem = new Calendar.OccupiedCalendar() {{
                setStartedTime(Duration.between(schedulingStartedDate, schedulingStartedDate.plusHours(8)));
                setEndedTime(Duration.between(schedulingStartedDate, schedulingStartedDate.plusHours(8).plusMinutes(145)));
                setResource(resources.get(0));
            }};
            rst.add(alg_CalendarItem);

            return rst;
        }
    }

    private List<Resource> buildEquipment(String[] workUnits, String[] workCenterName, Long[] workCenterId){
        List<Resource> rst = new ArrayList<Resource>();
        int i=0;
        for(String workUnitName : workUnits){
            Equipment equipment = new Equipment(i*1l);
            String[] workunitConf = workUnitName.split("[@]");
            if(workunitConf.length==2){
                workUnitName = workunitConf[0];
                equipment.setCuringTime(Integer.valueOf(workunitConf[1]));
            }
            if(workunitConf.length==3){
                workUnitName = workunitConf[0];
                if(StringUtils.isNoneBlank(workunitConf[1])) {
                    equipment.setCuringTime(Integer.valueOf(workunitConf[1]));
                }
                equipment.setTransferShopTime(Integer.valueOf(workunitConf[2]));
            }
            equipment.setWorkUnitName(workUnitName);
            equipment.setWorkCenterName(workCenterName[i]);
            equipment.setWorkCenterId(workCenterId[i]);
            equipment.setIsParallel(false);
            rst.add(equipment);
            i++;
        }
        Equipment equipment = new Equipment((i+1)*1l);
        equipment.setWorkUnitName("外协");
        equipment.setWorkUnitCode("GZBSWWDY");
        equipment.setWorkCenterName("外协");
        equipment.setWorkCenterId((i+1)*1l);
        equipment.setIsParallel(false);
        rst.add(equipment);
        return rst;
    }



    private Job buildJob(Long id, LocalDateTime schedulingStartedDate, String demandDate,  BigDecimal quantity,
                         String[] processes, Long[] workCenterId, Duration[] standardTime, Duration[] setupTime){
        LocalDateTime end = DateUtil.toLocalDateTime(DateUtil.parse(demandDate,"yy-MM-dd HH:mm"));
        Job job = new Job(id+"", Duration.between(schedulingStartedDate, end));
        LinkedList<Task> taskList = new LinkedList<Task>();
        int i=1;
        for(String processName : processes){
            String[] temps = processName.split("-");
            Task task = new Task(id*i, job);
            if(temps.length==2){
                processName = temps[0];
                //为1是外协工序
                if(temps[1].equals("1")){
                    task.setOutsourced(true);
                }
            }
            task.setProcessName(processName);
            task.setWorkCenterId(workCenterId[i-1]);
            task.setStandardWorkingTime(standardTime[i-1]);
            task.setSetupTime(setupTime[i-1]);
            task.setOrderQuantity(quantity);
            i++;
            taskList.add(task);
        }
        job.setTasks(taskList);
        return job;
    }

    /*
     * 转换工作日历
     */
    private Calendar.WorkingCalendar buildWorkingCalendar(Resource resource, LocalDateTime scheduleStartDate, String start, String end){

        return new Calendar.WorkingCalendar() {{
            LocalDateTime startDate = DateUtil.toLocalDateTime(DateUtil.parse(start,"yy-MM-dd HH:mm"));
            LocalDateTime endDate = DateUtil.toLocalDateTime(DateUtil.parse(end,"yy-MM-dd HH:mm"));
            setStartedTime(Duration.between(scheduleStartDate, startDate));
            setEndedTime(Duration.between(scheduleStartDate, endDate));
            setResource(resource);
        }};
    }

    private void jobPrint(List<Job> jobs, LocalDateTime scheduleStartDate){
        jobs.forEach(job->{
            System.out.println(job.getId()+" - "+job.getScheduleStatus());
            job.getTasks().forEach(task->{
                if(task.getScheduleStatus() == ScheduleStatus.Success){
                    if(task.getSplitTask()==null||task.getSplitTask().isEmpty()){
                        LocalDateTime start = scheduleStartDate.plus(task.getScheduledStartedTime());
                        LocalDateTime end = scheduleStartDate.plus(task.getScheduledEndedTime());
                        System.out.println(job.getId()+ " - " + task.getProcessName() +" - "+start + " - " +end+" - " +
                                task.getScheduledEquipment().getWorkUnitName());
                    }else{
                        task.getSplitTask().forEach(subTask->{
                            LocalDateTime start = scheduleStartDate.plus(subTask.getScheduledStartedTime());
                            LocalDateTime end = scheduleStartDate.plus(subTask.getScheduledEndedTime());
                            System.out.println(job.getId()+ " - " + subTask.getProcessName() +" - "+start + " - " +end +" - " +
                                    subTask.getScheduledEquipment().getWorkUnitName());
                        });
                    }
                }else{
                    System.out.println(job.getId() + " - " +task.getProcessName() +" - "+task.getScheduleStatus());
                }
            });
        });
    }


}
