package com.qmth.jkserver.core.kj.plugin;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.reflect.TypeToken;
import com.qmth.jkserver.common.FileData;
import com.qmth.jkserver.constant.SpringContextHolder;
import com.qmth.jkserver.constant.SystemConstant;
import com.qmth.jkserver.core.RoomClientMonitorService;
import com.qmth.jkserver.core.exception.JkServerException;
import com.qmth.jkserver.enums.AttachmentType;
import com.qmth.jkserver.enums.ProgressType;
import com.qmth.jkserver.model.*;
import com.qmth.jkserver.service.*;
import com.qmth.jkserver.util.FileStoreUtil;
import com.qmth.jkserver.util.GsonUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

/**
 * 数据存储 此操作在数据校验通过之后
 * 基于业务逻辑实现的事物控制
 *
 * @author tianjun
 */
public class ExamRoomSolfegeKjStore {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExamRoomSolfegeKjStore.class);
    //考生答案缓存
    private Map<String, ExamStudentAnswer> ANSWER_CACHE = new LinkedHashMap<String, ExamStudentAnswer>();
    //视唱文件缓存
    private Map<String, ExamSolfegeRecord> RECORD_CACHE = new LinkedHashMap<String, ExamSolfegeRecord>();
    //需要删除的考生旧答案
    private List<Long> OLD_ANSWER_LIST = new ArrayList<Long>();
    private Map<String, ExamStudent> STUDENT_CAHE;

    private InputStream absentCsv;
    private InputStream cheatCsv;
    private InputStream abortCsv;
    private InputStream paperCsv;

    private ExamPlan examPlan;
    private ProgressType type;

    private File zip;
    private InputStream inputStream;
    private ZipFile zipFile;
    private ZipInputStream zipInputStream;
    private Attachment encrypted;
    private ExamStudentService examStudentService;
    private ExamStudentAnswerService examStudentAnswerService;
    private FileStoreUtil fileStoreConfig;
    private AttachmentService attachmentService;

    private String placeCode;
    private String roomCode;

    public ExamRoomSolfegeKjStore(
            File zip,
            ExamPlan examPlan,
            Attachment encrypted,
            ProgressType type,
            Map<String, ExamStudent> STUDENT_CAHE,
            String placeCode,
            String roomCode
    ) throws ZipException, IOException {
        this.zip = zip;
        zipFile = new ZipFile(this.zip);
        inputStream = new BufferedInputStream(new FileInputStream(zip));
        zipInputStream = new ZipInputStream(inputStream);
        this.examPlan = examPlan;
        this.encrypted = encrypted;
        this.type = type;
        this.examStudentService = SpringContextHolder.getBean(ExamStudentService.class);
        this.examStudentAnswerService = SpringContextHolder.getBean(ExamStudentAnswerService.class);
        this.fileStoreConfig = SpringContextHolder.getBean(FileStoreUtil.class);
        this.attachmentService = SpringContextHolder.getBean(AttachmentService.class);
        this.STUDENT_CAHE = STUDENT_CAHE;
        this.placeCode = placeCode;
        this.roomCode = roomCode;
    }

    private ExamStudent getCachedStudent(String examCode, String ticketNo) {
        if (StringUtils.isEmpty(examCode) || StringUtils.isEmpty(ticketNo)) {
            throw new JkServerException("考试识别码以及准考证号不能够为空");
        }
        String key = examCode + ticketNo;
        ExamStudent examStudent = STUDENT_CAHE.get(key);
        if (examStudent != null) {
            LOGGER.info(".....@get student from cache OK!!");
            return examStudent;
        }
        examStudent = examStudentService.findSolfegeStudent(examCode, ticketNo);
        if (examStudent == null) {
            throw new JkServerException(
                    "无法获取到此考生的考务数据,考试识别码:" + examCode + ",准考证号:" + ticketNo);
        } else {
            if (StringUtils.isEmpty(this.placeCode) || StringUtils.isEmpty(this.roomCode)) {
                this.placeCode = examStudent.getPlaceCode();
                this.roomCode = examStudent.getRoomCode();
            }
            LOGGER.info(".....@cache student OK!!");
            STUDENT_CAHE.put(key, examStudent);
            return examStudent;
        }
    }

    protected void initCache() {
        ANSWER_CACHE.clear();
        RECORD_CACHE.clear();
    }

    public void execute() throws IOException {
        try {
            //0\解析文件
            initCache();
            extractFile();
            //1\提取考生缺考信息
            extractAbsent();
            //2\提取试卷名称
            extractPaper();
            //3\提取异常处信息
            extractAbort();
            //4\提取考生违纪信息
            extractCheat();
            //10\保存考生答案
            saveAnswer();
            //11\提取监考端日志文件以及数据
            Attachment storagedDecodedFile = storeKjDecodedFile();
            RoomClientMonitorService roomClientMonitorService = SpringContextHolder.getBean(RoomClientMonitorService.class);
            roomClientMonitorService.execute(storagedDecodedFile, placeCode, roomCode);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                IOUtils.closeQuietly(inputStream);
            }
            if (zipInputStream != null) {
                IOUtils.closeQuietly(zipInputStream);
            }
            if (zipFile != null) {
                IOUtils.closeQuietly(zipFile);
            }
            //关闭打开的文件的输入流
            if (absentCsv != null) {
                IOUtils.closeQuietly(absentCsv);
            }
            if (cheatCsv != null) {
                IOUtils.closeQuietly(cheatCsv);
            }
            if (abortCsv != null) {
                IOUtils.closeQuietly(abortCsv);
            }
            if (paperCsv != null) {
                IOUtils.closeQuietly(paperCsv);
            }
        }
    }

    private void storeStudentZipAnswerFile(ZipEntry ze) throws IOException {
        if (ze.getName().endsWith("zip")) {
            InputStream zipStream = null;
            try {
                zipStream = zipFile.getInputStream(ze);
                String zipName = ze.getName().replace("\\\\", "").replace("/", "");
                storeStudentZipAnswerFile(zipStream, zipName);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (zipStream != null) {
                    IOUtils.closeQuietly(zipStream);
                }
            }
        }
    }

    //将qm解密之后的文件进行存储
    protected Attachment storeKjDecodedFile() throws Exception {
        FileStoreUtil fileStoreConfig = SpringContextHolder.getBean(FileStoreUtil.class);
        AttachmentService attachmentService = SpringContextHolder.getBean(AttachmentService.class);
        ExamPlan examPlan = this.examPlan;
        //2020-12-19日加入阿里云下载
        File storeDir = null;
        if (fileStoreConfig.storageIsOss()) {
            StringJoiner stringJoiner = new StringJoiner("").add(fileStoreConfig.getStorageRoot())
                    .add(File.separator).add(examPlan.getExamType().name());
            storeDir = fileStoreConfig.ossDownload(stringJoiner.toString().replaceAll("\\\\", "/"), fileStoreConfig.getStorageRoot() + File.separator + examPlan.getExamType().name(), fileStoreConfig.getStorageRoot());
        } else {
            storeDir = new File(fileStoreConfig.getStorageRoot(), examPlan.getExamType().name());
        }
        storeDir = new File(storeDir, examPlan.getExamCode());
        storeDir = new File(storeDir, "kj");
        storeDir = new File(storeDir, "decoded");
        storeDir = new File(storeDir, placeCode + "_" + roomCode);
        String timestamp = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        storeDir = new File(storeDir, timestamp);
        String random = SystemConstant.getNanoId();
        storeDir = new File(storeDir, random);
        if (!storeDir.exists()) {
            storeDir.mkdirs();
        }
        String path = examPlan.getExamType().name() + File.separator + examPlan.getExamCode() + File.separator + "kj"
                + File.separator + "decoded" + File.separator + (placeCode + "_" + roomCode) + File.separator +
                timestamp + File.separator + random;
        String accessUri = path + File.separator + zip.getName();
        //2020-12-19日加入阿里云下载
        File target = null;
        if (fileStoreConfig.storageIsOss()) {
            StringJoiner stringJoiner = new StringJoiner("").add(fileStoreConfig.getStorageRoot())
                    .add(File.separator).add(accessUri);
            target = fileStoreConfig.ossDownload(stringJoiner.toString().replaceAll("\\\\", "/"), fileStoreConfig.getStorageRoot() + File.separator + accessUri, fileStoreConfig.getStorageRoot());
        } else {
            target = new File(fileStoreConfig.getStorageRoot(), accessUri);
        }
        target.createNewFile();
        FileUtils.copyFile(zip, target);
        Attachment attachment = new Attachment();
        attachment.setId(SystemConstant.getDbUuid());
        attachment.setExamCode(examPlan.getExamCode());
        attachment.setName(target.getName());
        attachment.setOriginalName(target.getName());
        attachment.setPath(path);
        attachment.setAccessUri(accessUri);
        attachment.setSize((double) target.length());
        attachment.setMd5(DigestUtils.md5Hex(new FileInputStream(target)));
        attachmentService.saveOrUpdate(attachment);
        return attachment;
    }

    private void storeStudentZipAnswerFile(InputStream zipStream, String zipName) throws Exception {
        String ticketNumber = zipName.replace(SystemConstant.ZIP_PREFIX, "");
        if (StringUtils.isEmpty(ticketNumber)) {
            throw JkServerException.withMessage("准考证号不能够为空");
        }
        Boolean a = fileStoreConfig.storageIsOss();
        String examCode = examPlan.getExamCode();
        if (a == null) {
            a = true;
        }
        //将校验通过的文件从临时目录转存到存储区存储
        Attachment answerFile = null;
        if (!a) {
            //存储到本地文件系统
            String path = examPlan.getExamType().name() + File.separator + examCode + File.separator + "kj";
            String accessUri = path + File.separator + zipName;
            File root = new File(fileStoreConfig.getStorageRoot());
            File target = new File(root, accessUri);
            FileUtils.copyInputStreamToFile(zipStream, target);
            answerFile = new Attachment();
            answerFile.setId(SystemConstant.getDbUuid());
            answerFile.setExamCode(examCode);
            answerFile.setExt("zip");
            answerFile.setMd5(DigestUtils.md5Hex(new FileInputStream(target)));
            answerFile.setName(zipName);
            answerFile.setOriginalName(zipName);
            answerFile.setPath(path);
            answerFile.setRelateId(encrypted.getId());
            answerFile.setSize((double) target.length());
            answerFile.setTime(System.currentTimeMillis());
            answerFile.setType(AttachmentType.FILE);
            answerFile.setAccessUri(accessUri);
            attachmentService.saveOrUpdate(answerFile);
        } else {
            //存储到阿里云的OSS
            File tempFile = null;
            try {
                String key = examPlan.getExamType().name() + "/" + examCode + "/" + "kj" + "/" + zipName;
                tempFile = SystemConstant.getFileTempVar(SystemConstant.ZIP_PREFIX);
                FileUtils.copyInputStreamToFile(zipStream, tempFile);
                String md5 = DigestUtils.md5Hex(new FileInputStream(tempFile));
                fileStoreConfig.ossUpload(key, tempFile, md5, fileStoreConfig.getStorageRoot());
                answerFile = new Attachment();
                answerFile.setExamCode(examCode);
                answerFile.setExt("zip");
                answerFile.setId(System.currentTimeMillis());
                answerFile.setMd5(md5);
                answerFile.setName(zipName);
                answerFile.setOriginalName(zipName);
                answerFile.setRelateId(encrypted.getId());
                answerFile.setSize((double) zipStream.available());
                answerFile.setTime(System.currentTimeMillis());
                answerFile.setType(AttachmentType.FILE);
//            answerFile.setBucket(aliYunOssConfig.getBucket());
//            answerFile.setObjectKey(key);
                attachmentService.saveOrUpdate(answerFile);
                String cacheKey = examCode + ticketNumber;
                if (RECORD_CACHE.get(cacheKey) == null) {
                    ExamSolfegeRecord examSolfegeRecord = new ExamSolfegeRecord();
                    examSolfegeRecord.setId(SystemConstant.getDbUuid());
                    examSolfegeRecord.setExamCode(examCode);
                    examSolfegeRecord.setStudentId(STUDENT_CAHE.get(cacheKey).getId());
                    examSolfegeRecord.setTime(System.currentTimeMillis());
                    examSolfegeRecord.setProgressType(type);
                    examSolfegeRecord.setAttachmentId(answerFile.getId());
                    RECORD_CACHE.put(cacheKey, examSolfegeRecord);
                } else {
                    RECORD_CACHE.get(cacheKey).setTime(System.currentTimeMillis());
                    RECORD_CACHE.get(cacheKey).setProgressType(type);
                    RECORD_CACHE.get(cacheKey).setAttachmentId(answerFile.getId());
                }
            } finally {
                if (Objects.nonNull(tempFile)) {
                    tempFile.delete();
                }
            }
//            answerFile = new Attachment();
//            OSSClient client = new OSSClient(aliYunOssConfig.getEndpoint(), aliYunOssConfig.getAccessKeyId(),
//                    aliYunOssConfig.getAccessKeySecret());
//            PutObjectResult result = client.putObject(aliYunOssConfig.getBucket(), key,
//                    zipStream);
//            client.shutdown();
//            if (StringUtils.isNotEmpty(result.getRequestId()) && result.getResponse() == null) {
//                LOGGER.info("upload solfege answer to Aliyun OSS success key=:" + key);
//            } else {
//                throw JkServerException.withFieldValidateError("");
//            }
        }
    }

    // 监考端上传的原始数据包 转存到 存储区
    protected Attachment storeKjOriginalFile(String placeCode, String roomCode, Long tempId) throws Exception {
        FileStoreUtil fileStoreConfig = SpringContextHolder.getBean(FileStoreUtil.class);
        JkExamPlanService examPlanService = SpringContextHolder.getBean(JkExamPlanService.class);
        AttachmentService attachmentService = SpringContextHolder.getBean(AttachmentService.class);
        Attachment temp = attachmentService.findByIdService(tempId);
        ExamPlan examPlan = examPlanService.findByExamCode(temp.getExamCode());
        //2020-12-19日加入阿里云下载
        File storeDir = null;
        if (fileStoreConfig.storageIsOss()) {
            StringJoiner stringJoiner = new StringJoiner("").add(fileStoreConfig.getStorageRoot())
                    .add(File.separator).add(examPlan.getExamType().name());
            storeDir = fileStoreConfig.ossDownload(stringJoiner.toString().replaceAll("\\\\", "/"), fileStoreConfig.getStorageRoot() + File.separator + examPlan.getExamType().name(), fileStoreConfig.getStorageRoot());
        } else {
            storeDir = new File(fileStoreConfig.getStorageRoot(), examPlan.getExamType().name());
        }
        storeDir = new File(storeDir, temp.getExamCode());
        storeDir = new File(storeDir, "kj");
        storeDir = new File(storeDir, "original");
        storeDir = new File(storeDir, placeCode + "_" + roomCode);
        if (!storeDir.exists()) {
            storeDir.mkdirs();
        }
        String path = examPlan.getExamType().name() + File.separator + temp.getExamCode() + File.separator + "kj"
                + File.separator + "original" + File.separator + (placeCode + "_" + roomCode) + File.separator + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) +
                File.separator + SystemConstant.getNanoId();
        String accessUri = path + File.separator + temp.getOriginalName();
        //2020-12-19日加入阿里云下载
        File target = null;
        if (fileStoreConfig.storageIsOss()) {
            StringJoiner stringJoiner = new StringJoiner("").add(fileStoreConfig.getStorageRoot())
                    .add(File.separator).add(accessUri);
            target = fileStoreConfig.ossDownload(stringJoiner.toString().replaceAll("\\\\", "/"), fileStoreConfig.getStorageRoot() + File.separator + accessUri, fileStoreConfig.getStorageRoot());
        } else {
            target = new File(fileStoreConfig.getStorageRoot(), accessUri);
        }
        if (!target.getParentFile().exists()) {
            target.getParentFile().mkdirs();
        }
        if (!target.exists()) {
            target.createNewFile();
        }
        File src = null;
        if (fileStoreConfig.workIsOss()) {
            StringJoiner stringJoiner = new StringJoiner("").add(fileStoreConfig.getWorkRoot())
                    .add(File.separator).add(temp.getAccessUri());
            src = fileStoreConfig.ossDownload(stringJoiner.toString().replaceAll("\\\\", "/"), fileStoreConfig.getWorkRoot() + File.separator + temp.getAccessUri(), fileStoreConfig.getWorkRoot());
        } else {
            src = new File(fileStoreConfig.getWorkRoot(), temp.getAccessUri());
        }
        if (!src.exists()) {
            throw new JkServerException("原始文件不存在");
        }
        attachmentService.copyFile(src, target);
        Attachment attachment = new Attachment();
        attachment.setId(SystemConstant.getDbUuid());
        attachment.setName(temp.getOriginalName());
        attachment.setExamCode(temp.getExamCode());
        attachment.setExt(temp.getExt());
        attachment.setMoved(false);
        attachment.setOriginalName(temp.getOriginalName());
        attachment.setPath(path);
        attachment.setSize(temp.getSize());
        attachment.setTime(System.currentTimeMillis());
        attachment.setRelateId(temp.getId());
        attachment.setAccessUri(accessUri);
        attachment.setMd5(DigestUtils.md5Hex(new FileInputStream(target)));
        attachmentService.saveOrUpdate(attachment);
        // 修改临时文件的转存属性值
        temp.setMoved(true);
        attachmentService.saveOrUpdate(temp);
        return attachment;
    }

    /**
     * 获取文件的后缀
     */
    protected String getExtension(String fileName) {
        int k = fileName.lastIndexOf(".");
        String ext = "";
        if (k > 0) {
            ext = fileName.substring(k + 1, fileName.length());
        }
        return ext;
    }

    // 提取考生违纪信息
    protected void extractCheat() throws IOException {
        if (cheatCsv != null) {
            JkExamCheatService jkExamCheatService = SpringContextHolder.getBean(JkExamCheatService.class);
            FileData fileData = new FileData(cheatCsv, "~");
            List<ExamCheat> examCheatList = new ArrayList<>();
            while (fileData.nextLine()) {
                String[] datas = fileData.getDatas();
                String ticketNo = datas[3];
                ExamStudentAnswer examStudentAnswer = invokeAnswer(ticketNo);
                examStudentAnswer.setIsCheat(true);
                ExamCheat examCheat = new ExamCheat();
                examCheat.setId(SystemConstant.getDbUuid());
                examCheat.setOperateType(datas[7]);
                examCheat.setOperateTime(Objects.nonNull(datas[8]) ? DateUtil.parse(datas[8]).getTime() : null);
                examCheat.setCreateTime(System.currentTimeMillis());
                examCheat.setReason(datas[9]);
                examCheat.setIntroduce(datas[10]);
//                examStudentAnswer.setExamCheat(examCheat);
                examCheat.setExamStudentAnswerId(examStudentAnswer.getId());
                examCheatList.add(examCheat);
            }
            fileData.close();
            jkExamCheatService.saveBatch(examCheatList);
        }
    }

    // 提取异常处理信息
    protected void extractAbort() throws IOException {
        // 1、提取异常处理信息
        if (abortCsv != null) {
            JkExamAbortService jkExamAbortService = SpringContextHolder.getBean(JkExamAbortService.class);
            FileData fileData = new FileData(abortCsv, "~");
            List<ExamAbort> examAbortList = new ArrayList<>();
            while (fileData.nextLine()) {
                String[] datas = fileData.getDatas();
                String ticketNo = datas[3];
                ExamStudentAnswer examStudentAnswer = invokeAnswer(ticketNo);
                examStudentAnswer.setIsAbort(true);
                ExamAbort examAbort = new ExamAbort();
                examAbort.setId(SystemConstant.getDbUuid());
                String loginTime = datas[7];
                if (StringUtils.isNotEmpty(loginTime)) {
                    Long time = DateUtil.parse(loginTime).getTime();
                    examAbort.setTime(time);
                    examStudentAnswer.setLoginTime(time);
                }
                if (datas.length >= 9) {
                    examAbort.setReason(StringUtils.trimToNull(datas[8]));
                }
                if (datas.length >= 10) {
                    examAbort.setRemark(StringUtils.trimToNull(datas[9]));
                }
//                examStudentAnswer.getExamAborts().add(examAbort);
                examAbort.setExamStudentAnswerId(examStudentAnswer.getId());
                examAbortList.add(examAbort);
            }
            fileData.close();
            jkExamAbortService.saveBatch(examAbortList);
        }
    }

    // 提取考生缺考信息
    protected void extractAbsent() throws IOException {
        // 1、提取考生缺考信息
        if (absentCsv != null) {
            JkExamAbsentService jkExamAbsentService = SpringContextHolder.getBean(JkExamAbsentService.class);
            FileData fileData = new FileData(absentCsv, "~");
            List<ExamAbsent> examAbsentList = new ArrayList<>();
            while (fileData.nextLine()) {
                String[] datas = fileData.getDatas();
                String ticketNo = datas[3];
                ExamStudentAnswer examStudentAnswer = invokeAnswer(ticketNo);
                examStudentAnswer.setIsAbsent(true);
                ExamAbsent examAbsent = new ExamAbsent();
                examAbsent.setId(SystemConstant.getDbUuid());
                examAbsent.setCreateTime(System.currentTimeMillis());
                examAbsent.setRemark("缺考");
//                examStudentAnswer.setExamAbsent(examAbsent);
                examAbsent.setExamStudentAnswerId(examStudentAnswer.getId());
                examAbsentList.add(examAbsent);
            }
            fileData.close();
            jkExamAbsentService.saveBatch(examAbsentList);
        }
    }

    // 读取考生考试科目信息
    protected void extractPaper() throws IOException {
        if (paperCsv != null) {
            FileData fileData = new FileData(paperCsv, "~");
            while (fileData.nextLine()) {
                String[] datas = fileData.getDatas();
                String ticketNo = datas[0];
                String paperName = datas[1];
                ExamStudentAnswer examStudentAnswer = invokeAnswer(ticketNo);
                examStudentAnswer.setIsAbsent(false);
                examStudentAnswer.setPaperName(paperName);
                ExamSolfegeRecord examSolfegeRecord = RECORD_CACHE.get(examPlan.getExamCode() + ticketNo);
                //如果是本地导入  则 试卷名字就用  paper.csv 中的名字
                if (examSolfegeRecord != null) {
                    examSolfegeRecord.setPaperName(paperName);
                }
            }
            fileData.close();
        }
    }

    protected void extractFile() throws IOException {
        ZipEntry ze = null;
        while ((ze = zipInputStream.getNextEntry()) != null) {
            if (!ze.isDirectory()) {
                long size = ze.getSize();
                if (size > 0 && (ze.getName().endsWith("csv") || ze.getName().endsWith("txt"))) {
                    if (StringUtils.trimToNull(ze.getName()).equalsIgnoreCase("absent.csv")) {
                        absentCsv = zipFile.getInputStream(ze);
                    }
                    if (StringUtils.trimToNull(ze.getName()).equalsIgnoreCase("cheat.csv")) {
                        cheatCsv = zipFile.getInputStream(ze);
                    }
                    if (StringUtils.trimToNull(ze.getName()).equalsIgnoreCase("abort.csv")) {
                        abortCsv = zipFile.getInputStream(ze);
                    }
                    if (StringUtils.trimToNull(ze.getName()).equalsIgnoreCase("paper.csv")) {
                        paperCsv = zipFile.getInputStream(ze);
                    }
                }
                if (size > 0) {
                    storeStudentZipAnswerFile(ze);
                }
            }
            zipInputStream.closeEntry();
        }
    }

    protected ExamStudentAnswer invokeAnswer(String ticketNo) {
        String examCode = examPlan.getExamCode();
        String key = examCode + ticketNo;
        ExamStudentAnswer examStudentAnswer = ANSWER_CACHE.get(key);
        if (examStudentAnswer == null) {
            examStudentAnswer = new ExamStudentAnswer();
            examStudentAnswer.setId(SystemConstant.getDbUuid());
            examStudentAnswer.setTime(System.currentTimeMillis());
            examStudentAnswer.setExamCode(examCode);
            examStudentAnswer.setProgressType(type);
            examStudentAnswer.setExamCode(examCode);
            long time1 = System.currentTimeMillis();
            ExamStudent examStudent = getCachedStudent(examCode, ticketNo);
            long time2 = System.currentTimeMillis();
            LOGGER.info("-----!!!find student use:" + ((time2 - time1) / 1000) + "s");
            if (examStudent == null) {
                throw new JkServerException(
                        "无法获取到此考生的考务数据,考试识别码:" + examCode + ",准考证号:" + ticketNo);
            }
            examStudentAnswer.setStudentId(examStudent.getId());
            ANSWER_CACHE.put(key, examStudentAnswer);
            Long oldId = examStudentAnswerService.findAnswerIdByStudentId(examStudent.getId());
            if (oldId != null) {
                OLD_ANSWER_LIST.add(oldId);
            }
        }
        return examStudentAnswer;
    }


    protected void saveAnswer() {
//        MongoTemplate mongoOperations = BeanFactory.getBean(MongoTemplate.class);
//        List<DBObject> list = new ArrayList<DBObject>();
//        for (ExamStudentAnswer answer : ANSWER_CACHE.values()) {
//            answer.setTime(System.currentTimeMillis());
//            Object object = mongoOperations.getConverter().convertToMongoType(answer);
//            DBObject dbObject = (DBObject) JSON.parse(object.toString());
//            dbObject.put("_class", ExamStudentAnswer.class.getName());
//            list.add(dbObject);
//        }
        examStudentAnswerService.saveOrUpdateBatch(ANSWER_CACHE.values());
        //删除此次上传的考生的旧答案
        if (OLD_ANSWER_LIST.size() > 0) {
            long time1 = System.currentTimeMillis();
//            DBObject delObject = new BasicDBObject("$in", OLD_ANSWER_LIST);
//            DBObject queryDel = new BasicDBObject("_id", delObject);
//            mongoOperations.getCollection("jk_exam_student_answer").remove(queryDel);
            examStudentAnswerService.removeByIds(OLD_ANSWER_LIST);
            long time2 = System.currentTimeMillis();
            LOGGER.info(".....@DELETE old use :" + (time2 - time1) + "ms");
        }
        //保存当前考场新的答案
        System.out.println("###insert answer to mongodb!!!!");
        long time3 = System.currentTimeMillis();
//        mongoOperations.getCollection("jk_exam_student_answer").insert(list);
        long time4 = System.currentTimeMillis();
        LOGGER.info(".....@INSERT new use :" + (time4 - time3) + "ms");
        //保存答案历史记录
        try {
//            List<DBObject> anshistoryList = list.stream().map(obj -> {
//                obj.put("_class", ExamStudentAnswerHistory.class.getName());
//                return obj;
//            }).collect(Collectors.toList());
//            mongoOperations.getCollection("jk_exam_student_answer_history").insert(anshistoryList);
            JkExamStudentAnswerHistoryService examStudentAnswerHistoryService = SpringContextHolder.getBean(JkExamStudentAnswerHistoryService.class);
            List<ExamStudentAnswerHistory> listHistory = GsonUtil.fromJson(GsonUtil.toJson(ANSWER_CACHE.values()), new TypeToken<List<ExamStudentAnswerHistory>>() {
            }.getType());
            examStudentAnswerHistoryService.saveOrUpdateBatch(listHistory);
//            LOGGER.info("----------insert history list size:" + anshistoryList.size() + "------------------");
        } catch (Exception e) {
            LOGGER.warn("----------insert history list error:", e);
        }
        //////////////////////////////////存储考生zip答案包
        List<ExamSolfegeRecord> recordList = new ArrayList<ExamSolfegeRecord>();
        //按照考生准考证号删除 之前的MP3
//        List<String> deleteList = new ArrayList<String>();
        List<Long> deleteExamStudentIdList = new ArrayList<>();
        for (ExamSolfegeRecord record : RECORD_CACHE.values()) {
            record.setTime(System.currentTimeMillis());
//            Object object = mongoOperations.getConverter().convertToMongoType(record);
//            DBObject dbObject = (DBObject) JSON.parse(object.toString());
//            dbObject.put("_class", ExamSolfegeRecord.class.getName());
            recordList.add(record);
//            ExamStudent examStudent = examStudentService.getById(record.getStudentId());
            deleteExamStudentIdList.add(record.getStudentId());
//            deleteList.add(examStudent.getTicketNo());
        }
        JkExamSolfegeRecordService jkExamSolfegeRecordService = SpringContextHolder.getBean(JkExamSolfegeRecordService.class);
        if (deleteExamStudentIdList.size() > 0) {
//            DBObject delObject = new BasicDBObject("$in", deleteList);
//            DBObject queryDel = new BasicDBObject("student.ticket_no", delObject);
//            queryDel.put("exam_code", examPlan.getExamCode());
//            mongoOperations.getCollection("jk_exam_solfege_record").remove(queryDel);
            QueryWrapper<ExamSolfegeRecord> examSolfegeRecordQueryWrapper = new QueryWrapper<>();
            examSolfegeRecordQueryWrapper.lambda().in(ExamSolfegeRecord::getStudentId, deleteExamStudentIdList)
                    .eq(ExamSolfegeRecord::getExamCode, examPlan.getExamCode());
            jkExamSolfegeRecordService.remove(examSolfegeRecordQueryWrapper);
            LOGGER.info("----------delete old record list size:" + deleteExamStudentIdList.size() + "------------------");
        }
        if (recordList.size() > 0) {
//            mongoOperations.getCollection("jk_exam_solfege_record").insert(recordList);
            jkExamSolfegeRecordService.saveOrUpdateBatch(recordList);
        }
        //写入历史记录表
        try {
//            List<DBObject> mp3HistoryList = recordList.stream().map(obj -> {
//                obj.put("_class", ExamSolfegeRecordHistory.class.getName());
//                return obj;
//            }).collect(Collectors.toList());
//            mongoOperations.getCollection("jk_exam_solfege_record_history").insert(mp3HistoryList);
//            LOGGER.info("----------insert record history list size:" + mp3HistoryList.size() + "------------------");
            JkExamSolfegeRecordHistoryService jkExamSolfegeRecordHistoryService = SpringContextHolder.getBean(JkExamSolfegeRecordHistoryService.class);
            List<ExamSolfegeRecordHistory> listHistory = GsonUtil.fromJson(GsonUtil.toJson(recordList), new TypeToken<List<ExamSolfegeRecordHistory>>() {
            }.getType());
            jkExamSolfegeRecordHistoryService.saveOrUpdateBatch(listHistory);
        } catch (Exception e) {
            LOGGER.warn("----------insert history list error:", e);
        }
    }
}
