package cn.com.qmth.stmms.mark;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import cn.com.qmth.stmms.admin.utils.SessionExamUtils;
import cn.com.qmth.stmms.biz.exam.model.Exam;
import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
import cn.com.qmth.stmms.biz.exam.model.Marker;
import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
import cn.com.qmth.stmms.biz.exam.service.ExamService;
import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
import cn.com.qmth.stmms.biz.exam.service.MarkerClassService;
import cn.com.qmth.stmms.biz.exam.service.MarkerService;
import cn.com.qmth.stmms.biz.file.service.FileService;
import cn.com.qmth.stmms.biz.lock.LockService;
import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
import cn.com.qmth.stmms.biz.mark.model.MarkResult;
import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
import cn.com.qmth.stmms.biz.mark.model.ProblemType;
import cn.com.qmth.stmms.biz.mark.model.SubmitResult;
import cn.com.qmth.stmms.biz.mark.model.Task;
import cn.com.qmth.stmms.biz.mark.model.TrialLibrary;
import cn.com.qmth.stmms.biz.mark.query.MarkLibrarySearchQuery;
import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
import cn.com.qmth.stmms.biz.mark.service.MarkService;
import cn.com.qmth.stmms.biz.mark.service.ProblemTypeService;
import cn.com.qmth.stmms.biz.mark.service.TaskService;
import cn.com.qmth.stmms.biz.mark.service.TrialService;
import cn.com.qmth.stmms.biz.user.model.User;
import cn.com.qmth.stmms.biz.user.service.UserService;
import cn.com.qmth.stmms.common.annotation.Logging;
import cn.com.qmth.stmms.common.controller.BaseController;
import cn.com.qmth.stmms.common.domain.WebUser;
import cn.com.qmth.stmms.common.enums.ExamStatus;
import cn.com.qmth.stmms.common.enums.ExamType;
import cn.com.qmth.stmms.common.enums.LibraryStatus;
import cn.com.qmth.stmms.common.enums.LockType;
import cn.com.qmth.stmms.common.enums.LogType;
import cn.com.qmth.stmms.common.enums.MarkMode;
import cn.com.qmth.stmms.common.enums.MarkStatus;
import cn.com.qmth.stmms.common.session.model.StmmsSession;
import cn.com.qmth.stmms.common.session.service.SessionService;
import cn.com.qmth.stmms.common.utils.EncryptUtils;
import cn.com.qmth.stmms.common.utils.RequestIPUtil;
import cn.com.qmth.stmms.common.utils.RequestUtils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
@RequestMapping("/mark")
public class MarkController extends BaseController {

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

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private TrialService trialService;

    @Autowired
    private MarkerService markerService;

    @Autowired
    private MarkLibraryService libraryService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private MarkService markService;

    @Autowired
    private ExamService examService;

    @Autowired
    private MarkGroupService groupService;

    @Autowired
    private LockService lockService;

    @Autowired
    private ProblemTypeService problemTypeService;

    @Autowired
    private UserService userService;

    @Autowired
    private MarkerClassService markerClassService;

    @Autowired
    private SessionService sessionService;

    @Autowired
    private FileService fileService;

    @Autowired
    private ExamQuestionService questionService;

    @Value("${slice.split.config}")
    private String splitConfig;

    @Value("${marker.prefetch.count}")
    private long prefetchCount;

    @Value("${marker.forceMode}")
    private String forceMarkMode;

    @Value("${marker.name.verify}")
    private boolean nameVerify;

    @Value("${marker.secretNumber.hide}")
    private boolean secretNumberHide;

    private static final String DEFALT_SECRET_NUMBER = "***";

    @RequestMapping(value = "/reset", method = RequestMethod.GET)
    public ModelAndView reset(HttpServletRequest request) {
        User user = RequestUtils.getWebUser(request).getUser();
        ModelAndView modelAndView = new ModelAndView("modules/mark/reset");
        modelAndView.addObject("user", user);
        modelAndView.addObject("nameVerify", nameVerify);
        return modelAndView;
    }

    @Logging(menu = "修改姓名密码", type = LogType.UPDATE)
    @RequestMapping(value = "/reset", method = RequestMethod.POST)
    public ModelAndView reset(HttpServletRequest request, User user) {
        User current = RequestUtils.getWebUser(request).getUser();
        if (current.getPassword().equalsIgnoreCase(EncryptUtils.md5(user.getPassword()))) {
            ModelAndView modelAndView = new ModelAndView("modules/mark/reset");
            modelAndView.addObject("message", "新密码不可与初始密码一致");
            modelAndView.addObject("user", user);
            modelAndView.addObject("nameVerify", nameVerify);
            return modelAndView;
        }
        current.setName(user.getName());
        current.setEmpno(user.getEmpno());
        current.setPassword(EncryptUtils.md5(user.getPassword()));
        current.setRandomPassword(null);
        current.setLastLoginIp(RequestIPUtil.getIpAddress(request));
        current.setLastLoginTime(new Date());
        userService.save(current);
        return new ModelAndView("redirect:/mark/subject-select");
    }

    @RequestMapping(value = "/subject-select", method = RequestMethod.GET)
    public ModelAndView select(HttpServletRequest request, @RequestParam(required = false) Integer examId) {
        ModelAndView modelAndView = new ModelAndView("modules/mark/subjectSelect");
        User user = RequestUtils.getWebUser(request).getUser();
        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(new Date());
        rightNow.add(Calendar.YEAR, -1);
        List<Exam> examList = examService.findByMarkerUserId(user.getId(), rightNow.getTime());
        modelAndView.addObject("examList", examList);
        if (examId != null) {
            Exam exam = examService.findById(examId);
            if (exam != null && exam.getStatus() == ExamStatus.START) {
                modelAndView.addObject("exam", exam);
            }
        }
        return modelAndView;
    }

    @RequestMapping(value = "/subject/query")
    @ResponseBody
    public JSONArray subjectQuery(HttpServletRequest request, @RequestParam Integer examId) {
        User user = RequestUtils.getWebUser(request).getUser();
        List<Marker> list = markerService.findByExamAndUserId(examId, user.getId());
        Set<String> subjectSet = new HashSet<>();
        JSONArray array = new JSONArray();
        for (Marker marker : list) {
            MarkGroup group = groupService.findOne(examId, marker.getSubjectCode(), marker.getGroupNumber());
            if (!subjectSet.contains(marker.getSubjectCode()) && marker.isEnable()
                    && group.getStatus() != MarkStatus.FINISH) {
                ExamSubject subject = subjectService.find(marker.getExamId(), marker.getSubjectCode());
                if (subject != null) {
                    JSONObject item = new JSONObject();
                    item.accumulate("id", marker.getId());
                    item.accumulate("subjectCode", subject.getCode());
                    item.accumulate("subjectName", subject.getName());
                    array.add(item);
                }
                subjectSet.add(marker.getSubjectCode());
            }
        }
        return array;
    }

    @RequestMapping(value = "/subject/group/query")
    @ResponseBody
    public JSONArray groupQuery(HttpServletRequest request, @RequestParam Integer examId,
            @RequestParam String subjectCode) {
        User user = RequestUtils.getWebUser(request).getUser();
        List<Marker> list = markerService.findByExamAndSubjectAndUserIdAndEnable(examId, subjectCode, user.getId(),
                true);
        JSONArray array = new JSONArray();
        for (Marker marker : list) {
            MarkGroup group = groupService.findOne(examId, marker.getSubjectCode(), marker.getGroupNumber());
            group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId,
                    marker.getSubjectCode(), false, group.getNumber()));
            if (group.getStatus() != MarkStatus.FINISH) {
                JSONObject item = new JSONObject();
                item.accumulate("id", marker.getId());
                item.accumulate("title", group.getTitle());
                item.accumulate("groupNumber", group.getNumber());
                int percent = group.getLibraryCount() > 0 ? (int) (group.getMarkedCount() * 100.00 / group
                        .getLibraryCount()) : 0;
                if (group.getMarkedCount() > 0 && percent == 0) {
                    percent = 1;
                } else if (group.getLeftCount() > 0 && percent == 100) {
                    percent = 99;
                }
                item.accumulate("percent", percent);
                array.add(item);
            }
        }
        return array;
    }

    @RequestMapping(value = "/subject-select", method = RequestMethod.POST)
    public ModelAndView select(HttpServletRequest request, HttpServletResponse response, @RequestParam Integer markerId) {
        WebUser user = RequestUtils.getWebUser(request);
        ModelAndView modelAndView = new ModelAndView("modules/mark/subjectSelect");
        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(new Date());
        rightNow.add(Calendar.YEAR, -1);
        List<Exam> examList = examService.findByMarkerUserId(user.getId(), rightNow.getTime());
        modelAndView.addObject("examList", examList);

        Marker marker = markerService.findById(markerId);
        if (marker == null) {
            modelAndView.addObject("message", "评卷分组不存在");
            return modelAndView;
        }
        Exam exam = examService.findById(marker.getExamId());
        modelAndView.addObject("exam", exam);
        Date now = new Date();
        if ((exam.getStartTime() != null && now.before(exam.getStartTime()))
                || (exam.getEndTime() != null && now.after(exam.getEndTime()))) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String start = exam.getStartTime() == null ? "" : " 开始时间：" + sdf.format(exam.getStartTime());
            String end = exam.getEndTime() == null ? "" : " 结束时间：" + sdf.format(exam.getEndTime());
            modelAndView.addObject("message", "不在评卷时间范围 " + start + " " + end);
            return modelAndView;
        }
        MarkGroup group = groupService.findOne(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
        if (group == null) {
            modelAndView.addObject("message", "评卷分组不存在");
            return modelAndView;
        }
        if (group.getStatus() == MarkStatus.FINISH) {
            modelAndView.addObject("message", "评卷分组已结束");
            return modelAndView;
        }
        user.setMarkerId(marker.getId());
        StmmsSession session = RequestUtils.getSession(request);
        session.saveWebUser(user);
        sessionService.put(request, response, session);
        SessionExamUtils.setExamId(request, exam);
        return new ModelAndView("redirect:/web/mark");
    }

    @RequestMapping("/logout")
    public ModelAndView logout(HttpServletRequest request) {
        WebUser wu = RequestUtils.getWebUser(request);
        releaseMarker(wu.getMarker());
        StmmsSession session = RequestUtils.getSession(request);
        String logoutUrl = session.getWebUserLogoutUrl();
        session.setInvalid(true);
        if (StringUtils.isNotBlank(logoutUrl)) {
            return new ModelAndView("redirect:" + logoutUrl);
        } else {
            return new ModelAndView("redirect:/mark-login");
        }
    }

    @RequestMapping(value = "/getSetting", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject getSetting(HttpServletRequest request) {
        JSONObject setting = new JSONObject();
        WebUser wu = RequestUtils.getWebUser(request);
        Marker marker = wu.getMarker();
        Exam exam = examService.findById(marker.getExamId());
        MarkGroup group = groupService.findOne(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
        setting.accumulate("examType", exam.getType());
        setting.accumulate("remarkCount", exam.getRemarkCount() == null ? "" : exam.getRemarkCount());
        setting.accumulate("showObjectiveScore", exam.getShowObjectiveScore());
        setting.accumulate("startTime", exam.getStartTime() == null ? 0 : exam.getStartTime().getTime());
        setting.accumulate("endTime", exam.getEndTime() == null ? 0 : exam.getEndTime().getTime());
        setting.accumulate("topCount", marker.getTopCount() != null ? marker.getTopCount() : 0);
        setting.accumulate("enableAllZero", group.isEnableAllZero());
        setting.accumulate("statusValue", group.getStatus());
        setting.accumulate("groupNumber", group.getNumber());
        group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(group.getExamId(),
                group.getSubjectCode(), false, group.getNumber()));
        setting.accumulate("groupTitle", group.getTitle());
        setting.accumulate("fileServer", fileService.getRandomFileServer());
        setting.accumulate("uiSetting",
                StringUtils.isBlank(marker.getMarkSetting()) ? new JSONObject() : marker.getMarkSetting());
        setting.accumulate("splitConfig", getSplitConfig());
        setting.accumulate("prefetchCount", prefetchCount);
        if (ExamType.MULTI_MEDIA.equals(exam.getType())) {
            setting.accumulate("mode", MarkMode.COMMON);
            setting.accumulate("forceMode", true);
            setting.accumulate("forceSpecialTag", false);
            setting.accumulate("sheetView", false);
        } else {
            setModeAndForceMode(setting, exam, marker, group);
            setting.accumulate("forceSpecialTag", exam.isForceSpecialTag());
            setting.accumulate("sheetView", group.isSheetView() && exam.isSheetView());
        }
        setSubjectAndSheetConfig(setting, marker, exam);
        setting.accumulate("userName", RequestUtils.getWebUser(request).getName());
        setProblemType(setting, marker);
        setting.accumulate("selective", group.isSelective());
        return setting;
    }

    private double[] getSplitConfig() {
        String strs[] = splitConfig.split(",");
        double[] config = new double[strs.length];
        for (int i = 0; i < strs.length; i++) {
            config[i] = Double.parseDouble(strs[i]);
        }
        return config;
    }

    @RequestMapping(value = "/getStatus", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject status(HttpServletRequest request) {
        JSONObject status = new JSONObject();
        Marker marker = RequestUtils.getWebUser(request).getMarker();
        long classCount = markerClassService.countByUserIdAndExamId(marker.getUserId(), marker.getExamId());
        ExamSubject subject = subjectService.find(marker.getExamId(), marker.getSubjectCode());
        MarkGroup group = groupService.findOne(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
        if (subject == null || group == null || group.getStatus() == MarkStatus.FINISH) {
            status.accumulate("valid", false);
            return status;
        }
        long totalCount = 0;
        long personCount = 0;
        long markedCount = 0;
        long problemCount = 0;
        long arbitrateCount = 0;
        if (group.getStatus() == MarkStatus.FORMAL) {
            MarkLibrarySearchQuery query = new MarkLibrarySearchQuery();
            query.setExamId(marker.getExamId());
            query.setSubjectCode(marker.getSubjectCode());
            query.setGroupNumber(marker.getGroupNumber());
            if (classCount > 0) {
                totalCount = libraryService.countByExamAndSubjectAndGroupAndFilterClass(marker.getExamId(),
                        marker.getSubjectCode(), marker.getGroupNumber(), marker.getUserId());
            } else {
                totalCount = libraryService.countByQuery(query);
            }

            query.setMarkerId(marker.getId());
            query.addStatus(LibraryStatus.MARKED);
            query.addStatus(LibraryStatus.INSPECTED);
            personCount = libraryService.countByQuery(query);
            if (classCount > 0) {
                markedCount = libraryService.countMarkedByExamAndSubjectAndGroupAndFilterClass(marker.getExamId(),
                        marker.getSubjectCode(), marker.getGroupNumber(), marker.getUserId(), LibraryStatus.MARKED,
                        LibraryStatus.INSPECTED, LibraryStatus.ARBITRATED);
            } else {
                query.setMarkerId(0);
                query.addStatus(LibraryStatus.ARBITRATED);
                markedCount = libraryService.countByQuery(query);
            }

            query.clearStatus();
            query.addStatus(LibraryStatus.PROBLEM);
            problemCount = libraryService.countByQuery(query);

            query.clearStatus();
            query.addStatus(LibraryStatus.WAIT_ARBITRATE);
            arbitrateCount = libraryService.countByQuery(query);
        } else if (group.getStatus() == MarkStatus.TRIAL) {
            totalCount = trialService.countLibrary(group.getExamId(), group.getSubjectCode(), group.getNumber());
            personCount = trialService.countByMarkerId(marker.getId());
            markedCount = trialService.countMarkedLibrary(group.getExamId(), group.getSubjectCode(), group.getNumber());
        }
        status.accumulate("personCount", personCount);
        status.accumulate("totalCount", totalCount);
        status.accumulate("markedCount", markedCount);
        status.accumulate("problemCount", problemCount);
        status.accumulate("arbitrateCount", arbitrateCount);
        status.accumulate("valid", totalCount > 0);
        return status;
    }

    @RequestMapping(value = "/getGroup", method = RequestMethod.POST)
    @ResponseBody
    public JSONArray getGroup(HttpServletRequest request) {
        Marker marker = RequestUtils.getWebUser(request).getMarker();
        JSONArray array = new JSONArray();
        List<Marker> markers = markerService.findByExamAndSubjectAndUserIdAndEnable(marker.getExamId(),
                marker.getSubjectCode(), marker.getUserId(), true);
        for (Marker m : markers) {
            JSONObject json = new JSONObject();
            json.accumulate("markerId", m.getId());
            json.accumulate("number", m.getGroupNumber());
            MarkGroup group = groupService.findOne(m.getExamId(), m.getSubjectCode(), m.getGroupNumber());
            group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(group.getExamId(),
                    group.getSubjectCode(), false, group.getNumber()));
            json.accumulate("title", group.getTitle());
            json.accumulate("totalCount", group.getLibraryCount());
            json.accumulate("markedCount", group.getMarkedCount());
            array.add(json);
        }
        return array;
    }

    @RequestMapping(value = "/getTask", method = RequestMethod.POST)
    @ResponseBody
    public Task getTask(HttpServletRequest request) {
        Marker marker = RequestUtils.getWebUser(request).getMarker();
        Task task = null;
        try {
            lockService.watch(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
            lockService.watch(LockType.MARKER, marker.getId());

            MarkGroup group = groupService
                    .findOne(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
            if (group == null) {
                task = new Task();
                task.setMessage("评卷大题不存在");
            } else if (group.getStatus() == MarkStatus.FINISH) {
                task = new Task();
                task.setMessage("评卷已结束");
            } else if (group.getStatus() == MarkStatus.TRIAL) {
                task = getTrialTask(marker);
            } else if (group.getStatus() == MarkStatus.FORMAL) {
                task = getFormalTask(marker);
            }
            if (task == null) {
                task = new Task();
                task.setMessage("当前无评卷任务");
            }
        } catch (Exception e) {
            log.error("get task error", e);
        } finally {
            lockService.unwatch(LockType.MARKER, marker.getId());
            lockService.unwatch(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
        }
        task.setExamNumber(null);
        task.setStudentCode(null);
        if (secretNumberHide) {
            task.setSecretNumber(DEFALT_SECRET_NUMBER);
        }
        return task;
    }

    private Task getFormalTask(Marker marker) {
        int retry = 1;
        Task task = null;
        List<MarkLibrary> list = new ArrayList<MarkLibrary>();
        while (task == null) {
            // 需要判断评卷员是否绑定了机组
            Set<LibraryStatus> statusSet = new HashSet<>();
            statusSet.add(LibraryStatus.WAITING);
            statusSet.add(LibraryStatus.REJECTED);
            long classCount = markerClassService.countByUserIdAndExamId(marker.getUserId(), marker.getExamId());
            list = libraryService.findUnMarked(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber(),
                    marker.getId(), marker.getUserId(), classCount > 0, retry, 20, statusSet);
            if (list.isEmpty()) {
                break;
            }
            for (MarkLibrary library : list) {
                if (markService.applyLibrary(library, marker)) {
                    task = taskService.build(library);
                    break;
                }
            }
            if (task == null) {
                retry++;
            }
        }
        return task;
    }

    private Task getTrialTask(Marker marker) {
        int retry = 1;
        Task task = null;
        while (task == null) {
            List<TrialLibrary> list = trialService.findUnMarkedLibrary(marker.getExamId(), marker.getSubjectCode(),
                    marker.getGroupNumber(), marker.getId(), retry, 10);
            if (list.isEmpty()) {
                break;
            }
            for (TrialLibrary library : list) {
                if (markService.applyLibrary(library, marker)) {
                    task = taskService.build(library);
                    break;
                }
            }
            retry++;
        }
        return task;
    }

    @Logging(menu = "评卷", type = LogType.UPDATE)
    @RequestMapping(value = "/saveTask")
    @ResponseBody
    public JSONObject saveTask(HttpServletRequest request, @RequestBody MarkResult markResult) {
        JSONObject result = new JSONObject();
        Marker marker = RequestUtils.getWebUser(request).getMarker();
        boolean success = false;
        try {
            lockService.watch(LockType.EXAM_SUBJECT, marker.getExamId(), marker.getSubjectCode());
            lockService.watch(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
            lockService.watch(LockType.MARKER, marker.getId());
            lockService.waitlock(LockType.STUDENT, markResult.getStudentId());
            SubmitResult sr = markService.submitTask(markResult, marker);
            if (sr.isSuccess()) {
                markService.releaseTask(sr, marker);
                success = true;
            }
        } catch (Exception e) {
            log.error("save task error", e);
        } finally {
            lockService.unlock(LockType.STUDENT, markResult.getStudentId());
            lockService.unwatch(LockType.MARKER, marker.getId());
            lockService.unwatch(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
            lockService.unwatch(LockType.EXAM_SUBJECT, marker.getExamId(), marker.getSubjectCode());
        }
        result.accumulate("success", success);
        // result.accumulate("status", status(request));
        if (!success) {
            result.accumulate("message", "评卷任务提交失败，请刷新页面");
        }
        return result;
    }

    @Logging(menu = "查询回评任务", type = LogType.QUERY)
    @RequestMapping(value = "/getHistory", method = RequestMethod.POST)
    @ResponseBody
    public Object getHistory(HttpServletRequest request, @RequestParam int pageNumber, @RequestParam int pageSize,
            @RequestParam String order, @RequestParam String sort, @RequestParam(required = false) String secretNumber,
            @RequestParam(required = false) Double markerScore) throws Exception {
        Marker marker = RequestUtils.getWebUser(request).getMarker();
        List<Task> list = new ArrayList<>();
        Direction d = Direction.DESC;
        Sort querySort = null;
        if (sort.equalsIgnoreCase("ASC")) {
            d = Direction.ASC;
        }
        if (order.equals("markerTime")) {
            querySort = new Sort(d, "markerTime");
        } else if (order.equals("markerScore")) {
            querySort = new Sort(d, "markerScore").and(new Sort(Direction.DESC, "markerTime"));
        } else {
            querySort = new Sort(Direction.DESC, "markerTime");
        }
        MarkGroup group = groupService.findOne(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
        Exam exam = examService.findById(marker.getExamId());
        if (group != null && group.getStatus() == MarkStatus.FORMAL) {
            // 正评查找已给分的评卷任务
            MarkLibrarySearchQuery query = new MarkLibrarySearchQuery();
            query.setExamId(marker.getExamId());
            query.setSubjectCode(marker.getSubjectCode());
            query.setMarkerId(marker.getId());
            query.addStatus(LibraryStatus.MARKED);
            query.addStatus(LibraryStatus.INSPECTED);
            query.setGroupNumber(marker.getGroupNumber());
            query.setStartScore(0.0);
            query.setSort(querySort);
            if (StringUtils.isNotBlank(secretNumber) && exam.getRemarkCount() != null) {
                query.setPageNumber(1);
                query.setPageSize(exam.getRemarkCount());
                list = taskService.findHistory(query);
                list = list.stream().filter(e -> e.getSecretNumber().equals(secretNumber)).collect(Collectors.toList());
            } else if (markerScore != null && exam.getRemarkCount() != null) {
                query.setPageNumber(1);
                query.setPageSize(exam.getRemarkCount());
                list = taskService.findHistory(query);
                list = list.stream().filter(e -> e.getMarkerScore().doubleValue() == markerScore.doubleValue())
                        .collect(Collectors.toList());
            } else {
                query.setSecretNumber(secretNumber);
                query.setMarkerScore(markerScore);
                query.setPageNumber(pageNumber);
                query.setPageSize(pageSize);
                list = taskService.findHistory(query);
            }
        } else if (group != null && group.getStatus() == MarkStatus.TRIAL) {
            // 试评查找给分历史记录
            List<TrialLibrary> historyList = new ArrayList<TrialLibrary>();
            if (StringUtils.isNotBlank(secretNumber)) {
                historyList = trialService.findHistory(marker.getExamId(), marker.getSubjectCode(),
                        marker.getGroupNumber(), marker.getId(), secretNumber, pageNumber, pageSize, querySort);
            } else if (markerScore != null) {
                historyList = trialService.findHistory(marker.getExamId(), marker.getSubjectCode(),
                        marker.getGroupNumber(), marker.getId(), pageNumber, pageSize, querySort, markerScore);
            } else {
                historyList = trialService.findHistory(marker.getExamId(), marker.getSubjectCode(),
                        marker.getGroupNumber(), marker.getId(), pageNumber, pageSize, querySort, null);
            }
            for (TrialLibrary library : historyList) {
                Task task = taskService.build(library);
                task.setPrevious(true);
                list.add(task);
            }
        }
        for (Task task : list) {
            task.setExamNumber(null);
            task.setStudentCode(null);
            if (secretNumberHide) {
                task.setSecretNumber(DEFALT_SECRET_NUMBER);
            }
        }
        return list;
    }

    @Logging(menu = "修改密码", type = LogType.UPDATE)
    @RequestMapping(value = "/changeName", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject changeName(HttpServletRequest request, @RequestParam String name,
            @RequestParam(required = false) String password) {
        User user = userService.findById(RequestUtils.getWebUser(request).getId());
        JSONObject result = new JSONObject();
        user.setName(name);
        if (StringUtils.isNotBlank(password)) {
            password = StringEscapeUtils.unescapeHtml(password);
            user.setPassword(EncryptUtils.md5(password));
        }
        try {
            user = userService.save(user);
            result.accumulate("success", true);
        } catch (Exception e) {
            result.accumulate("success", false);
            log.error("MarkController-修改名字出错", e);
        }
        return result;
    }

    @RequestMapping(value = "/updateSetting", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject updateSetting(HttpServletRequest request, @RequestParam(required = false) String uiSetting,
            @RequestParam(required = false) String mode) {
        Marker marker = RequestUtils.getWebUser(request).getMarker();
        if (uiSetting != null) {
            marker.setMarkSetting(StringEscapeUtils.unescapeHtml(StringUtils.trimToNull(uiSetting)));
        }
        if (mode != null) {
            marker.setMode(MarkMode.findByName(mode));
        }
        markerService.save(marker);
        JSONObject result = new JSONObject();
        result.accumulate("success", true);
        return result;
    }

    @RequestMapping("/clear")
    @ResponseBody
    public void clear(HttpServletRequest request) {
        releaseMarker(RequestUtils.getWebUser(request).getMarker());
    }

    @ResponseBody
    @RequestMapping(value = "/subjectSelect", method = RequestMethod.POST)
    public Object subjectSelect(HttpServletRequest request, HttpServletResponse response, @RequestParam Integer markerId) {
        WebUser user = RequestUtils.getWebUser(request);
        Marker old = user.getMarker();
        Marker marker = markerService.findById(markerId);
        JSONObject result = new JSONObject();
        if (marker == null) {
            result.accumulate("success", false);
            result.accumulate("message", "评卷分组不存在");
            return result;
        }
        MarkGroup group = groupService.findOne(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
        if (group == null) {
            result.accumulate("success", false);
            result.accumulate("message", "评卷分组不存在");
        } else if (group.getStatus() == MarkStatus.FINISH) {
            result.accumulate("success", false);
            result.accumulate("message", "评卷分组已结束");
        } else {
            releaseMarker(old);
            user.setMarkerId(marker.getId());
            StmmsSession session = RequestUtils.getSession(request);
            session.saveWebUser(user);
            sessionService.put(request, response, session);
            result.accumulate("success", true);
        }
        return result;
    }

    private void releaseMarker(Marker marker) {
        if (marker == null) {
            return;
        }
        try {
            lockService.waitlock(LockType.MARKER, marker.getId());
            markService.releaseByMarker(marker);
        } catch (Exception e) {
            log.error("release marker error", e);
        } finally {
            lockService.unlock(LockType.MARKER, marker.getId());
        }
    }

    protected String buildPictureConfig(String sheetConfig) {
        String json = "";
        if (StringUtils.isNotBlank(sheetConfig)) {
            try {
                ObjectMapper mapper = new ObjectMapper();
                json = mapper.writeValueAsString(PictureConfigItem.parse(sheetConfig));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return json;
    }

    private void setProblemType(JSONObject setting, Marker marker) {
        List<ProblemType> problemTypes = problemTypeService.findByExamId(marker.getExamId());
        ObjectMapper mapper = new ObjectMapper();
        try {
            setting.accumulate("problemTypes", mapper.writeValueAsString(problemTypes));
        } catch (JsonProcessingException e) {
            log.error("MarkController-问题类型获取出错", e);
        }
    }

    private void setSubjectAndSheetConfig(JSONObject setting, Marker marker, Exam exam) {
        ExamSubject examSubject = subjectService.find(marker.getExamId(), marker.getSubjectCode());
        String sheetConfig = "";
        if (StringUtils.isNotBlank(examSubject.getSheetConfig())) {
            sheetConfig = buildPictureConfig(examSubject.getSheetConfig());
        } else if (StringUtils.isNotBlank(exam.getSheetConfig())) {
            sheetConfig = buildPictureConfig(exam.getSheetConfig());
        }
        setting.accumulate("sheetConfig", sheetConfig);
        setting.accumulate("enableSplit",
                examSubject.getEnableSplit() == null ? exam.isEnableSplit() : examSubject.getEnableSplit());
        setting.accumulate("autoScroll",
                examSubject.getAutoScroll() == null ? exam.isAutoScroll() : examSubject.getAutoScroll());
        JSONObject subject = new JSONObject();
        subject.accumulate("name", examSubject.getName());
        subject.accumulate("code", examSubject.getCode());
        examSubject.setPaperAnswerUrl(fileService);
        subject.accumulate("paperUrl", examSubject.getPaperUrl() == null ? "" : examSubject.getPaperUrl());
        subject.accumulate("answerUrl", examSubject.getAnswerUrl() == null ? "" : examSubject.getAnswerUrl());
        setting.accumulate("subject", subject);
    }

    private void setModeAndForceMode(JSONObject setting, Exam exam, Marker marker, MarkGroup group) {
        MarkMode mode = null;
        boolean forceMode = false;
        if (MarkMode.findByName(forceMarkMode) != null) {
            // 全局配置的强制评卷模式
            mode = MarkMode.findByName(forceMarkMode);
            forceMode = true;
        } else {
            // 没有全局配置，优先从考试取强制评卷模式
            if (exam != null && exam.getMarkMode() != null) {
                mode = exam.getMarkMode();
                forceMode = true;
            } else if (group != null && group.getMarkMode() != null) {
                // 没有全局配置，优先从大题配置取强制评卷模式
                mode = group.getMarkMode();
                forceMode = true;
            }
            // 否则取评卷员当前记录的评卷模式
            if (mode == null) {
                mode = marker.getMode();
            }
            if (mode == null) {
                mode = MarkMode.COMMON;
            }
            if (marker.getMode() != mode) {
                marker.setMode(mode);
                markerService.save(marker);
            }
        }
        setting.accumulate("mode", mode);
        setting.accumulate("forceMode", forceMode);
    }

}
