package cn.com.qmth.examcloud.core.questions.service.export;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import com.google.gson.Gson;

import cn.com.qmth.examcloud.api.commons.security.bean.User;
import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
import cn.com.qmth.examcloud.core.questions.base.FileDisposeUtil;
import cn.com.qmth.examcloud.core.questions.base.IdUtils;
import cn.com.qmth.examcloud.core.questions.base.IoUtils;
import cn.com.qmth.examcloud.core.questions.base.Model;
import cn.com.qmth.examcloud.core.questions.base.enums.ExamFileType;
import cn.com.qmth.examcloud.core.questions.base.enums.ExportTemplateType;
import cn.com.qmth.examcloud.core.questions.base.enums.ExportType;
import cn.com.qmth.examcloud.core.questions.base.enums.PaperSeqMode;
import cn.com.qmth.examcloud.core.questions.base.excel.ExcelWriter;
import cn.com.qmth.examcloud.core.questions.base.json.JsonImportUtil;
import cn.com.qmth.examcloud.core.questions.base.question.enums.QuesStructType;
import cn.com.qmth.examcloud.core.questions.dao.AudioTimeConfigRepo;
import cn.com.qmth.examcloud.core.questions.dao.PaperDetailRepo;
import cn.com.qmth.examcloud.core.questions.dao.PaperDetailUnitRepo;
import cn.com.qmth.examcloud.core.questions.dao.PaperRepo;
import cn.com.qmth.examcloud.core.questions.dao.QuesRepo;
import cn.com.qmth.examcloud.core.questions.dao.entity.AudioTimeConfig;
import cn.com.qmth.examcloud.core.questions.dao.entity.ExamFile;
import cn.com.qmth.examcloud.core.questions.dao.entity.ExamPaper;
import cn.com.qmth.examcloud.core.questions.dao.entity.ExportStructure;
import cn.com.qmth.examcloud.core.questions.dao.entity.ExtractConfig;
import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionTypeNum;
import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Block;
import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestOption;
import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestPaper;
import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestPaperDetail;
import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestQuestion;
import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Section;
import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Sections;
import cn.com.qmth.examcloud.core.questions.service.ExamFileService;
import cn.com.qmth.examcloud.core.questions.service.ExportTemplateService;
import cn.com.qmth.examcloud.core.questions.service.PaperDetailService;
import cn.com.qmth.examcloud.core.questions.service.PaperService;
import cn.com.qmth.examcloud.core.questions.service.QuestionAudioService;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.DownloadPaperDto;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.ObjectiveQuestionStructure;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailExp;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailUnitExp;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperExp;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.SubjectiveQuestionStructure;
import cn.com.qmth.examcloud.core.questions.service.config.SysProperty;
import cn.com.qmth.examcloud.core.questions.service.util.ExportPaperUtil;
import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
import cn.com.qmth.examcloud.web.filestorage.FileStoragePathEnvInfo;
import cn.com.qmth.examcloud.web.filestorage.YunPathInfo;
import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * @author chenken
 * @date 2017年7月15日 下午4:00:24
 * @company QMTH
 * @description 导出、上传文件service 父类
 */
@Service("exportPaperAbstractService")
public class ExportPaperAbstractService {

    private static final Logger log = LoggerFactory.getLogger(ExportPaperAbstractService.class);

    @Autowired
    protected ExportTemplateService exportTemplateService;

    @Autowired
    protected PaperRepo paperRepo;

    @Autowired
    protected PaperService paperService;

    @Autowired
    protected PaperDetailRepo paperDetailRepo;

    @Autowired
    protected PaperDetailUnitRepo paperDetailUnitRepo;

    @Autowired
    protected ExamFileService examFileService;

    @Autowired
    protected PaperDetailService paperDetailService;

    @Autowired
    protected QuestionAudioService questionAudioService;

    @Autowired
    protected BuildComputerTestJsonService buildComputerTestJsonService;

    @Autowired
    protected InitPaperExpService initPaperExpService;

    @Autowired
    protected QuesRepo quesRepo;

    @Autowired
    protected AudioTimeConfigRepo audioTimeConfigRepo;

    // @Autowired
    // protected QuesPkgPathRepo quesPkgPathRepo;

    @Autowired
    private SysProperty sysProperty;

    public static final String FILL_BLANK_QUESTION_FLAG = "###";

    public static final String TEMP_FILE_EXP = "docxExport/";

    /**
     * Word文件后缀
     */
    public static final String DOCX_SUFFIX = ".docx";

    /**
     * Excel文件后缀
     */
    public static final String EXCEL_SUFFIX = ".xlsx";

    /**
     * ZIP文件后缀
     */
    public static final String ZIP_SUFFIX = ".zip";

    public static final String ENCODING = "UTF-8";

    /**
     * 下划线
     */
    private static final String UNDERSCORE = "_";

    protected static final String OFFLINE = "offLine";


    // 原卷word A4 模板
    public final static Template ORIGINAL_PAPER;

    private static Configuration CONFIGURATION;

    static {

        CONFIGURATION = new Configuration(Configuration.VERSION_2_3_25);
        // 设置编码
        CONFIGURATION.setDefaultEncoding(ENCODING);
        // 设置ftl模板路径
        CONFIGURATION.setClassForTemplateLoading(JsonImportUtil.class, "/");

        Template originalTemplate;
        try {
            originalTemplate = CONFIGURATION.getTemplate("original_paper.ftl", ENCODING);
        } catch (IOException e) {
            originalTemplate = null;
        }
        ORIGINAL_PAPER = originalTemplate;

    }

    /**
     * 下载试卷
     *
     * @param paperId
     * @param zipFileName
     * @throws Exception
     */
    public void downloadPaper(DownloadPaperDto dto) throws Exception {
        PaperExp paperExp = initPaperExp(dto);
        if (paperExp != null) {
            String paperfileName = paperExp.getName() + "_" + paperExp.getCourseNo() + "_"
                    + ExamFileType.PAPER.getName() + DOCX_SUFFIX;
            File directory = new File(TEMP_FILE_EXP + File.separator + dto.getZipFileName());
            if (OFFLINE.equals(dto.getExamType())) {
                if (StringUtils.isBlank(paperExp.getExamRemark())) {
                    paperExp.setExamRemark("<p></p>");
                }

                ExportPaperUtil.createPaperDocFile(dto.getRootOrgId(),paperExp, directory,paperfileName, ExportTemplateType.OUTLINE_PAPER_EXPORT);
            } else {
                ExportPaperUtil.createPaperDocFile(dto.getRootOrgId(),paperExp, directory,paperfileName, ExportTemplateType.PAPER_EXPORT);
            }

            // 下载音频
            downloadAudio(paperExp, dto.getZipFileName());
        }
    }

    /**
     * 下载答案
     *
     * @param paperId
     * @param zipFileName
     * @throws Exception
     */
    public void downloadPaperAnswer(DownloadPaperDto dto) throws Exception {
        PaperExp paperExp = initPaperExp(dto);
        if (paperExp != null) {
            String answerFileName = paperExp.getName() + "_" + paperExp.getCourseNo() + "_"
                    + ExamFileType.ANSWER.getName() + DOCX_SUFFIX;
            File directory = new File(TEMP_FILE_EXP + File.separator + dto.getZipFileName());
            ExportPaperUtil.createPaperDocFile(dto.getRootOrgId(),paperExp, directory,answerFileName, ExportTemplateType.ANWSER_EXPORT);
        }
    }

    /**
     * 上传试卷相关文件
     *
     * @param extractConfig
     * @param paperId
     * @param exportStructure
     * @param accessUser
     * @throws Exception
     */
    public void uploadFile(ExtractConfig extractConfig, String paperId, ExportStructure exportStructure,
            User accessUser, ExamPaper examPaper,PaperSeqMode seqMode){
    	DownloadPaperDto dto=new DownloadPaperDto();
    	dto.setPaperId(paperId);
    	dto.setSeqMode(seqMode);
        PaperExp paperExp = initPaperExp(dto);
        if (paperExp != null) {
            String currNum = CommonUtils.getCurNum();
            // 没有试卷结构导出设置
            if (exportStructure == null) {
                // 上传试卷
                uploadPaperOrAnswerFile(paperExp, extractConfig, accessUser, currNum,
                        ExportTemplateType.PAPER_EXPORT, ExamFileType.PAPER, examPaper);
                // 上传答案
                uploadPaperOrAnswerFile(paperExp, extractConfig, accessUser, currNum,
                        ExportTemplateType.ANWSER_EXPORT, ExamFileType.ANSWER, examPaper);
            } else if (exportStructure != null && exportStructure.getExportType() == ExportType.NORMAL) {
                List<QuestionTypeNum> questionTypeNums = exportStructure.getQuestionTypeNums();
                // 检查试卷中客观题的数量是否大于试卷导出设置中的设置的数量
                checkObjectiveDetailsNum(paperExp, questionTypeNums);
                // 上传试卷
                uploadPaperOrAnswerFile(paperExp, extractConfig, accessUser, currNum,
                        ExportTemplateType.PAPER_EXPORT, ExamFileType.PAPER, examPaper);
                // 上传答案
                uploadPaperOrAnswerFile(paperExp, extractConfig, accessUser, currNum,
                        ExportTemplateType.ANWSER_EXPORT, ExamFileType.ANSWER, examPaper);
                // 上传试卷结构 不能在上传试卷和答案之前
                uploadPaperStructure(paperExp, extractConfig, accessUser, currNum, questionTypeNums, examPaper);
            } else if (exportStructure != null && exportStructure.getExportType() == ExportType.ONLINE) {
                // 上传机考JSON文件
                uploadComputerTestFile(extractConfig, accessUser, examPaper);
            }
        }
    }


    /**
     * 将数字1,2,3,4转化成A,B,C,D
     *
     * @param number
     * @return
     */
    public String getOptionNum(int number) {
        char optionNum = (char) (65 + number);
        return String.valueOf(optionNum);
    }


    /**
     * 计算选项长度
     *
     * @param tmpText
     * @return
     */
    public int optionsLength(String tmpText) {
        String regEx = "[\\u4e00-\\u9fa5]";
        String term = tmpText.replaceAll(regEx, "aa");
        return term.length();
    }


    /**
     * 设置大题标题
     */
    public void setExportQuestionTitle(List<PaperDetailExp> details, boolean isWord) {
        if (CollectionUtils.isEmpty(details)) {
            return;
        }

        final String style = "<em class=\"e_num\">%s</em>";

        for (PaperDetailExp detail : details) {
            String perQuesScore = checkPaperDetailUnitScore(detail);
            if (perQuesScore != null) {
                perQuesScore = CommonUtils.clearZeroPoint(perQuesScore);
                if (!isWord) {
                    perQuesScore = String.format(style, perQuesScore);
                }
                perQuesScore = String.format("每小题%s分，", perQuesScore);
            } else {
                perQuesScore = "";// 每题分数不一致则不注明
            }

            QuesStructType type = detail.getPaperDetailUnits().get(0).getQuestionType();
            String detailScore = CommonUtils.formatValue(detail.getScore());
            String unitCount = String.valueOf(detail.getUnitCount());

            if (!isWord) {
                detailScore = String.format(style, detailScore);
                unitCount = String.format(style, unitCount);
            }
            String title = String.format("（本大题共%s小题，%s共%s分）", unitCount, perQuesScore, detailScore);

            if (type == QuesStructType.SINGLE_ANSWER_QUESTION) {
                detail.setTitleDetail("在每小题列出的备选项中只有一个符合题目要求的，请将其选出并将“答题卡”的相应代码涂黑，错涂、多涂或未涂均无分");
            } else if (type == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
                detail.setTitleDetail("在每小题列出的备选项中有一个或多个符合题目要求的，请将符合项选出并将“答题卡”的相应代码涂黑");
            } else if (type == QuesStructType.BOOL_ANSWER_QUESTION) {
                detail.setTitleDetail("正确的填涂√、错误填涂×。错涂、多涂或未涂均无分");
            }

            detail.setTitle(title);
        }
    }

    /**
     * 创建机考文件，并打包上传至又拍云
     *
     * @param extractConfig
     * @param accessUser
     * @throws IOException
     */
    protected void uploadComputerTestFile(ExtractConfig extractConfig, User accessUser, ExamPaper examPaper){
        List<ComputerTestPaper> computerTestPaperList = buildComputerTestJsonService
                .buildComputerTestPapers(extractConfig);
        String currentTimeStr = CommonUtils.getCurNum();
        for (int i = 0; i < computerTestPaperList.size(); i++) {
            ComputerTestPaper computerTestPaper = computerTestPaperList.get(i);
            String jsonDirectoryName = currentTimeStr + UNDERSCORE + ExamFileType.COMPUTERTEST_PACKAGE.name()
                    + UNDERSCORE + i;
            String jsonDirectoryPath = TEMP_FILE_EXP + File.separator + jsonDirectoryName;
            // 新建文件夹
            File dirFile = new File(jsonDirectoryPath);
            if (!dirFile.exists()) {
                dirFile.mkdirs();
            }
            // 下载试卷中的音频文件到jsonDirectoryPath文件夹中
            downloadQuestionAudio(computerTestPaper, jsonDirectoryPath, extractConfig.getExamId() + "");
            // 将computerTestPaper对象生成JSON文件存放在jsonDirectoryPath中
            makeComputerTestPaperToJsonFile(extractConfig, computerTestPaper, jsonDirectoryPath);
            // 将文件夹打包成zip压缩包放在docxExport下
            FileDisposeUtil.fileToZip(jsonDirectoryPath, "docxExport", jsonDirectoryName);
            // 上传zip压缩包到又拍云
            File zipFile = new File(TEMP_FILE_EXP + jsonDirectoryName + ZIP_SUFFIX);
            String zipUpyunFilePath = sysProperty.getUploadPath() + extractConfig.getOrgId() + "/" + jsonDirectoryName
                    + ZIP_SUFFIX;
//            UpYun upyun = new UpYun(sysProperty.getBucketName(), sysProperty.getUserName(), sysProperty.getPassword());
//            upyun.writeFile(zipUpyunFilePath, zipFile, true);
            //通用存储
    		FileStoragePathEnvInfo env=new FileStoragePathEnvInfo();
    		env.setRelativePath(zipUpyunFilePath);
    		YunPathInfo pi=FileStorageUtil.saveFile("computerTestFile", env, zipFile,null);
            // 保存数据库记录
            ExamFile examFile = new ExamFile(computerTestPaper, extractConfig, pi.getRelativePath(),
                    ExamFileType.COMPUTERTEST_PACKAGE, ZIP_SUFFIX);
            examFile.setGroupCode(examPaper.getGroupCode());
            examFileService.saveExamFile(examFile, accessUser);

            // 删除本地生成的文件
            IoUtils.removeFile(zipFile);
            FileUtils.deleteQuietly(dirFile);
        }
    }

    /**
     * 将computerTestPaper对象生成JSON文件存放在jsonDirectoryPath中
     *
     * @param extractConfig
     * @param computerTestPaper
     * @param jsonDirectoryPath
     */
    private void makeComputerTestPaperToJsonFile(ExtractConfig extractConfig, ComputerTestPaper computerTestPaper,
            String jsonDirectoryPath) {
        // 创建新的JSON文件
        File file = new File(jsonDirectoryPath + File.separator + extractConfig.getCourseCode() + ".json");
        // 将对象转成 json对象
        Gson gson = new Gson();
        String strJSON = gson.toJson(computerTestPaper);
        strJSON = CommonUtils.replaceUnicodeStr(strJSON);

        // 生成文件流写入JSON文件
        try (FileOutputStream outputStream = new FileOutputStream(file);) {
            outputStream.write(strJSON.getBytes());
        } catch (FileNotFoundException e) {
            log.error(e.getMessage(), e);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 下载题目音频文件
     *
     * @param computerTestPaper
     */
    private void downloadQuestionAudio(ComputerTestPaper computerTestPaper, String jsonDirectoryPath, String examId) {
        List<ComputerTestPaperDetail> details = computerTestPaper.getDetails();
        for (ComputerTestPaperDetail detail : details) {
            List<ComputerTestQuestion> questions = detail.getQuestions();
            for (ComputerTestQuestion computerTestQuestion : questions) {
                getBodyAndOptionAudioFile(computerTestQuestion, computerTestQuestion.getBody(), jsonDirectoryPath,
                        computerTestPaper, examId, detail, null, 1);
                List<ComputerTestOption> options = computerTestQuestion.getOptions();
                for (ComputerTestOption option : options) {
                    getBodyAndOptionAudioFile(computerTestQuestion, option.getBody(), jsonDirectoryPath,
                            computerTestPaper, examId, detail, option, 2);
                }
                // 子题音频处理
                // List<ComputerTestQuestion> subQuestions =
                // question.getSubQuestions();
            }
        }
    }

    private void getBodyAndOptionAudioFile(ComputerTestQuestion computerTestQuestion, Sections bodySections,
            String jsonDirectoryPath, ComputerTestPaper computerTestPaper, String examId,
            ComputerTestPaperDetail detail, ComputerTestOption option, int number) {
        List<Section> sectionList = bodySections.getSections();
        int bNum = 1;
        int oNum = 1;
        for (Section section : sectionList) {
            List<Block> blocks = section.getBlocks();
            for (Block block : blocks) {
                if ("audio".equals(block.getType())) {
                    computerTestPaper.setHasVideo(1);
                    PaperDetailUnit paperDetailUnit = Model
                            .of(paperDetailUnitRepo.findById(computerTestQuestion.getId()));
                    QuestionAudio audio = questionAudioService.findAudioById(block.getValue());
                    // block.setValue(block.getValue()+"."+audio.getFileSuffixes());
                    if (audio != null) {
                        AudioTimeConfig audioTime = new AudioTimeConfig();
                        audioTime.setCourseCode(computerTestPaper.getCourseCode());
                        audioTime.setExamId(examId);
                        audioTime.setGroupCode(computerTestPaper.getGroupCode());
                        audioTime.setPaperDetailUnit(paperDetailUnit);
                        AudioTimeConfig audioTimeConfig = Model.of(audioTimeConfigRepo.findOne(Example.of(audioTime)));
                        if (audioTimeConfig != null) {
                            if (audioTimeConfig.getPlayTime() == null) {
                                block.setPlayTime(-1);
                            } else {
                                block.setPlayTime(audioTimeConfig.getPlayTime());
                            }
                        } else {
                            block.setPlayTime(-1);
                        }
                        String audioFileName = "";
                        if (number == 1) {
                            audioFileName = audio.getId() + "_" + detail.getNumber() + "_"
                                    + computerTestQuestion.getNumber() + "_1_" + bNum + "." + audio.getFileSuffixes();
                            bNum++;
                        } else {
                            audioFileName = audio.getId() + "_" + detail.getNumber() + "_"
                                    + computerTestQuestion.getNumber() + "_2_" + option.getNumber() + oNum + "."
                                    + audio.getFileSuffixes();
                            oNum++;
                        }
                      //通用存储
                        FileDisposeUtil.saveUrlAs(FileStorageUtil.realPath(audio.getFileUrl()),
                                jsonDirectoryPath + File.separator + audioFileName);
                    }
                }
            }
        }
    }

    /**
     * 生成试卷或答案Word，上传至又拍云
     */
    protected void uploadPaperOrAnswerFile(PaperExp paperExp, ExtractConfig extractConfig, User accessUser,
            String currNum, ExportTemplateType templateType, ExamFileType examFileType, ExamPaper examPaper) {
        String paperFileName = currNum + examFileType.name() + DOCX_SUFFIX;
        File directory = new File(TEMP_FILE_EXP + IdUtils.uuid() + File.separator);
        directory.mkdir();
        try {
            // DocxProcessUtil.exportWord(paperExp, paperFileName, template);
            // DocxProcessUtil.processImage(paperFileName,
            // getPkgList(paperExp.getId()));
            File file = new File(directory.getAbsoluteFile() + File.separator + paperFileName);
            ExportPaperUtil.createPaperDocFile(accessUser.getRootOrgId(), paperExp, directory, paperFileName,
                    templateType);
            String paperFilePath = sysProperty.getUploadPath() + extractConfig.getOrgId() + "/" + paperFileName;
//            UpYun upyun = new UpYun(sysProperty.getBucketName(), sysProperty.getUserName(), sysProperty.getPassword());
//            upyun.writeFile(paperFilePath, file, true);
          //通用存储
    		FileStoragePathEnvInfo env=new FileStoragePathEnvInfo();
    		env.setRelativePath(paperFilePath);
    		YunPathInfo pi=FileStorageUtil.saveFile("paperOrAnswerFile", env, file,null);
            ExamFile examFile = new ExamFile(paperExp.getId(), extractConfig, pi.getRelativePath(), examFileType, DOCX_SUFFIX);
            examFile.setGroupCode(examPaper.getGroupCode());
            examFile.setFileName(paperExp.getName()+"_"+extractConfig.getCourseName() + "_" + extractConfig.getCourseCode() + "_"
                    + examFileType.getName() + "_" + examFile.getGroupCode() + DOCX_SUFFIX);
            examFileService.saveExamFile(examFile, accessUser);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                FileUtils.deleteDirectory(directory);
            } catch (IOException e) {
            }
        }
    }

    /**
     * 生成试卷结构，上传至又拍云
     */
    protected void uploadPaperStructure(PaperExp paperExp, ExtractConfig extractConfig, User accessUser, String currNum,
            List<QuestionTypeNum> questionTypeNums, ExamPaper examPaper) {
        exportObjectiveQuestionStructures(paperExp, extractConfig, accessUser, currNum, questionTypeNums, examPaper);
        exportSubjectiveQuestionStructures(paperExp, extractConfig, accessUser, currNum, examPaper);
    }

    /**
     * 获得客观题导出结构，并上传至又拍云
     *
     * @param paperExp
     * @return
     */
    protected void exportObjectiveQuestionStructures(PaperExp paperExp, ExtractConfig extractConfig, User accessUser,
            String currNum, List<QuestionTypeNum> questionTypeNums, ExamPaper examPaper) {
        String objectiveFilename = currNum + ExamFileType.PAPER_STRUCTURE_OBJECTIVE.name() + EXCEL_SUFFIX;
        // 得到试卷中的客观大题
        List<PaperDetailExp> objectiveDetails = getAllObjectiveDetails(paperExp);
        // 根据试卷结构导出设置中的数量补齐客观题
        List<PaperDetailExp> paperDetailExps = fillObjectiveQuestions(objectiveDetails, questionTypeNums);
        List<ObjectiveQuestionStructure> objectiveQuestionStructureList = new ArrayList<>();

        // String paperType = findPaperType(extractConfig,paperExp.getId());
        String paperType = examPaper.getGroupCode();
        for (PaperDetailExp paperDetailExp : paperDetailExps) {
            for (PaperDetailUnitExp unit : paperDetailExp.getPaperDetailUnits()) {
                objectiveQuestionStructureList
                        .add(new ObjectiveQuestionStructure(paperExp, paperDetailExp, unit, paperType));
            }
        }

        ExcelWriter objectiveExcelExporter = new ExcelWriter(ObjectiveQuestionStructure.class);
        File file = new File(TEMP_FILE_EXP + objectiveFilename);
        try (FileOutputStream out = new FileOutputStream(file);) {
            objectiveExcelExporter.write(objectiveFilename, objectiveQuestionStructureList, out);

            String objectiveFilePath = sysProperty.getUploadPath() + extractConfig.getOrgId() + "/" + objectiveFilename;
//            UpYun upyun = new UpYun(sysProperty.getBucketName(), sysProperty.getUserName(), sysProperty.getPassword());
//            upyun.writeFile(objectiveFilePath, file, true);
            
            //通用存储
      		FileStoragePathEnvInfo env=new FileStoragePathEnvInfo();
      		env.setRelativePath(objectiveFilePath);
      		YunPathInfo pi=FileStorageUtil.saveFile("objectiveQuestionStructures", env, file,null);

            ExamFile examFile = new ExamFile(paperExp.getId(), extractConfig, pi.getRelativePath(),
                    ExamFileType.PAPER_STRUCTURE_OBJECTIVE, EXCEL_SUFFIX);
            examFile.setGroupCode(examPaper.getGroupCode());
            examFile.setFileName(extractConfig.getCourseName() + "_" + extractConfig.getCourseCode() + "_"
                    + ExamFileType.PAPER_STRUCTURE_OBJECTIVE + "_" + examPaper.getGroupCode() + EXCEL_SUFFIX);
            examFileService.saveExamFile(examFile, accessUser);

            IoUtils.removeFile(file);
        } catch (FileNotFoundException e) {
            log.error(e.getMessage(), e);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 获得主观题导出结构，并上传至又拍云
     *
     * @param paperExp
     * @return
     */
    protected void exportSubjectiveQuestionStructures(PaperExp paperExp, ExtractConfig extractConfig, User accessUser,
            String currNum, ExamPaper examPaper) {
        String subjectiveFileName = currNum + ExamFileType.PAPER_STRUCTURE_SUBJECTIVE.name() + EXCEL_SUFFIX;
        List<PaperDetailExp> subjectiveDetails = getAllSubjectiveDetails(paperExp);
        List<SubjectiveQuestionStructure> subjectiveQuestionStructureList = new ArrayList<>();
        // String paperType = findPaperType(extractConfig,paperExp.getId());
        String paperType = examPaper.getGroupCode();
        for (PaperDetailExp paperDetailExp : subjectiveDetails) {
            for (PaperDetailUnitExp unit : paperDetailExp.getPaperDetailUnits()) {
                subjectiveQuestionStructureList
                        .add(new SubjectiveQuestionStructure(paperExp, paperDetailExp, unit, paperType));
            }
        }

        ExcelWriter subjectiveExcelExporter = new ExcelWriter(SubjectiveQuestionStructure.class);
        File file = new File(TEMP_FILE_EXP + subjectiveFileName);
        try (FileOutputStream out = new FileOutputStream(file);) {
            subjectiveExcelExporter.write(subjectiveFileName, subjectiveQuestionStructureList, out);

            String subjectiveFilePath = sysProperty.getUploadPath() + extractConfig.getOrgId() + "/"
                    + subjectiveFileName;
//            UpYun upyun = new UpYun(sysProperty.getBucketName(), sysProperty.getUserName(), sysProperty.getPassword());
//            upyun.writeFile(subjectiveFilePath, file, true);

            //通用存储
      		FileStoragePathEnvInfo env=new FileStoragePathEnvInfo();
      		env.setRelativePath(subjectiveFilePath);
      		YunPathInfo pi=FileStorageUtil.saveFile("subjectiveQuestionStructures", env, file,null);
      		
            ExamFile examFile = new ExamFile(paperExp.getId(), extractConfig, pi.getRelativePath(),
                    ExamFileType.PAPER_STRUCTURE_SUBJECTIVE, EXCEL_SUFFIX);
            examFile.setGroupCode(examPaper.getGroupCode());
            examFile.setFileName(extractConfig.getCourseName() + "_" + extractConfig.getCourseCode() + "_"
                    + ExamFileType.PAPER_STRUCTURE_SUBJECTIVE + "_" + examPaper.getGroupCode() + EXCEL_SUFFIX);
            examFileService.saveExamFile(examFile, accessUser);

            IoUtils.removeFile(file);
        } catch (FileNotFoundException e) {
            log.error(e.getMessage(), e);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 根据试卷结构导出设置中的数量补齐客观题
     *
     * @param objectiveDetails
     * @param questionTypeNums
     */
    public List<PaperDetailExp> fillObjectiveQuestions(List<PaperDetailExp> objectiveDetails,
            List<QuestionTypeNum> questionTypeNums) {
        // 1.得到所有客观题大题的类型
        Set<QuesStructType> types = new HashSet<>();
        for (PaperDetailExp paperDetailExp : objectiveDetails) {
            types.add(QuesStructType.getQuesStructTypeById(paperDetailExp.getSortNumber()));
        }
        List<PaperDetailExp> paperDetailExps = new ArrayList<>();
        // 如果没有单选
        if (!types.contains(QuesStructType.SINGLE_ANSWER_QUESTION)) {
            buildObjectiveQuestion(paperDetailExps, questionTypeNums, QuesStructType.SINGLE_ANSWER_QUESTION);
        } else {
            addObjectiveQuestion(paperDetailExps, objectiveDetails, questionTypeNums,
                    QuesStructType.SINGLE_ANSWER_QUESTION);
        }
        // 如果没有多选
        if (!types.contains(QuesStructType.MULTIPLE_ANSWER_QUESTION)) {
            buildObjectiveQuestion(paperDetailExps, questionTypeNums, QuesStructType.MULTIPLE_ANSWER_QUESTION);
        } else {
            addObjectiveQuestion(paperDetailExps, objectiveDetails, questionTypeNums,
                    QuesStructType.MULTIPLE_ANSWER_QUESTION);
        }
        // 如果没有判断
        if (!types.contains(QuesStructType.BOOL_ANSWER_QUESTION)) {
            buildObjectiveQuestion(paperDetailExps, questionTypeNums, QuesStructType.BOOL_ANSWER_QUESTION);
        } else {
            addObjectiveQuestion(paperDetailExps, objectiveDetails, questionTypeNums,
                    QuesStructType.BOOL_ANSWER_QUESTION);
        }
        return paperDetailExps;
    }

    /**
     * 根据数量和类型构建客观题
     *
     * @param questionTypeNums
     * @param quesStructType
     * @return
     */
    private void buildObjectiveQuestion(List<PaperDetailExp> paperDetailExps, List<QuestionTypeNum> questionTypeNums,
            QuesStructType quesStructType) {
        // 1.得到需要的题量
        int quantity = getQuantity(questionTypeNums, quesStructType);
        // 2.构建题目
        PaperDetailExp paperDetailExp = new PaperDetailExp();
        List<PaperDetailUnitExp> paperDetailUnits = new ArrayList<PaperDetailUnitExp>();
        for (int i = 0; i < quantity; i++) {
            paperDetailUnits.add(new PaperDetailUnitExp(quesStructType, i + 1));
        }
        paperDetailExp.setPaperDetailUnits(paperDetailUnits);
        paperDetailExp.setNumber(Integer.parseInt(quesStructType.getId() + ""));
        paperDetailExps.add(paperDetailExp);
    }

    /**
     * 补齐需要的客观题
     *
     * @param objectiveDetails
     * @param questionTypeNums
     */
    private void addObjectiveQuestion(List<PaperDetailExp> paperDetailExps, List<PaperDetailExp> objectiveDetails,
            List<QuestionTypeNum> questionTypeNums, QuesStructType quesStructType) {
        // 得到当前题量
        int currentSize = 0;
        /**
         * 构建新的大题 遍历所有的客观大题，如果是符合的类型，就添加该大题
         * 该大题中，如果有套题，要将该套题下的小题拆出来，添加到大题中，并删除原套题
         */
        for (PaperDetailExp paperDetailExp : objectiveDetails) {
            if (paperDetailExp.getSortNumber().equals(quesStructType.getId())) {
                PaperDetailExp newPaperDetailExp = new PaperDetailExp();
                List<PaperDetailUnitExp> newPaperDetailUnits = new ArrayList<>();

                // 得到大题下的所有小题
                List<PaperDetailUnitExp> paperDetailUnits = paperDetailExp.getPaperDetailUnits();
                for (PaperDetailUnitExp paperDetailUnitExp : paperDetailUnits) {
                    if (paperDetailUnitExp.getQuestionType() != QuesStructType.NESTED_ANSWER_QUESTION) {
                        newPaperDetailUnits.add(paperDetailUnitExp);
                        currentSize += 1;
                    } else {
                        List<Question> subQuestions = paperDetailUnitExp.getQuestion().getSubQuestions();
                        if (subQuestions != null && subQuestions.size() > 0) {
                            for (int i = 0; i < subQuestions.size(); i++) {
                                newPaperDetailUnits.add(new PaperDetailUnitExp(quesStructType, subQuestions.get(i)));
                            }
                            currentSize += subQuestions.size();
                        }
                    }
                }
                // 设置小题
                newPaperDetailExp.setPaperDetailUnits(newPaperDetailUnits);
                // 设置大题题号
                newPaperDetailExp.setNumber(Integer.parseInt(quesStructType.getId() + ""));
                newPaperDetailExp.setSortNumber(paperDetailExp.getSortNumber());
                paperDetailExps.add(newPaperDetailExp);
            }
        }

        // 刷一遍number
        int num = 0;
        for (int i = 0; i < paperDetailExps.size(); i++) {
            PaperDetailExp detailExp = paperDetailExps.get(i);

            if (quesStructType.getId().equals(detailExp.getSortNumber())) {
                List<PaperDetailUnitExp> exps = detailExp.getPaperDetailUnits();
                for (int j = 0; j < exps.size(); j++) {
                    num++;
                    exps.get(j).setNumber(num);
                }
            }
        }

        // 计算差额、补齐试题
        int quantity = getQuantity(questionTypeNums, quesStructType) - currentSize;
        PaperDetailExp paperDetailExp = new PaperDetailExp();
        List<PaperDetailUnitExp> paperDetailUnits = new ArrayList<>();
        for (int i = 0; i < quantity; i++) {
            int number = currentSize + (i + 1);
            paperDetailUnits.add(new PaperDetailUnitExp(quesStructType, number));
        }
        paperDetailExp.setPaperDetailUnits(paperDetailUnits);
        // 设置大题题号
        paperDetailExp.setNumber(Integer.parseInt(quesStructType.getId() + ""));
        paperDetailExps.add(paperDetailExp);
    }

    // 根据类型得到需要的题量
    private Integer getQuantity(List<QuestionTypeNum> questionTypeNums, QuesStructType quesStructType) {
        int quantity = 0;
        for (QuestionTypeNum typeNum : questionTypeNums) {
            if (typeNum.getQuestionType() == quesStructType) {
                quantity = typeNum.getQuantity();
            }
        }
        return quantity;
    }

    /**
     * 得到试卷中所有客观大题 与试题类型枚举:QuesStructType中的ID对应
     *
     * @param paperExp
     * @return
     */
    public List<PaperDetailExp> getAllObjectiveDetails(PaperExp paperExp) {
        List<PaperDetailExp> objectiveDetails = new ArrayList<PaperDetailExp>();
        for (PaperDetailExp paperDetailExp : paperExp.getPaperDetails()) {
            if (paperDetailExp.getSortNumber() == 1L || paperDetailExp.getSortNumber() == 2L
                    || paperDetailExp.getSortNumber() == 3L) {
                objectiveDetails.add(paperDetailExp);
            }
        }
        return objectiveDetails;
    }

    /**
     * 得到所有主观大题 与试题类型枚举:QuesStructType中的ID对应
     *
     * @param paperExp
     * @return
     */
    public List<PaperDetailExp> getAllSubjectiveDetails(PaperExp paperExp) {
        List<PaperDetailExp> subjectiveDetails = new ArrayList<PaperDetailExp>();
        for (PaperDetailExp paperDetailExp : paperExp.getPaperDetails()) {
            if (paperDetailExp.getSortNumber() == 4L || paperDetailExp.getSortNumber() == 5L
                    || paperDetailExp.getSortNumber() == 6L) {
                subjectiveDetails.add(paperDetailExp);
            }
        }
        return subjectiveDetails;
    }

    /**
     * 检查客观题数量是否小于试卷结构导出设置的数量
     *
     * @param paperExp
     * @param questionTypeNums
     * @return
     */
    protected void checkObjectiveDetailsNum(PaperExp paperExp, List<QuestionTypeNum> questionTypeNums) {
        List<PaperDetailExp> objectiveDetails = getAllObjectiveDetails(paperExp);
        for (QuestionTypeNum typeNum : questionTypeNums) {
            List<PaperDetailUnitExp> paperDetailUnits = new ArrayList<>();
            for (PaperDetailExp paperDetailExp : objectiveDetails) {
                if (paperDetailExp.getSortNumber().equals(typeNum.getQuestionType().getId())) {
                    paperDetailUnits.addAll(paperDetailExp.getPaperDetailUnits());
                }
            }

            int currentSize = 0;
            for (PaperDetailUnitExp paperDetailUnitExp : paperDetailUnits) {
                if (paperDetailUnitExp.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
                    currentSize += paperDetailUnitExp.getQuestion().getSubQuestions().size();
                } else {
                    currentSize++;
                }
            }
            if (currentSize > typeNum.getQuantity()) {
                throw new RuntimeException("试卷中" + typeNum.getQuestionType().getName() + "题题量超出设定范围" + ",当前试卷题量:"
                        + currentSize + ",设定题量:" + typeNum.getQuantity() + ",请核实后重新设置导出规则！");
            }
        }
    }


    /**
     * 筛选出试卷类型
     *
     * @param extractConfig
     * @param paperId
     * @return
     */
    @SuppressWarnings("unused")
    private String findPaperType(ExtractConfig extractConfig, String paperId) {
        String paperType = "";
        Map<String, String> paperIdMap = extractConfig.getFinishedPaperIdMap();
        Set<Entry<String, String>> entry = paperIdMap.entrySet();
        Iterator<Entry<String, String>> iterator = entry.iterator();
        while (iterator.hasNext()) {
            Entry<String, String> next = iterator.next();
            if (paperId.equals(next.getValue())) {
                paperType = next.getKey();
                break;
            }
        }
        return paperType;
    }

    /**
     * 下载试卷音频
     *
     * @param zipFileName
     */
    public void downloadAudio(PaperExp paperExp, String zipFileName) {
        // 先判断是否是音频试卷
        if (paperExp.getHasAudio() != null && paperExp.getHasAudio() == true) {
//            UpYun upyun = new UpYun(sysProperty.getBucketName(), sysProperty.getUserName(), sysProperty.getPassword());
            // 取到所有大题
            List<PaperDetailExp> paperDetailExps = paperExp.getPaperDetails();
            if (paperDetailExps != null && paperDetailExps.size() > 0) {
                for (PaperDetailExp paperDetailExp : paperDetailExps) {
                    // 取到所有小题
                    List<PaperDetailUnitExp> paperDetailUnitExps = paperDetailExp.getPaperDetailUnits();
                    if (paperDetailUnitExps != null && paperDetailUnitExps.size() > 0) {
                        for (PaperDetailUnitExp unit : paperDetailUnitExps) {
                            if (unit.getQuestion().getHasAudio() != null && unit.getQuestion().getHasAudio()) {
                                List<QuestionAudio> questionAudios = questionAudioService
                                        .findQuestionAudiosByQuestionId(unit.getQuestion().getId());
                                for (QuestionAudio audio : questionAudios) {
                                    String audioFileName = paperExp.getCourseName() + "_" + paperExp.getName() + "_试卷_"
                                            + "_" + getAudioFileName(audio, unit, paperDetailExp);
                                    File file = new File(TEMP_FILE_EXP + File.separator + zipFileName + File.separator
                                            + audioFileName);
//                                    upyun.readFile(audio.getFileUrl(), file);
                                    //通用存储
									FileStorageUtil.saveUrlAs(FileStorageUtil.realPath(audio.getFileUrl()), file);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 计算取得音频文件名称
     *
     * @param audio
     * @param unit
     * @return
     */
    public String getAudioFileName(QuestionAudio audio, PaperDetailUnitExp unit, PaperDetailExp paperDetailExp) {
        String questionAudioId = audio.getId();
        StringBuffer audioFileName = new StringBuffer(paperDetailExp.getNumber() + "_" + unit.getNumber() + "_");
        Question question = unit.getQuestion();
        List<String> idvaluesBody = CommonUtils.getTagANames(question.getQuesBody());
        if (idvaluesBody.contains(questionAudioId)) {
            audioFileName.append("1");// 题干
            audioFileName.append("_");
            int index = idvaluesBody.indexOf(questionAudioId);
            audioFileName.append(index + 1);
        } else {
            List<QuesOption> options = question.getQuesOptions();
            if (options != null && options.size() > 0) {
                for (QuesOption option : options) {
                    List<String> idvaluesOption = CommonUtils.getTagANames(option.getOptionBody());
                    if (idvaluesOption.contains(questionAudioId)) {
                        audioFileName.append("2");// 选项
                        audioFileName.append("_");
                        audioFileName.append(CommonUtils.getOptionNum(Integer.parseInt(option.getNumber()) - 1));
                        audioFileName.append("_");
                        int index = idvaluesOption.indexOf(questionAudioId);
                        audioFileName.append(index + 1);
                        break;
                    }
                }
            }
        }
        audioFileName.append(".");
        audioFileName.append(audio.getFileSuffixes());
        return audioFileName.toString();
    }

    /*
     * 用于导出Word试卷和试卷答案
     */
    public PaperExp initPaperExp(DownloadPaperDto dto){
        PaperExp exportPaper = initPaperExpService.initPaperExp(dto);

        // 给新的大题下所有小题排序
//        sortPaperDetailUnits(exportPaper.getPaperDetails());

        // 如果每个小题分数不一样，题干后面添加分数
        setQuestionScore(exportPaper.getPaperDetails(), true);

        // 处理Word的题干选项
        // setQuestionNumberForWord(exportPaper.getPaperDetails());

        // 设置大题标题
        setExportQuestionTitle(exportPaper.getPaperDetails(), true);
        return exportPaper;
    }

    /**
     * 用于页面上预览PDF试卷
     */
    public PaperExp previewPaperForPDF(Paper paper) {
    	DownloadPaperDto dto=new DownloadPaperDto();
    	dto.setSeqMode(PaperSeqMode.MODE3);
        PaperExp previewPaper = initPaperExpService.initPaperExp(paper,dto);

        // 给新的大题下所有小题排序
//        sortPaperDetailUnits(previewPaper.getPaperDetails());

        // 如果每个小题分数不一致，题干后面添加分数；一致时则不用加
        setQuestionScore(previewPaper.getPaperDetails(), false);

        // 处理Html的题干选项
        setQuestionNumberForHtml(previewPaper.getPaperDetails());

        // 设置大题标题
        setExportQuestionTitle(previewPaper.getPaperDetails(), false);
        return previewPaper;
    }

    /**
     * 对相同类型的大题分组，生成不同的集合放入小题，再对小题排序
     */
    public void sortPaperDetailUnits(List<PaperDetailExp> details) {
        if (CollectionUtils.isEmpty(details)) {
            return;
        }

        int index = 0;
        Map<Long, List<PaperDetailUnitExp>> map = new HashMap<>();

        // 循环所有大题,将同类型的小题放到同一个集合下面
        for (PaperDetailExp detail : details) {
            // 单选，多选，判断放在同一集合下排序
            List<PaperDetailUnitExp> units;
            Long sortNumber = detail.getSortNumber();
            if (sortNumber < 4L) {
                units = map.get(sortNumber);
                if (units == null) {
                    units = new ArrayList<>();
                }
                units.addAll(detail.getPaperDetailUnits());
                map.put(sortNumber, units);
            } else {
                units = new ArrayList<>();
                units.addAll(detail.getPaperDetailUnits());
                map.put(sortNumber + index, units);
                index++;
            }
        }

        // 循环所有小题，给小题排序
        for (Long sortNumber : map.keySet()) {
            List<PaperDetailUnitExp> utils = map.get(sortNumber);
            if (CollectionUtils.isEmpty(utils)) {
                continue;
            }

            int number = 1;// 小题号
            int nestedNumber = 1;// 套题号
            for (int i = 0; i < utils.size(); i++) {
                PaperDetailUnitExp unit = utils.get(i);
                if (unit.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
                    unit.setNumber(nestedNumber);
                    List<Question> subQuestions = unit.getQuestion().getSubQuestions();
                    for (int j = 0; j < subQuestions.size(); j++) {
                        subQuestions.get(j).setNumber(number + j);
                    }
                    number += subQuestions.size();
                    nestedNumber++;
                } else {
                    unit.setNumber(number);
                    number++;
                }
            }
        }
    }


    /**
     * 题干上设置分数内容(Html)
     */
    public String appendScoreToQuestionHtmlBody(String quesBodyHtml, double score) {
        quesBodyHtml = quesBodyHtml.replaceAll("<p>", "").replaceAll("</p>", "");
        quesBodyHtml = quesBodyHtml.replaceAll("<span>", "").replaceAll("</span>", "");
        return "<p>" + quesBodyHtml + "(" + score + "分)</p>";
    }

    /**
     * 如果每个小题分数不一致，题干后面添加分数；一致时则不用加
     */
    public void setQuestionScore(List<PaperDetailExp> details, boolean isWord) {
        if (CollectionUtils.isEmpty(details)) {
            return;
        }

        for (PaperDetailExp detail : details) {
            if (checkPaperDetailUnitScore(detail) != null) {
                continue;// 分数一致
            }

            for (PaperDetailUnitExp unit : detail.getPaperDetailUnits()) {
                // 判断小题是否为套题
                if (unit.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
                    List<Question> subQuestions = unit.getQuestion().getSubQuestions();
                    for (int i = 0; i < subQuestions.size(); i++) {
                        Question subQuestion = subQuestions.get(i);
                        double subScore = unit.getSubScoreList().get(i);
                        if (isWord) {
//                            String questionBodyWord = appendScoreToQuestionWordBody(subQuestion.getQuesBodyWord(), subScore);
//                            subQuestion.setQuesBodyWord(questionBodyWord);
                            String questionBody = appendScoreToQuestionBody(subQuestion.getQuesBody(), subScore);
                            subQuestion.setQuesBody(questionBody);
                        } else {
                            String bodyHtml = appendScoreToQuestionHtmlBody(subQuestion.getQuesBody(), subScore);
                            subQuestion.setQuesBody(bodyHtml);
                        }
                    }
                } else {
                    Question question = unit.getQuestion();
                    if (isWord) {
//                        String questionBodyWord = appendScoreToQuestionWordBody(question.getQuesBodyWord(), unit.getScore());
//                        question.setQuesBodyWord(questionBodyWord);
                        String questionBody = appendScoreToQuestionBody(question.getQuesBody(), unit.getScore());
                        question.setQuesBody(questionBody);
                    } else {
                        String bodyHtml = appendScoreToQuestionHtmlBody(question.getQuesBody(), unit.getScore());
                        question.setQuesBody(bodyHtml);
                    }
                }
            }
        }
    }

    private String appendScoreToQuestionBody(String html, Double score) {
        Document doc = Jsoup.parse(html);
        Element b = doc.body();
        for (Node e : b.childNodes()) {
            if ("p".equals(e.nodeName()) && e.childNodeSize() > 0) {
                e.childNode(e.childNodeSize() - 1).after("（"+score + "分）");
                break;
            }
        }
        return doc.body().html();
    }

    /**
     * 校验大题下的小题分数是不是一样 1.如果分数一样，返回分数 2.如果分数不一样，返回null
     */
    public String checkPaperDetailUnitScore(PaperDetailExp detail) {
        Set<Double> scoreSet = new HashSet<>();
        List<PaperDetailUnitExp> units = detail.getPaperDetailUnits();
        for (PaperDetailUnitExp unit : units) {
            if (unit.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {

                List<Question> subQuestions = unit.getQuestion().getSubQuestions();
                for (Question subQuestion : subQuestions) {
                    scoreSet.add(subQuestion.getScore());
                }

                List<Double> subScoreList = unit.getSubScoreList();
                for (Double score : subScoreList) {
                    scoreSet.add(score);
                }
            } else {
                scoreSet.add(unit.getScore());
            }
        }
        if (scoreSet.size() == 1) {
            return scoreSet.iterator().next() + "";
        }
        return null;
    }

    /**
     * 处理Html的题干选项 1.设置题号 2.给小题选项进行排序 3.设置选项号 4.替换题干中的##为____
     */
    public void setQuestionNumberForHtml(List<PaperDetailExp> details) {
        if (CollectionUtils.isEmpty(details)) {
            return;
        }

        for (PaperDetailExp detail : details) {
            List<PaperDetailUnitExp> units = detail.getPaperDetailUnits();
            for (PaperDetailUnitExp unit : units) {
                Question question = unit.getQuestion();
                List<QuesOption> options = question.getQuesOptions();
                if (CollectionUtils.isNotEmpty(options)) {
                    for (QuesOption option : options) {
                        option.setOptionBody(replaceHashSign(option.getOptionBody()));
                        option.setOptionBodyWord(null);
                    }
                }

                List<Question> subQuestions = question.getSubQuestions();
                question.setQuesBodyWord(null);
                question.setQuesAnswerWord(null);

                if (CollectionUtils.isNotEmpty(subQuestions)) {
                	int index=0;
                    for (Question subQues : subQuestions) {
                    	index++;
                        Map<String, String> params = new HashMap<>();
                        params.put("number", String.valueOf(index));
                        subQues.setQuesParams(params);
                        subQues.setQuesBodyWord(null);
                        subQues.setQuesAnswerWord(null);

                        List<QuesOption> subOptions = subQues.getQuesOptions();
                        if (CollectionUtils.isNotEmpty(subOptions)) {
                            for (QuesOption subOption : subOptions) {
                                subOption.setOptionBody(replaceHashSign(subOption.getOptionBody()));
                                subOption.setOptionBodyWord(null);
                            }
                        }
                    }
                } else {
                    question.setQuesBody(replaceHashSign(question.getQuesBody()));
                    question.setQuesAnswer(replaceHashSign(question.getQuesAnswer()));
                }
            }
        }
    }

    /**
     * 替换#号
     */
    private String replaceHashSign(String str) {
        if (StringUtils.isEmpty(str)) {
            return "";
        }
        str = str.replace("###", "____");
        return CommonUtils.relaceQuestionIdx(str, 0);
    }


}