package cn.cslg.pas.service.upLoadPatent;

import cn.cslg.pas.common.model.vo.ProjectImportPatentVO;
import cn.cslg.pas.common.model.vo.UploadParamsVO;
import cn.cslg.pas.common.utils.DateUtils;
import cn.cslg.pas.common.utils.JsonUtils;
import cn.cslg.pas.domain.PQueueData;
import cn.cslg.pas.domain.QuestionRecord;
import cn.cslg.pas.domain.QueueData;
import cn.cslg.pas.domain.Task;
import cn.cslg.pas.domain.asso.TaskCondition;
import cn.cslg.pas.mapper.QuestionRecordMapper;
import cn.cslg.pas.service.OutInterfaceService;
import cn.cslg.pas.service.PatentInstructionService;
import cn.cslg.pas.service.TaskService;
import cn.cslg.pas.service.UploadPatentBatchService;
import cn.cslg.pas.service.asso.TaskConditionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 1.生产者线程生产专利（根据任务类型调用对应工厂方法执行获取专利数据）
 * 2.装载者线程装载专利（将专利数据装载到专利实体类）
 * 3.消费者线程消费专利（将专利入库）
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class PantentQueueService {
    private final UploadPatentToDBService uploadPatentToDBService;
    private final UploadPatentBatchService uploadPatentBatchService;
    private final MessageService messageService;
    private final TaskService taskService;
    private final TaskConditionService taskConditionService;
    private final ExcutePatentDataExcel excutePatentDataExcel;
    private final ExcutePatentDataEpo excutePatentDataEpo;
    private final ExcutePatentDataStar excutePatentDataStar;
    private final PatentInstructionService patentInstructionService;
    private final OutInterfaceService outInterfaceService;
    private final QuestionRecordService questionRecordService;
    private final QuestionRecordMapper questionRecordMapper;
    private final List<Integer> taskQueueList = new ArrayList<>();
    private final List<PQueueData> setPatentImageQueueList = new ArrayList<>();
    private final List<PQueueData> setPatentZhuluQueueList = new ArrayList<>();
    private final List<PQueueData> setPatentRightQueueList = new ArrayList<>();
    private final List<PQueueData> setPatentInstructionTextQueueList = new ArrayList<>();
    private final List<PQueueData> setPatentInstructionPDFQueueList = new ArrayList<>();
    private final List<QueueData> patentImageQueueList = new ArrayList<>();
    private final List<QueueData> patentZhuluQueueList = new ArrayList<>();
    private final List<QueueData> patentRightQueueList = new ArrayList<>();
    private final List<QueueData> patentInstructionTextQueueList = new ArrayList<>();
    private final List<QueueData> patentInstructionPDFQueueList = new ArrayList<>();
    private final Lock taskLock = new ReentrantLock();
    private final Lock setPatentImageLock = new ReentrantLock();
    private final Lock setPatentZhuluLock = new ReentrantLock();
    private final Lock setPatentRightLock = new ReentrantLock();
    private final Lock setPatentInstructionTextLock = new ReentrantLock();
    private final Lock setPatentInstructionPDFLock = new ReentrantLock();
    private final Lock patentImageLock = new ReentrantLock();
    private final Lock patentZhuluLock = new ReentrantLock();
    private final Lock patentRightLock = new ReentrantLock();
    private final Lock patentInstructionTextLock = new ReentrantLock();
    private final Lock patentInstructionPDFLock = new ReentrantLock();
    private final Condition taskCondition = taskLock.newCondition();
    private final Condition setPatentImageCondition = setPatentImageLock.newCondition();
    private final Condition setPatentZhuluCondition = setPatentZhuluLock.newCondition();
    private final Condition setPatentRightCondition = setPatentRightLock.newCondition();
    private final Condition setPatentInstructionTextCondition = setPatentInstructionTextLock.newCondition();
    private final Condition setPatentInstructionPDFCondition = setPatentInstructionPDFLock.newCondition();
    private final Condition patentImageCondition = patentImageLock.newCondition();
    private final Condition patentZhuluCondition = patentZhuluLock.newCondition();
    private final Condition patentRightCondition = patentRightLock.newCondition();
    private final Condition patentInstructionTextCondition = patentInstructionTextLock.newCondition();
    private final Condition patentInstructionPDFCondition = patentInstructionPDFLock.newCondition();
    private final HashMap<String, Integer> patentIdMap = new HashMap<>();

    /**
     * 生产者：从任务队列取出任务，再调用工厂方法根据任务类型返回对应的生产专利方法的对象将专利分配给消费者
     */
    public void addPatnetToQueue() {
        while (true) {
            Task task = new Task();
            try {
                //判断任务队列是否有任务，若没有则线程等待唤醒
                if (taskQueueList.size() == 0) {
                    taskLock.lock();
                    taskCondition.await();
                }

                //线程被唤醒后 ↓
                if (taskQueueList.size() > 0) {
                    //从任务队列中取出第一个task任务，同时将其从任务队列中剔除
                    task = taskService.getById(taskQueueList.remove(0));
                    //判断任务状态，若不存在或已完成或已暂停或已取消，则跳过继续取下一个任务
                    if (task == null || task.getStatus().equals(2) || task.getStatus().equals(4) || task.getStatus().equals(5)) {
                        continue;
                    }

                    //若是网站导入任务，则将网站导入相关信息存入task对象中（方便生产与消费时使用）
                    if (task.getType().equals(3) || task.getType().equals(4)) {
                        TaskCondition taskCondition = taskConditionService.getById(task.getTaskConditionId());
                        List<String> configCells = Arrays.asList(taskCondition.getConfigCells().split(","));
                        task.setConfigCellsNum(configCells.size());
                        task.setConfigCells(configCells);
                        task.setOrderBy(taskCondition.getOrderBy());
                        task.setOrderByType(taskCondition.getOrderByType());
                        task.setDBType(taskCondition.getDBType());
                        task.setStartNumber(taskCondition.getStartNumber());
                        task.setEndNumber(taskCondition.getEndNumber());
                        if (taskCondition.getIsAddPatentNos() != null && !taskCondition.getIsAddPatentNos().equals("")) {
                            task.setIsAddPatentNos(Arrays.asList(taskCondition.getIsAddPatentNos().split(",")));
                        }
                        if (taskCondition.getIsDeletePatentNos() != null && !taskCondition.getIsDeletePatentNos().equals("")) {
                            task.setIsDeletePatentNos(Arrays.asList(taskCondition.getIsDeletePatentNos().split(",")));
                        }
                        task.setConditions(taskCondition.getConditions());
                        task.setContinueLastInformation(taskCondition.getContinueLastInformation());
                    }

                    //TODO 调用工厂方法，工厂方法会根据任务类型创建并返回对应的生产专利方法的对象
                    IExcutePatentData excutePatentDataObject = createObject(task);
                    if (excutePatentDataObject != null) {
                        //执行方法
                        excutePatentDataObject.startExcute(task);
                    }

                }

            } catch (Exception e) {
                e.printStackTrace();
                //任务表更新状态完成
                task.setStatus(2);
                task.setEndTime(DateUtils.getDateTime());
                taskService.updateById(task);
            }

        }
    }

    /**
     * 装载线程1：著录项目
     */
    public void setPatentZhuLu() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (setPatentZhuluQueueList.size() > 0) {
                    PQueueData pQueueData = setPatentZhuluQueueList.remove(0);
                    Task task = pQueueData.getTask();
                    queueData
                            .setTask(task)
                            .setUploadParamsVO(pQueueData.getUploadParamsVO());

                    //专利之星
                    if (task.getType() == 4) {
                        excutePatentDataStar.setPatentZhuLu(pQueueData.getStarPatent(), pQueueData.getUploadParamsVO());
                    }

                    queueData.setUploadParamsVO(pQueueData.getUploadParamsVO());
                    //装载完成，将其丢入著录消费者队列，并唤醒著录消费者线程
                    patentZhuluQueueList.add(queueData);
                    if (patentZhuluLock.tryLock()) {
                        //patentZhuluLock.lock();
                        patentZhuluCondition.signalAll();
                        patentZhuluLock.unlock();
                    }

                } else {
                    setPatentZhuluLock.lock();
                    setPatentZhuluCondition.await();
                    setPatentZhuluLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 1);
                sendMessage(queueData);
            }

        }
    }

    /**
     * 装载线程2：权要
     */
    public void setPatentRight() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (setPatentRightQueueList.size() > 0) {
                    PQueueData pQueueData = setPatentRightQueueList.remove(0);
                    Task task = pQueueData.getTask();
                    queueData
                            .setTask(task)
                            .setUploadParamsVO(pQueueData.getUploadParamsVO());

                    //专利之星
                    if (task.getType() == 4) {
                        excutePatentDataStar.setPatentClaim(pQueueData.getStarPatent(), pQueueData.getUploadParamsVO());
                    }

                    queueData.setUploadParamsVO(pQueueData.getUploadParamsVO());

                    //装载完成，将其丢入权要消费者队列，并唤醒权要消费者线程
                    patentRightQueueList.add(queueData);
                    if (patentRightLock.tryLock()) {
                        //patentRightLock.lock();
                        patentRightCondition.signalAll();
                        patentRightLock.unlock();
                    }

                } else {
                    setPatentRightLock.lock();
                    setPatentRightCondition.await();
                    setPatentRightLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 2);
                sendMessage(queueData);
            }

        }
    }

    /**
     * 装载线程3：说明书文本
     */
    public void setPatentInstructionText() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (setPatentInstructionTextQueueList.size() > 0) {
                    PQueueData pQueueData = setPatentInstructionTextQueueList.remove(0);
                    Task task = pQueueData.getTask();
                    queueData
                            .setTask(task)
                            .setUploadParamsVO(pQueueData.getUploadParamsVO());

                    //专利之星
                    if (task.getType() == 4) {
                        excutePatentDataStar.setPatentInstructionText(pQueueData.getStarPatent(), pQueueData.getUploadParamsVO());
                    }

                    queueData.setUploadParamsVO(pQueueData.getUploadParamsVO());

                    //装载完成，将其丢入说明书文本消费者队列，并唤醒说明书文本消费者线程
                    patentInstructionTextQueueList.add(queueData);
                    if (patentInstructionTextLock.tryLock()) {
                        //patentInstructionTextLock.lock();
                        patentInstructionTextCondition.signalAll();
                        patentInstructionTextLock.unlock();
                    }

                } else {
                    setPatentInstructionTextLock.lock();
                    setPatentInstructionTextCondition.await();
                    setPatentInstructionTextLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 3);
                sendMessage(queueData);
            }

        }
    }

    /**
     * 装载线程4：说明书pdf
     */
    public void setPatentInstructionPDF() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (setPatentInstructionPDFQueueList.size() > 0) {
                    PQueueData pQueueData = setPatentInstructionPDFQueueList.remove(0);
                    Task task = pQueueData.getTask();
                    queueData
                            .setTask(task)
                            .setUploadParamsVO(pQueueData.getUploadParamsVO());

                    //专利之星
                    if (task.getType() == 4) {
                        excutePatentDataStar.setPatentInstructionPDF(pQueueData.getStarPatent(), pQueueData.getUploadParamsVO());
                    }

                    queueData.setUploadParamsVO(pQueueData.getUploadParamsVO());

                    //装载完成，将其丢入说明书pdf消费者队列，并唤醒说明书pdf消费者线程
                    patentInstructionPDFQueueList.add(queueData);
                    if (patentInstructionPDFLock.tryLock()) {
                        //patentInstructionPDFLock.lock();
                        patentInstructionPDFCondition.signalAll();
                        patentInstructionPDFLock.unlock();
                    }

                } else {
                    setPatentInstructionPDFLock.lock();
                    setPatentInstructionPDFCondition.await();
                    setPatentInstructionPDFLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 4);
                sendMessage(queueData);
            }

        }
    }

    /**
     * 装载线程5：摘要附图
     */
    public void setPatentImage() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (setPatentImageQueueList.size() > 0) {
                    PQueueData pQueueData = setPatentImageQueueList.remove(0);
                    Task task = pQueueData.getTask();
                    queueData
                            .setTask(task)
                            .setUploadParamsVO(pQueueData.getUploadParamsVO());

                    //专利之星
                    if (task.getType() == 4) {
                        excutePatentDataStar.setPatentPicture(pQueueData.getStarPatent(), pQueueData.getUploadParamsVO());
                    }

                    queueData.setUploadParamsVO(pQueueData.getUploadParamsVO());

                    //装载完成，将其丢入摘要附图消费者队列，并唤醒摘要附图消费者线程
                    patentImageQueueList.add(queueData);
                    if (patentImageLock.tryLock()) {
                        //patentImageLock.lock();
                        patentImageCondition.signalAll();
                        patentImageLock.unlock();
                    }

                } else {
                    setPatentImageLock.lock();
                    setPatentImageCondition.await();
                    setPatentImageLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 5);
                sendMessage(queueData);
            }

        }
    }

    /**
     * 消费者1：著录项目入库
     */
    public void pushPatentZhuLuToDB() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (patentZhuluQueueList.size() > 0) {
                    queueData = patentZhuluQueueList.remove(0);
                    //著录项目入库
                    uploadPatentToDBService.uploadPatentZhulu(queueData.getUploadParamsVO());
                    //判断是与专题库关联还是与报告关联
                    if (queueData.getTask().getProjectId() != null && !queueData.getTask().getProjectId().equals(0)) {
                        //与专题库关联入库
                        uploadPatentToDBService.uploadAssoThemaPat(queueData.getUploadParamsVO(), queueData.getTask().getProjectId());
                    } else if (queueData.getTask().getReportId() != null && !queueData.getTask().getReportId().equals(0)) {
                        //与报告关联入库（调用报告系统接口）
                        outInterfaceService.importAssoReportPatentNo(queueData.getTask().getReportId(), queueData.getUploadParamsVO().getPatent().getPatentNo(), queueData.getUploadParamsVO().getPatent().getName());
                    }
                    if (queueData.getTask().getPramJson() != null && !queueData.getTask().getPramJson().equals("")) {
                        ProjectImportPatentVO projectImportPatentVO = JsonUtils.jsonToPojo(queueData.getTask().getPramJson(), ProjectImportPatentVO.class);
                        //自定义字段标引与专利关联入库
                        uploadPatentToDBService.uploadAssoFieldPat(queueData.getUploadParamsVO(), projectImportPatentVO);
                        //文件夹与专利关联入库
                        uploadPatentToDBService.uploadAssoPorPat(queueData.getUploadParamsVO(), projectImportPatentVO);
                    }

                    sendMessage(queueData);
                } else {
                    patentZhuluLock.lock();
                    patentZhuluCondition.await();
                    patentZhuluLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 1);
                sendMessage(queueData);
            }

        }
    }

    /**
     * 消费者2：权利要求入库
     */
    public void pushPatentRightToDB() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (patentRightQueueList.size() > 0) {
                    queueData = patentRightQueueList.remove(0);
                    //权要文本入库
                    uploadPatentToDBService.uploadPatentRight(queueData.getUploadParamsVO());

                    sendMessage(queueData);
                } else {
                    patentRightLock.lock();
                    patentRightCondition.await();
                    patentRightLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 2);
                sendMessage(queueData);
            }

        }
    }

    /**
     * 消费者3：说明书文本入库
     */
    public void pushPatentInstructionTextToDB() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (patentInstructionTextQueueList.size() > 0) {
                    queueData = patentInstructionTextQueueList.remove(0);
                    //说明书文本入库
                    uploadPatentToDBService.uploadPatentInstructionText(queueData.getUploadParamsVO());

                    sendMessage(queueData);
                } else {
                    patentInstructionTextLock.lock();
                    patentInstructionTextCondition.await();
                    patentInstructionTextLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 3);
                sendMessage(queueData);
            }

        }
    }

    /**
     * 消费者4：说明书pdf入库
     */
    public void pushPatentInstructionPDFToDB() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (patentInstructionPDFQueueList.size() > 0) {
                    queueData = patentInstructionPDFQueueList.remove(0);
                    //说明书pdf入库
                    patentInstructionService.edit(queueData.getUploadParamsVO().getPatent().getPatentNo(), queueData.getUploadParamsVO().getFileDTO());

                    sendMessage(queueData);
                } else {
                    patentInstructionPDFLock.lock();
                    patentInstructionPDFCondition.await();
                    patentInstructionPDFLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 4);
                sendMessage(queueData);
            }

        }
    }

    /**
     * 消费者5：摘要附图入库
     */
    public void pushPatentImageToDB() {
        while (true) {
            QueueData queueData = new QueueData();
            try {
                if (patentImageQueueList.size() > 0) {
                    queueData = patentImageQueueList.remove(0);
                    UploadParamsVO uploadParamsVO = queueData.getUploadParamsVO();
                    //摘要附图入库（两种方式：1.Excel摘要附图方式 2.网站导入摘要附图方式）
                    if (queueData.getTask().getType().equals(1)) {
                        uploadPatentToDBService.uploadPatentImage(uploadParamsVO);
                    } else {
                        uploadPatentToDBService.uploadPatentImage2(uploadParamsVO);
                    }

                    sendMessage(queueData);
                } else {
                    patentImageLock.lock();
                    patentImageCondition.await();
                    patentImageLock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
                //记录该任务该专利该部分的失败记录
                saveQuestionRecord(queueData, 5);
                sendMessage(queueData);

            }

        }
    }

    /**
     * 当一个消费者消费完其负责的专利部分，修改成功条数，计算发送进度
     *
     * @param queueData 任务专利队列对象
     */
    public void sendMessage(QueueData queueData) {
        //每完成一个专利(根据计算该任务该专利的所有消费者都完成时)，发送进度
        synchronized ("此为同步锁") {
            //当前进行的任务
            Task task = queueData.getTask();
            //当前进行的任务的专利总数量
            Integer total = task.getTotal();

            //将任务id + "|" + 专利id，拼接成专利的标识（作为当前某一个消费者消费完的这个专利的数量标识）
            String currentPatent = task.getId() + "|" + queueData.getUploadParamsVO().getPatent().getId();
            Integer num = patentIdMap.get(currentPatent);
            int needNum = 3;  //临界默认设为4（即Excel导入任务默认使用5个消费者）
            if (task.getType().equals(3) || task.getType().equals(4)) {  //若是网站导入任务，则临界默认设为下载字段类型数量 - 1
                needNum = task.getConfigCellsNum() - 1;
            }
            if (num == null && needNum > 0) {
                patentIdMap.put(currentPatent, 1);
            } else if (num != null && num < needNum) {
                patentIdMap.put(currentPatent, ++num);
            } else {  //表示当前这个任务这个专利的消费者全都消费结束

                //若任务状态是等待中（即该任务的第一个专利消费完时）， 将状态置为进行中
                if (task.getStatus() == 0) {
                    task.setStatus(1);
                    task.setStartTime(DateUtils.getDateTime());
                    taskService.updateById(task);
                }
                patentIdMap.remove(currentPatent);

                //任务表更新 完成条数+1
                task.setSuccessNum(task.getSuccessNum() + 1);
                Task updateTask = new Task();
                updateTask.setId(task.getId());
                updateTask.setDefaultNum(questionRecordMapper.selectDefaultNum(task.getId()));
                updateTask.setTrueSuccessNum(task.getSuccessNum() - task.getDefaultNum());
                updateTask.setSuccessNum(task.getSuccessNum());
                taskService.updateById(updateTask);

                long percentage = (long) Math.floor((task.getSuccessNum() + 0D) / total * 100D);

                //当全部完成时
                if (task.getSuccessNum().equals(total)) {
                    percentage = 100L;
                    //任务表更新最终数据
                    task.setDefaultNum(questionRecordMapper.selectDefaultNum(task.getId()));
                    task.setTrueSuccessNum(task.getSuccessNum() - task.getDefaultNum());
                    task.setStatus(2);
                    task.setEndTime(DateUtils.getDateTime());
                    taskService.updateById(task);
                }

                //websocket发送进度
                messageService.sendWebsocketMessage(task, total, task.getSuccessNum(), percentage);

            }
        }
    }


    /**
     * 数据丢入著录项目生产队列并唤醒装载著录项目线程
     *
     * @param pQueueData 装载生产队列实体类
     */
    public void zhuluToPQueue(PQueueData pQueueData) {
        setPatentZhuluQueueList.add(pQueueData);
        if (setPatentZhuluLock.tryLock()) {
            //setPatentZhuluLock.lock();
            setPatentZhuluCondition.signalAll();
            setPatentZhuluLock.unlock();
        }
    }

    /**
     * 数据丢入权要生产队列并唤醒装载权要线程
     *
     * @param pQueueData 装载生产队列实体类
     */
    public void rightToPQueue(PQueueData pQueueData) {
        setPatentRightQueueList.add(pQueueData);
        if (setPatentRightLock.tryLock()) {
            //setPatentRightLock.lock();
            setPatentRightCondition.signalAll();
            setPatentRightLock.unlock();
        }
    }

    /**
     * 数据丢入说明书文本生产队列并唤醒装载说明书文本线程
     *
     * @param pQueueData 装载生产队列实体类
     */
    public void instructionTextToPQueue(PQueueData pQueueData) {
        setPatentInstructionTextQueueList.add(pQueueData);
        if (setPatentInstructionTextLock.tryLock()) {
            //setPatentInstructionTextLock.lock();
            setPatentInstructionTextCondition.signalAll();
            setPatentInstructionTextLock.unlock();
        }
    }

    /**
     * 数据丢入说明书pdf生产队列并唤醒装载说明书pdf线程
     *
     * @param pQueueData 装载生产队列实体类
     */
    public void instructionPDFToPQueue(PQueueData pQueueData) {
        setPatentInstructionPDFQueueList.add(pQueueData);
        if (setPatentInstructionPDFLock.tryLock()) {
            //setPatentInstructionPDFLock.lock();
            setPatentInstructionPDFCondition.signalAll();
            setPatentInstructionPDFLock.unlock();
        }
    }

    /**
     * 数据丢入摘要附图生产队列并唤醒装载摘要附图线程
     *
     * @param pQueueData 装载生产队列实体类
     */
    public void imageToPQueue(PQueueData pQueueData) {
        setPatentImageQueueList.add(pQueueData);
        if (setPatentImageLock.tryLock()) {
            //setPatentImageLock.lock();
            setPatentImageCondition.signalAll();
            setPatentImageLock.unlock();
        }
    }

    /**
     * Excel任务专利丢入消费者队列，并唤醒消费者线程
     *
     * @param task           任务对象
     * @param uploadParamsVO 专利实体类对象
     */
    public void patentToQueue(Task task, UploadParamsVO uploadParamsVO) {
        //保存专利基础数据（专利表"os_patent"）
        uploadPatentBatchService.getOneOrInsertOne(uploadParamsVO);


        QueueData queueData = new QueueData()
                .setTask(task)
                .setUploadParamsVO(uploadParamsVO);

        //专利分别加入消费者队列
        patentZhuluQueueList.add(queueData);
        patentRightQueueList.add(queueData);
        patentInstructionTextQueueList.add(queueData);
        patentImageQueueList.add(queueData);

        //通知消费者线程
        //1.著录项目
        if (patentZhuluLock.tryLock()) {
            //patentZhuluLock.lock();
            patentZhuluCondition.signalAll();
            patentZhuluLock.unlock();
        }
        //2.权利要求文本
        if (patentRightLock.tryLock()) {
            //patentRightLock.lock();
            patentRightCondition.signalAll();
            patentRightLock.unlock();
        }
        //3.说明书文本
        if (patentInstructionTextLock.tryLock()) {
            //patentInstructionTextLock.lock();
            patentInstructionTextCondition.signalAll();
            patentInstructionTextLock.unlock();
        }
        //5.摘要附图
        if (patentImageLock.tryLock()) {
            //patentImageLock.lock();
            patentImageCondition.signalAll();
            patentImageLock.unlock();
        }

    }

    /**
     * 生产者任务队列新增任务ids
     *
     * @param taskQueueList 生产者任务队列
     */
    public void taskQueueListAddTask(List<Integer> taskQueueList) {
        this.taskQueueList.addAll(taskQueueList);
    }

    public void taskQueueListRemoveTask(List<Integer> taskQueueList) {
        this.taskQueueList.removeAll(taskQueueList);
    }

    /**
     * 生产者生产队列剔除指定任务的所有专利
     *
     * @param taskId 任务id
     */
    public void setQueueRemoveTasks(Integer taskId) {
        //任务暂停时清除生产者队列中已有的该任务的所有专利
        this.setPatentZhuluQueueList.removeIf(pQueueData -> pQueueData.getTask().getId().equals(taskId));
        this.setPatentRightQueueList.removeIf(pQueueData -> pQueueData.getTask().getId().equals(taskId));
        this.setPatentInstructionTextQueueList.removeIf(pQueueData -> pQueueData.getTask().getId().equals(taskId));
        this.setPatentInstructionPDFQueueList.removeIf(pQueueData -> pQueueData.getTask().getId().equals(taskId));
        this.setPatentImageQueueList.removeIf(pQueueData -> pQueueData.getTask().getId().equals(taskId));
    }

    /**
     * 消费者专利队列剔除指定任务的所有专利
     *
     * @param taskId 任务id
     */
    public void consumerQueueRemoveTasks(Integer taskId) {
        //任务暂停时清除消费者队列中已有的该任务的所有专利
        this.patentZhuluQueueList.removeIf(queueData -> queueData.getTask().getId().equals(taskId));
        this.patentRightQueueList.removeIf(queueData -> queueData.getTask().getId().equals(taskId));
        this.patentInstructionTextQueueList.removeIf(queueData -> queueData.getTask().getId().equals(taskId));
        this.patentInstructionPDFQueueList.removeIf(queueData -> queueData.getTask().getId().equals(taskId));
        this.patentImageQueueList.removeIf(queueData -> queueData.getTask().getId().equals(taskId));
        //任务暂停时清除 patentIdMap（任务id + "|" + 专利id，拼接而成的专利的数量标识（作为辨别某一任务的某一专利消费完成的消费者数量））中该任务的专利数量标识
        Iterator<String> iterator = this.patentIdMap.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (key.contains(taskId + "")) {
                iterator.remove();
                this.patentIdMap.remove(key);
            }
        }

    }

    /**
     * 唤醒生产者线程
     */
    public void awakeTasktch() {
        if (taskLock.tryLock()) {
            //taskLock.lock();
            taskCondition.signalAll();
            taskLock.unlock();
        }
    }

    /**
     * 工厂方法，根据任务类型返回对应的生产专利数据的对象
     *
     * @param task 任务
     * @return 返回获取专利数据的对象
     */
    private IExcutePatentData createObject(Task task) {
        //根据任务的类型创建并返回对应的解析获取专利数据的对象
        switch (task.getType()) {
            case 1:  //Excel导入专利
                return excutePatentDataExcel;
            case 3:  //欧专局网站导入
                return excutePatentDataEpo;
            case 4:  //专利之星网站导入
                return excutePatentDataStar;
            default:
                return null;
        }

    }

    /**
     * 失败记录方法
     *
     * @param queueData 消费者专利队列
     * @param cell      消费者代表的专利字段部分
     */
    public void saveQuestionRecord(QueueData queueData, Integer cell) {
        QuestionRecord questionRecord = new QuestionRecord()
                .setPatentNo(queueData.getUploadParamsVO().getPatent().getPatentNo())
                .setTaskId(queueData.getTask().getId())
                .setCell(cell);
        questionRecordService.save(questionRecord);
    }

}
