package cn.com.qmth.stmms.admin.exam;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

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.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.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
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.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

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.model.MarkerDTO;
import cn.com.qmth.stmms.biz.exam.query.MarkerSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
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.lock.LockService;
import cn.com.qmth.stmms.biz.mark.service.MarkService;
import cn.com.qmth.stmms.common.auth.annotation.RoleRequire;
import cn.com.qmth.stmms.common.domain.WebUser;
import cn.com.qmth.stmms.common.enums.LockType;
import cn.com.qmth.stmms.common.enums.MarkerExcelError;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.utils.ExportExcel;
import cn.com.qmth.stmms.common.utils.ImportExcel;
import cn.com.qmth.stmms.common.utils.RequestUtils;

import com.google.common.collect.Lists;

@Controller("examMarkerController")
@RequestMapping("/admin/exam/marker")
public class MarkerController extends BaseExamController {

    protected static Logger log = LoggerFactory.getLogger(MarkerController.class);

    public static final String USER_PASSWORD = "123456";

    @Autowired
    private MarkerService markerService;

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private MarkGroupService groupService;

    @Autowired
    private MarkService markService;

    @Autowired
    private LockService lockService;
    
    @Autowired
    private MarkerClassService classService;
    
    @Autowired
    private ExamStudentService studentService;
    
    @Autowired
    private ExamQuestionService questionService; 

    @Value("${marker.showBtnImportAndBtnUpdateImport}")
    private String showBtnImport;

    @RequestMapping
    public String list(Model model, HttpServletRequest request, MarkerSearchQuery query) {
        WebUser wu = RequestUtils.getWebUser(request);
        int examId = getSessionExamId(request);
        query.setExamId(examId);
        query.orderById();
        subjectFilter(query, wu);
        query = markerService.findByQuery(query);
        for (Marker marker : query.getResult()) {
            marker.setSubject(subjectService.find(marker.getExamId(), marker.getSubjectCode()));
            MarkGroup group = groupService.findOne(examId, marker.getSubjectCode(), marker.getGroupNumber());
            group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId, marker.getSubjectCode(),
                    false, group.getNumber()));
            marker.setGroup(group);
            marker.setMarkedCount(markService.markedCount(marker));
            marker.setCurrentCount(markService.applyCount(marker));
        }
        model.addAttribute("query", query);
        model.addAttribute("subjectList", getExamSubject(examId, wu));
        model.addAttribute("showBtnImport", showBtnImport);
        return "modules/exam/markerList";
    }

    @RequestMapping("/query")
    @ResponseBody
    public JSONArray query(HttpServletRequest request, @RequestParam String subjectCode,
            @RequestParam Integer groupNumber) {
        int examId = getSessionExamId(request);
        JSONArray array = new JSONArray();
        List<Marker> list = markerService.findByExamAndSubjectAndGroup(examId, subjectCode, groupNumber);
        for (Marker marker : list) {
            JSONObject obj = new JSONObject();
            obj.accumulate("id", marker.getId());
            obj.accumulate("loginName", marker.getLoginName());
            obj.accumulate("name", marker.getName());
            array.add(obj);
        }
        return array;
    }

    @RequestMapping("/release")
    @ResponseBody
    @RoleRequire(Role.SCHOOL_ADMIN)
    public JSONObject release(@RequestParam Integer id) {
        JSONObject result = new JSONObject();
        Marker marker = markerService.findById(id);
        if (marker != null) {
            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());
            }
            result.accumulate("success", true);
        } else {
            result.accumulate("success", false);
            result.accumulate("message", "评卷员不存在");
        }
        return result;
    }

    @RequestMapping("/batch-create")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String createInit(Model model, HttpServletRequest request,
            @RequestParam(required = false) String subjectCode, @RequestParam(required = false) Integer groupNumber) {
        int examId = getSessionExamId(request);
        model.addAttribute("subjectList", getExamSubject(examId, RequestUtils.getWebUser(request)));
        if (subjectCode != null) {
            model.addAttribute("subjectCode", subjectCode);
            model.addAttribute("groupList", groupService.findByExamAndSubject(examId, subjectCode));
            if (groupNumber != null) {
                model.addAttribute("groupNumber", groupNumber);
            }
        } else {
            model.addAttribute("groupList", new ArrayList<MarkGroup>());
        }
        return "modules/exam/markerCreate";
    }

    @RequestMapping(value = "/batch-create", method = RequestMethod.POST)
    @RoleRequire(Role.SCHOOL_ADMIN)
    public ModelAndView create(HttpServletRequest request, @RequestParam String subjectCode,
            @RequestParam Integer groupNumber, @RequestParam Integer count,
            @RequestParam(required = false) String password) {
        int examId = getSessionExamId(request);
        ExamSubject subject = subjectService.find(examId, subjectCode);
        ModelAndView view = new ModelAndView("redirect:/admin/exam/marker");
        if (subject != null && count > 0) {
            markerService.batchCreate(subject, groupNumber, count, password);
        }
        view.addObject("subjectCode", subjectCode);
        if (groupNumber > 0) {
            view.addObject("groupNumber", groupNumber);
        }
        return view;
    }

    @RequestMapping(value = "/reset")
    @RoleRequire(Role.SCHOOL_ADMIN)
    public String resetMarker(@RequestParam Integer id, Model model, RedirectAttributes redirectAttributes) {
        Marker marker = markerService.findById(id);
        if (marker != null) {
            try {
                lockService.waitlock(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(),
                        marker.getGroupNumber());
                lockService.waitlock(LockType.MARKER, marker.getId());

                markService.resetMarker(marker);
            } catch (Exception e) {
                log.error("reset marker error", e);
                throw new RuntimeException("重置评卷员失败", e);
            } finally {
                lockService.unlock(LockType.MARKER, marker.getId());
                lockService.unlock(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(),
                        marker.getGroupNumber());
            }
        }
        redirectAttributes.addAttribute("subjectCode", marker.getSubjectCode());
        redirectAttributes.addAttribute("groupNumber", marker.getGroupNumber());
        return "redirect:/admin/exam/marker";
    }

    @RequestMapping(value = "/reset", method = RequestMethod.POST)
    @ResponseBody
    @RoleRequire(Role.SCHOOL_ADMIN)
    public JSONObject resetMarker(@RequestParam Integer id) {
        Marker marker = markerService.findById(id);
        JSONObject obj = new JSONObject();
        if (marker != null) {
            try {
                lockService.waitlock(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(),
                        marker.getGroupNumber());
                lockService.waitlock(LockType.MARKER, marker.getId());

                markService.resetMarker(marker);
                obj.accumulate("success", true);
            } catch (Exception e) {
                log.error("reset marker error", e);
                obj.accumulate("success", false);
                obj.accumulate("message", "重置评卷员失败");
            } finally {
                lockService.unlock(LockType.MARKER, marker.getId());
                lockService.unlock(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(),
                        marker.getGroupNumber());
            }
        } else {
            obj.accumulate("success", false);
            obj.accumulate("message", "该评卷员不存在");
        }
        return obj;
    }

    @RequestMapping(value = "/toggle", method = RequestMethod.POST)
    @ResponseBody
    @RoleRequire(Role.SCHOOL_ADMIN)
    public JSONObject toggle(@RequestParam Integer id, @RequestParam Boolean enable) {
        Marker marker = markerService.findById(id);
        JSONObject obj = new JSONObject();
        if (marker != null) {
            marker.setEnable(enable);
            markerService.save(marker);
            obj.accumulate("success", true);
        } else {
            obj.accumulate("success", false);
            obj.accumulate("message", "该评卷员不存在");
        }
        return obj;
    }

    @RequestMapping(value = "/export", method = RequestMethod.POST)
    public String exportFile(MarkerSearchQuery query, HttpServletRequest request, HttpServletResponse response,
            RedirectAttributes redirectAttributes) {
        WebUser wu = RequestUtils.getWebUser(request);
        int examId = getSessionExamId(request);
        query.setExamId(examId);
        try {
            query.setPageNumber(1);
            query.setPageSize(Integer.MAX_VALUE);
            query.setExamId(examId);
            query.orderById();
            subjectFilter(query, wu);
            String fileName = "评卷员账号.xlsx";
            query = markerService.findByQuery(query);
            for (Marker marker : query.getResult()) {
                ExamSubject subject = subjectService.find(examId, marker.getSubjectCode());
                if (subject != null) {
                    marker.setSubjectName(subject.getCode() + "-" + subject.getName());
                } else {
                    marker.setSubjectName("");
                }
                MarkGroup group = groupService.findOne(examId, marker.getSubjectCode(), marker.getGroupNumber());
                if (group != null) {
                    group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId, group.getSubjectCode(),
                    false, group.getNumber()));
                    marker.setGroupName(group.getNumber() + "-" + group.getTitle());
                } else {
                    marker.setGroupName("");
                }
            }
            new ExportExcel("评卷员数据", Marker.class).setDataList(query.getResult()).write(response, fileName).dispose();
            return null;
        } catch (Exception e) {
            addMessage(redirectAttributes, "导出评卷员失败！" + e.getMessage());
        }
        return "redirect:/admin/exam/marker?repage";
    }

    @RequestMapping(value = "/reSetPassword", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject reSetPassword(@RequestParam Integer id, @RequestParam String password) {
        Marker marker = markerService.findById(id);
        JSONObject obj = new JSONObject();
        if (marker != null) {
            marker.setPassword(password);
            marker = markerService.save(marker);
            obj.accumulate("success", true);
        } else {
            obj.accumulate("success", false);
            obj.accumulate("message", "该评卷员不存在");
        }
        return obj;
    }

    @RequestMapping(value = "/setTaskCount", method = RequestMethod.POST)
    @ResponseBody
    public JSONObject setTaskCount(@RequestParam Integer id, @RequestParam Integer taskCount) {
        Marker marker = markerService.findById(id);
        JSONObject obj = new JSONObject();
        if (marker != null) {
            marker.setTopCount(taskCount);
            marker = markerService.save(marker);
            obj.accumulate("success", true);
        } else {
            obj.accumulate("success", false);
            obj.accumulate("message", "该评卷员不存在");
        }
        return obj;
    }

    @RequestMapping(value = "/template")
    public String importFileTemplate(HttpServletResponse response, RedirectAttributes redirectAttributes) {
        try {
            String fileName = "评卷员数据导入模板.xlsx";
            List<Marker> list = Lists.newArrayList();
            list.add(new Marker());
            new ExportExcel("评卷员数据", Marker.class, 2).setDataList(list).write(response, fileName).dispose();
            return null;
        } catch (Exception e) {
            addMessage(redirectAttributes, "导入模板下载失败！失败信息：" + e.getMessage());
        }
        return "redirect:" + "/admin/exam/marker";
    }

    @RequestMapping(value = "/updateLoginNameTemplate")
    public String updateLoginNameTemplate(HttpServletResponse response, RedirectAttributes redirectAttributes) {
        try {
            String fileName = "评卷员账号修改导入模板.xlsx";
            List<MarkerDTO> list = Lists.newArrayList();
            list.add(new MarkerDTO());
            new ExportExcel("评卷员账号修改数据", MarkerDTO.class, 2).setDataList(list).write(response, fileName).dispose();
            return null;
        } catch (Exception e) {
            addMessage(redirectAttributes, "导入模板下载失败！失败信息：" + e.getMessage());
        }
        return "redirect:" + "/admin/exam/marker";
    }

    @RequestMapping(value = "/import", method = RequestMethod.POST)
    public String importFile(HttpServletRequest request, MultipartFile file, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode) {
        int examId = getSessionExamId(request);
        try {
            int successNum = 0;
            int failureNum = 0;
            StringBuilder failureMsg = new StringBuilder();
            ImportExcel ei = new ImportExcel(file, 1, 0);
            List<Marker> list = ei.getDataList(Marker.class);
            List<Marker> saveList = new LinkedList<Marker>();
            Map<String, Marker> saveMap = new HashMap<String, Marker>();
            Map<String, ExamSubject> current = null;
            current = new HashMap<String, ExamSubject>();
            List<ExamSubject> list2 = subjectService.list(examId);
            for (ExamSubject s : list2) {
                current.put(s.getCode(), s);
            }
            for (Marker marker : list) {
                String password = "";
                if (StringUtils.isBlank(marker.getSubjectCode()) || StringUtils.isBlank(marker.getLoginName())) {
                    continue;
                }
                marker.setExamId(examId);
                marker.setName(marker.getLoginName());
                marker.setEnable(true);
                marker.setClassCount(0);
                if (StringUtils.isBlank(marker.getPassword())) {
                    Random random = new Random();
                    for (int i = 0; i < 6; i++) {
                        password += random.nextInt(10);
                    }
                    marker.setPassword(password);
                }
                MarkerExcelError markerExcelError = checkLongNameAndPassword(marker, current, saveMap);
                if (markerExcelError.equals(MarkerExcelError.MARKER)) {
                    saveList.add(marker);
                    saveMap.put(marker.getLoginName(), marker);
                } else {
                    failureMsg.append("<br/>评卷员 " + marker.getLoginName() + "," + markerExcelError.getName());
                    failureNum++;
                }
            }
            successNum = markerService.batchSave(saveList);
            if (failureNum > 0) {
                failureMsg.insert(0, "，失败 " + failureNum + " 条记录！");
            }
            addMessage(redirectAttributes, "已成功导入 " + successNum + " 条评卷员" + failureMsg);
        } catch (Exception e) {
            log.error("Batch import marker error!", e);
            addMessage(redirectAttributes, "导入评卷员失败！失败信息：" + e.getMessage());
        }
        return "redirect:" + "/admin/exam/marker?subjectCode=" + subjectCode;
    }

    @RequestMapping(value = "/importUpdate", method = RequestMethod.POST)
    public String importUpdateFile(HttpServletRequest request, MultipartFile file,
            RedirectAttributes redirectAttributes) {
        try {
            int successNum = 0;
            int failureNum = 0;
            StringBuilder failureMsg = new StringBuilder();
            ImportExcel ei = new ImportExcel(file, 1, 0);
            List<MarkerDTO> list = ei.getDataList(MarkerDTO.class);
            List<Marker> saveList = new LinkedList<Marker>();
            Map<String, Marker> current = null;
            List<Marker> list2 = markerService.findMode("common");
            if (list2.size() < 10000) {
                current = new HashMap<String, Marker>();
                for (Marker s : list2) {
                    current.put(s.getLoginName(), s);
                }
            }
            for (MarkerDTO markerDTO : list) {
                if (StringUtils.isBlank(markerDTO.getSubjectCode()) || StringUtils.isBlank(markerDTO.getLoginName())
                        || StringUtils.isBlank(markerDTO.getNewLoginName())
                        || StringUtils.isBlank(markerDTO.getPassword())) {
                    continue;
                }
                MarkerExcelError markerExcelError = checkExcelData(markerDTO, current);
                if (markerExcelError.equals(MarkerExcelError.MARKER)) {
                    Marker marker = null;
                    if (current != null) {
                        marker = current.get(markerDTO.getLoginName());
                    } else {
                        marker = markerService.findByLoginName(markerDTO.getLoginName());
                    }
                    marker.setLoginName(markerDTO.getNewLoginName());
                    marker.setPassword(markerDTO.getPassword());
                    saveList.add(marker);
                } else {
                    failureMsg.append("<br/>科目代码(" + markerDTO.getSubjectCode() + ")原评卷员(" + markerDTO.getLoginName()
                            + ")更换新评卷员为(" + markerDTO.getNewLoginName() + ")失败!");
                    failureMsg.append("---->失败原因：(" + markerExcelError.getName() + ")");
                    failureNum++;
                }
            }
            successNum = markerService.batchSave(saveList);
            if (failureNum > 0) {
                failureMsg.insert(0, "，失败 " + failureNum + " 条记录！");
            }
            addMessage(redirectAttributes, "已成功导入 " + successNum + " 条" + failureMsg);
        } catch (Exception e) {
            log.error("Batch import marker error!", e);
            addMessage(redirectAttributes, "导入修改评卷员账号失败！失败信息：" + e.getMessage());
        }
        return "redirect:" + "/admin/exam/marker";
    }

    private MarkerExcelError checkLongNameAndPassword(Marker marker, Map<String, ExamSubject> current,
            Map<String, Marker> saveMap) {
        Marker previous = null;

        if (current != null && current.get(marker.getSubjectCode()) == null) {
            return MarkerExcelError.MARKERNOTCODE;
        }
        MarkGroup group = groupService.findOne(marker.getExamId(), marker.getSubjectCode(),
                Integer.valueOf(marker.getGroupName()));
        if (group == null) {
            return MarkerExcelError.MARKERNOTGROUP;
        } else {
            marker.setGroupNumber(Integer.valueOf(marker.getGroupName()));
        }
        if (saveMap != null) {
            previous = saveMap.get(marker.getLoginName());
        }

        if (previous != null) {
            return MarkerExcelError.MARKERED;
        }

        previous = markerService.findByLoginName(marker.getLoginName());

        if (marker.getPassword().length() > 0 && marker.getPassword().length() < 4) {
            return MarkerExcelError.MARKERPWERROR;
        }

        if (previous == null) {
            return MarkerExcelError.MARKER;
        }
        return MarkerExcelError.MARKERED;
    }

    // 校验excel中数据
    public MarkerExcelError checkExcelData(MarkerDTO markerDTO, Map<String, Marker> current) {
        if (markerDTO != null) {
            Marker marker = null;
            if (current == null) {
                marker = markerService.findByLoginName(markerDTO.getLoginName());
            } else {
                marker = current.get(markerDTO.getLoginName());
            }
            if (markerDTO.getPassword().length() < 4) {
                return MarkerExcelError.MARKERPWERROR;
            }
            if (marker != null) {
                if (marker.getSubjectCode().equals(markerDTO.getSubjectCode())) {
                    if (markerService.countByLoginName(markerDTO.getNewLoginName()) > 0) {
                        return MarkerExcelError.MARKERNEWMISS;
                    } else {
                        return MarkerExcelError.MARKER;
                    }
                } else {
                    return MarkerExcelError.MARKERCODEMISS;
                }
            } else {
                return MarkerExcelError.MARKERMISS;
            }
        } else {
            return MarkerExcelError.MARKERNOTINFO;
        }
    }
    
    @RequestMapping(value = "/class/{markerId}", method = RequestMethod.GET)
    public String classAdd(@PathVariable Integer markerId, Model model,RedirectAttributes redirectAttributes) {
        Marker marker = markerService.findById(markerId);
        if (marker != null) {
            model.addAttribute("marker", marker);
            List<String> classList = studentService.findDistinctClassName(marker.getExamId(),marker.getSubjectCode());
            Set<String> classes  = classService.findClassNameByMarkerId(markerId);
            classList.removeAll(classes);
            model.addAttribute("classList", classList);
            model.addAttribute("classes", classes);
            return "modules/exam/markerClass";
        } 
        addMessage(redirectAttributes, "评卷员不存在");
        return "redirect:/admin/exam/marker";
    }

    @RequestMapping(value = "/class/{markerId}", method = RequestMethod.POST)
    public String classSave(@PathVariable Integer markerId,@RequestParam(required=false) String[] classes,Model model,RedirectAttributes redirectAttributes) {
        Marker marker = markerService.findById(markerId);
        if (marker != null) {
            classService.save(marker,classes);
            addMessage(redirectAttributes, "保存'" + marker.getLoginName() + "'成功");
            return "redirect:" + "/admin/exam/marker?subjectCode=" + marker.getSubjectCode()+"&groupNumber="+marker.getGroupNumber();
        } 
        addMessage(redirectAttributes, "评卷员不存在");
        return "redirect:/admin/exam/marker";
    }
}
