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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import cn.com.qmth.stmms.admin.vo.MarkerVO;
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.query.MarkerSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
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.MarkerService;
import cn.com.qmth.stmms.biz.lock.LockService;
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.thread.MarkQualityThread;
import cn.com.qmth.stmms.common.domain.WebUser;
import cn.com.qmth.stmms.common.enums.LibraryStatus;
import cn.com.qmth.stmms.common.enums.LockType;
import cn.com.qmth.stmms.common.utils.RequestUtils;

@Controller("markQualityController")
@RequestMapping("/admin/exam/quality")
public class MarkQualityController extends BaseExamController {

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

    @Autowired
    private MarkGroupService groupService;

    @Autowired
    private MarkerService markerService;

    @Autowired
    private LockService lockService;

    @Autowired
    private AsyncTaskExecutor taskExecutor;

    @Autowired
    private ExamSubjectService subjectService;

    @Autowired
    private MarkLibraryService libraryService;

    @Autowired
    private ExamQuestionService questionService;
    
    @RequestMapping
    public String list(Model model, HttpServletRequest request, MarkerSearchQuery query) {
        int examId = getSessionExamId(request);
        WebUser wu = RequestUtils.getWebUser(request);
        List<ExamSubject> subjectList = getExamSubject(examId, wu);
        if (subjectList.isEmpty()) {
            return "redirect:/admin/exam/mark";
        }
        query.setExamId(examId);
        query.orderById();
        if (query.getSubjectCode() == null && !subjectList.isEmpty()) {
            query.setSubjectCode(subjectList.get(0).getCode());
        }
        subjectFilter(query, wu);
        List<MarkGroup> groupList = groupService.findByExamAndSubject(examId, query.getSubjectCode());
        if (query.getGroupNumber() == null && groupList.size() > 0) {
            query.setGroupNumber(groupList.get(0).getNumber());
        }
        if (query.getSubjectCode() != null && query.getGroupNumber() != null) {
            query = markerService.findByQuery(query);
            model.addAttribute("running", lockService.isLocked(LockType.BATCH_QUALITY,
                    getLockKey(examId, query.getSubjectCode(), query.getGroupNumber())));
        }
        model.addAttribute("query", query);
        model.addAttribute("subjectList", subjectList);
        model.addAttribute("groupList", groupList);
        return "modules/exam/qualityList";
    }

    @RequestMapping("/update")
    public String update(HttpServletRequest request, RedirectAttributes redirectAttributes,
            @RequestParam String subjectCode, @RequestParam Integer groupNumber) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, groupNumber);
        if (group != null) {
            final String lockKey = getLockKey(examId, subjectCode, groupNumber);
            if (lockService.trylock(LockType.BATCH_QUALITY, lockKey)) {
                taskExecutor.submit(new MarkQualityThread(
                        markerService.findByExamAndSubjectAndGroup(examId, subjectCode, groupNumber), lockKey));
            }
            redirectAttributes.addAttribute("groupNumber", groupNumber);
        }
        redirectAttributes.addAttribute("subjectCode", subjectCode);
        return "redirect:/admin/exam/quality";
    }

    private String getLockKey(Integer examId, String subjectCode, Integer groupNumber) {
        return examId + "_" + subjectCode + "_" + groupNumber;
    }

    @RequestMapping("/chart")
    public String chart(HttpServletRequest request, Model model, @RequestParam String subjectCode,
            @RequestParam Integer groupNumber) {
        int examId = getSessionExamId(request);
        MarkGroup group = groupService.findOne(examId, subjectCode, groupNumber);
        if (group != null) {
            List<MarkerVO> list = new ArrayList<MarkerVO>();
            List<Marker> markers = markerService.findByExamAndSubjectAndGroup(examId, subjectCode, groupNumber);
            List<Double> scores = libraryService.findScore(examId, subjectCode, groupNumber, LibraryStatus.MARKED);
            for (Marker marker : markers) {
                List<Object[]> libraries = libraryService.findScoreCount(examId, subjectCode, groupNumber,
                        marker.getId(), LibraryStatus.MARKED);
                Map<Double, Long> scoreCount = new HashMap<Double, Long>();
                for (Object[] array : libraries) {
                    Double score = (Double) array[0];
                    Long count = (Long) array[1];
                    scoreCount.put(score, count);
                }
                MarkerVO vo = new MarkerVO();
                vo.setLoginName(marker.getLoginName());
                vo.setName(marker.getName());
                vo.setScoreCount(scoreCount);
                list.add(vo);
            }
            group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId, subjectCode,
                    false, group.getNumber()));
            model.addAttribute("scores", scores);
            model.addAttribute("markers", list);
            model.addAttribute("group", group);
        }
        model.addAttribute("subject", subjectService.find(examId, subjectCode));
        model.addAttribute("subjectCode", subjectCode);
        model.addAttribute("groupNumber", groupNumber);
        return "modules/exam/qualityChart";
    }

    @RequestMapping("/getChart")
    @ResponseBody
    public List<MarkerVO> getChart(HttpServletRequest request, @RequestParam String subjectCode,
            @RequestParam Integer groupNumber) {
        int examId = getSessionExamId(request);
        List<MarkerVO> list = new ArrayList<MarkerVO>();
        List<Marker> markers = markerService.findByExamAndSubjectAndGroup(examId, subjectCode, groupNumber);
        for (Marker marker : markers) {
            List<Object[]> libraries = libraryService.findScoreCount(examId, subjectCode, groupNumber, marker.getId(),
                    LibraryStatus.MARKED);
            MarkLibrarySearchQuery query = new MarkLibrarySearchQuery();
            query.setMarkerId(marker.getId());
            query.addStatus(LibraryStatus.MARKED);
            long totalCount = libraryService.countByQuery(query);
            Map<Double, Double> scorePercent = new HashMap<Double, Double>();
            for (Object[] array : libraries) {
                Double score = (Double) array[0];
                Long count = (Long) array[1];
                double percent = 0;
                if (totalCount != 0) {
                    percent = count * 100 / totalCount;
                }
                scorePercent.put(score, percent);
            }
            MarkerVO vo = new MarkerVO();
            vo.setLoginName(marker.getLoginName());
            vo.setName(marker.getName());
            vo.setScorePercent(scorePercent);
            list.add(vo);
        }
        return list;
    }

}
