global without sharing class SetOlympusCalendarWorkDayBatch implements Database.Batchable<sObject>, Database.Stateful {

    private final Integer DAYCOUNT = 30;
    public List<String> emailMessages = new List<String>();
    private Integer totalCount = 0; // 总件数
    private Integer failedCount = 0;
    private Integer totalCountDone = 0;

    Boolean IsNeedExecute = false; // 2021-03-08  mzy  WLIG-BYHD79  SFDC环境batch合并调查  是否符合执行条件

    // 2021-03-08  mzy  WLIG-BYHD79  SFDC环境batch合并调查  start
    global SetOlympusCalendarWorkDayBatch() {
    }
    global SetOlympusCalendarWorkDayBatch(Boolean NeedExecute) {
        this.IsNeedExecute = NeedExecute;
    }
    // 2021-03-08  mzy  WLIG-BYHD79  SFDC环境batch合并调查  end

    global Database.QueryLocator start(Database.BatchableContext BC) {
        return Database.getQueryLocator([
            SELECT Id
                , Date__c
                , IsWorkDay__c
                , After_1_WorkDay__c
                , After_2_WorkDay__c
                , After_3_WorkDay__c
                , After_4_WorkDay__c
                , After_5_WorkDay__c
                , After_6_WorkDay__c
                , After_7_WorkDay__c
                , After_8_WorkDay__c
                , After_9_WorkDay__c
                , After_10_WorkDay__c
                , After_11_WorkDay__c
                , After_12_WorkDay__c
                , After_13_WorkDay__c
                , After_14_WorkDay__c
                , After_15_WorkDay__c
                , After_16_WorkDay__c
                , After_17_WorkDay__c
                , After_18_WorkDay__c
                , After_19_WorkDay__c
                , After_20_WorkDay__c
                , After_21_WorkDay__c
                , After_22_WorkDay__c
                , After_23_WorkDay__c
                , After_24_WorkDay__c
                , After_25_WorkDay__c
                , After_26_WorkDay__c
                , After_27_WorkDay__c
                , After_28_WorkDay__c
                , After_29_WorkDay__c
                , After_30_WorkDay__c
                , Before_1_WorkDay__c
                , Before_2_WorkDay__c
                , Before_3_WorkDay__c
                , Before_4_WorkDay__c
                , Before_5_WorkDay__c
                , Before_6_WorkDay__c
                , Before_7_WorkDay__c
                , Before_8_WorkDay__c
                , Before_9_WorkDay__c
                , Before_10_WorkDay__c
                , Before_11_WorkDay__c
                , Before_12_WorkDay__c
                , Before_13_WorkDay__c
                , Before_14_WorkDay__c
                , Before_15_WorkDay__c
                , Before_16_WorkDay__c
                , Before_17_WorkDay__c
                , Before_18_WorkDay__c
                , Before_19_WorkDay__c
                , Before_20_WorkDay__c
                , Before_21_WorkDay__c
                , Before_22_WorkDay__c
                , Before_23_WorkDay__c
                , Before_24_WorkDay__c
                , Before_25_WorkDay__c
                , Before_26_WorkDay__c
                , Before_27_WorkDay__c
                , Before_28_WorkDay__c
                , Before_29_WorkDay__c
                , Before_30_WorkDay__c
             FROM OlympusCalendar__c
            WHERE Before_30_WorkDay__c = null
               OR After_30_WorkDay__c = null
            ]);
    }

    global void execute(Database.BatchableContext B, List<OlympusCalendar__c> ocList) {
        Savepoint sp = Database.setSavepoint();
        try {
            totalCount += ocList.size();
            Date minDate = Date.newInstance(4000, 12, 31);
            Date maxDate = Date.newInstance(1700, 1, 1);
            for (OlympusCalendar__c oc : ocList) {
                if (oc.Date__c > maxDate) {
                    maxDate = oc.Date__c;
                }
                if (oc.Date__c < minDate) {
                    minDate = oc.Date__c;
                }
            }
            List<OlympusCalendar__c> olcList = [SELECT Id
                        , Date__c
                        , IsWorkDay__c
                     FROM OlympusCalendar__c
                    WHERE Date__c >= :minDate.addDays(-60)
                      AND Date__c <= :maxDate.addDays(60)
                      AND IsWorkDay__c = 1
                    ORDER BY Date__c];
            for (Integer i = 0; i < ocList.size(); i ++) {
                OlympusCalendar__c oc = ocList[i];
                for (Integer j = 0; j < olcList.size(); j ++) {
                    OlympusCalendar__c olc = olcList[j];
                    if (olc.Date__c > oc.Date__c) {
                        // 因为字段是从1开始的所以直接g从1开始
                        for (Integer g = 1; g <= olcList.size() - j; g ++) {
                            // 因为字段是从1开始所得所以直接用g
                            oc.put('After_' + g + '_WorkDay__c', olcList[j + g - 1].Date__c);
                            // 因为从1开始所以不需要减1
                            if (g == DAYCOUNT) {
                                break;
                            }
                        }
                        Integer k = 1;
                        // 因为当前日历可能是周末，所以从1开始
                        for (Integer g = 1; g <= j; g ++) {
                            // 因为上面上大于的判断。所以前一天可能和日历日期是同一天。所以需要加if文
                            if (olcList[j - g].Date__c < oc.Date__c) {
                                oc.put('Before_' + k + '_WorkDay__c', olcList[j - g].Date__c);
                                if (k == DAYCOUNT) {
                                    break;
                                }
                                k ++;
                            }
                        }
                        break;
                    }
                }
            }
            Database.update(ocList);
            totalCountDone += ocList.size();
        }
        catch (Exception e) {
            Database.rollback(sp);
            emailMessages.add(e.getMessage() + e.getStackTraceString());
            failedCount += ocList.size();
        }
    }

    global void finish(Database.BatchableContext BC) {
        BatchEmailUtil be = new BatchEmailUtil();
        String[] toList = new String[]{UserInfo.getUserEmail()};
        String title = 'OlympusCalendar工作日更新Batch';
        String[] ccList = new String[] {};
        if(this.emailMessages.size() == 0
                && totalCountDone == totalCount){
            // 不发送成功邮件
        }
        else{
            String emailLabel = 'BatchNotify';
            for (OrgWideEmailAddress tmpEmailObj : [SELECT Id, Address, DisplayName 
                    FROM OrgWideEmailAddress
                    WHERE DisplayName like :emailLabel]) {
                ccList.add(tmpEmailObj.Address);
            }
            be.failedMail(toList, ccList, title,
                String.join(this.emailMessages, '\n'),
                totalCount, totalCountDone, failedCount);
            be.send();
        }
        Id execBTId = Database.executeBatch(new InventoryAutoGiveupBatch(true), 200);
    }
}