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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;

public class SubjectQuestionDTO {

    private static final String NULL_PAPER_TYPE_PLACEHOLDER = "#";

    private int examId;

    private String subjectCode;

    private List<ExamQuestion> list;

    private double totalScore;

    private boolean objective;

    private Map<String, List<ExamQuestion>> paperTypeList;

    private Map<Integer, MarkGroup> groups;

    public SubjectQuestionDTO(int examId, String subjectCode, boolean objective) {
        this.examId = examId;
        this.subjectCode = subjectCode;
        this.list = new LinkedList<ExamQuestion>();
        this.paperTypeList = new HashMap<>();
        this.groups = new HashMap<Integer, MarkGroup>();
        this.totalScore = 0d;
        this.objective = objective;
    }

    public void addQuestion(ExamQuestion question) {
        if (question != null && question.getTotalScore() != null) {
            question.setExamId(examId);
            list.add(question);

            if (objective) {
                String paperType = question.getPaperType();
                if (paperType == null) {
                    paperType = NULL_PAPER_TYPE_PLACEHOLDER;
                }
                List<ExamQuestion> list = paperTypeList.get(paperType);
                if (list == null) {
                    list = new ArrayList<>();
                    paperTypeList.put(paperType, list);
                }
                list.add(question);
            } else {
                MarkGroup group = groups.get(question.getGroupNumber());
                if (group == null) {
                    group = new MarkGroup(examId, subjectCode, question.getGroupNumber(),
                            PictureConfigItem.parse(question.getPicList()), 0d, question.getDoubleRate(),
                            question.getArbitrateThreshold(), question.getScorePolicy(), question.getMarkMode(),
                            question.getTrialCount(), false);
                    group.setQuestionMap(new HashMap<Integer, List<ExamQuestion>>());
                    groups.put(question.getMainNumber(), group);
                }
                List<ExamQuestion> list = group.getQuestionMap().get(question.getMainNumber());
                if (list == null) {
                    list = new ArrayList<ExamQuestion>();
                    group.getQuestionMap().put(question.getMainNumber(), list);
                }
                list.add(question);
                group.setTotalScore(group.getTotalScore() + question.getTotalScore());
                totalScore += question.getTotalScore();
            }
        }
    }

    public List<ExamQuestion> getQuestionList() {
        return list;
    }

    public String getSubjectCode() {
        return subjectCode;
    }

    public double getTotalScore() {
        return totalScore;
    }

    public Map<Integer, MarkGroup> getGroups() {
        return groups;
    }

    public boolean validate(List<String> error) {
        if (list.size() > 0) {
            Set<String> numberSet = new HashSet<String>();
            Map<Integer, String> titleMap = new HashMap<Integer, String>();
            Map<Integer, Integer> groupNumberMap = new HashMap<Integer, Integer>();
            try {
                // 基本字段合法性校验
                for (ExamQuestion question : list) {
                    if (StringUtils.isBlank(question.getMainTitle())) {
                        error.add("[" + subjectCode + "] 有大题名称为空的记录");
                        return false;
                    }
                    if (question.getMainTitle().length() > 30) {
                        error.add("[" + subjectCode + "] 有大题名称超过30个字的记录");
                        return false;
                    }
                    if (question.getMainNumber() == null || question.getSubNumber() == null) {
                        error.add("[" + subjectCode + "] 有题号为空的记录");
                        return false;
                    }
                    if (question.getGroupNumber() == null || question.getGroupNumber() < 0) {
                        error.add("[" + subjectCode + "] 有评卷分组为空的记录");
                        return false;
                    }
                    if (question.getTotalScore() == null) {
                        error.add("[" + subjectCode + "] 有满分为空的记录");
                        return false;
                    }
                    if (objective && StringUtils.isBlank(question.getAnswer())) {
                        error.add("[" + subjectCode + "] 有答案为空的记录");
                        return false;
                    }

                    String title = titleMap.get(question.getMainNumber());
                    if (title != null && !title.equals(question.getMainTitle())) {
                        error.add("[" + subjectCode + "] 大题号" + question.getMainNumber() + "有名称不一致的记录");
                        return false;
                    } else {
                        titleMap.put(question.getMainNumber(), question.getMainTitle());
                    }

                    Integer groupNumber = groupNumberMap.get(question.getMainNumber());
                    if (groupNumber != null && !groupNumber.equals(question.getGroupNumber())) {
                        error.add("[" + subjectCode + "] 大题号" + question.getMainNumber() + "有评卷分组不一致的记录");
                        return false;
                    } else {
                        groupNumberMap.put(question.getMainNumber(), question.getGroupNumber());
                    }

                    String number = question.getQuestionNumber();
                    if (objective) {
                        number = StringUtils.trimToEmpty(question.getPaperType()) + " " + number;
                    }
                    if (numberSet.contains(number)) {
                        error.add("[" + subjectCode + "] 题号" + number + "有重复记录");
                        return false;
                    } else {
                        numberSet.add(number);
                    }
                }

                // 客观题时额外校验不同试卷类型的总分需要一致
                if (objective) {
                    totalScore = -1;
                    List<ExamQuestion> questions = null;
                    for (Entry<String, List<ExamQuestion>> entry : paperTypeList.entrySet()) {
                        double score = 0;
                        for (ExamQuestion question : entry.getValue()) {
                            score += question.getTotalScore();
                        }
                        if (totalScore == -1) {
                            totalScore = score;
                        } else if (totalScore != score) {
                            error.add("[" + subjectCode + "] 多个试卷类型总分不一致");
                            return false;
                        }
                        if (questions != null) {
                            String message = check(questions, entry.getValue());
                            if (message != null) {
                                error.add("[" + subjectCode + "] 多个试卷类型" + message);
                                return false;
                            }
                        } else {
                            questions = entry.getValue();
                        }
                    }
                }
                return true;
            } finally {
                numberSet.clear();
                titleMap.clear();
                groupNumberMap.clear();
            }
        } else {
            return false;
        }
    }

    private String check(List<ExamQuestion> questions, List<ExamQuestion> value) {
        if (questions.size() != value.size()) {
            return "题目总数不一致";
        }
        Map<Integer, Integer> subCountMap = new HashMap<Integer, Integer>();
        Map<Integer, Double> mainScoreMap = new HashMap<Integer, Double>();
        int maniCount = 0;
        for (ExamQuestion question : questions) {
            if (question.getTotalScore() != 0) {
                Integer subCount = subCountMap.get(question.getMainNumber());
                if (subCount != null) {
                    subCountMap.put(question.getMainNumber(), subCount + 1);
                    Double mainScore = mainScoreMap.get(question.getMainNumber());
                    mainScoreMap.put(question.getMainNumber(), mainScore + question.getTotalScore());
                } else {
                    subCountMap.put(question.getMainNumber(), 1);
                    mainScoreMap.put(question.getMainNumber(), question.getTotalScore());
                    maniCount++;
                }
            }
        }

        Map<Integer, Integer> subCountMap1 = new HashMap<Integer, Integer>();
        Map<Integer, Double> mainScoreMap1 = new HashMap<Integer, Double>();
        int maniCount1 = 0;
        for (ExamQuestion question : value) {
            if (question.getTotalScore() != 0) {
                Integer subCount = subCountMap1.get(question.getMainNumber());
                if (subCount != null) {
                    subCountMap1.put(question.getMainNumber(), subCount + 1);
                    Double mainScore = mainScoreMap1.get(question.getMainNumber());
                    mainScoreMap1.put(question.getMainNumber(), mainScore + question.getTotalScore());
                } else {
                    subCountMap1.put(question.getMainNumber(), 1);
                    mainScoreMap1.put(question.getMainNumber(), question.getTotalScore());
                    maniCount1++;
                }
            }
        }
        if (maniCount != maniCount1) {
            return "大题数量不一致";
        }
        for (Integer mainNumber : subCountMap.keySet()) {
            if (!subCountMap.get(mainNumber).equals(subCountMap1.get(mainNumber))) {
                return "小题数量不一致";
            }
            if (!mainScoreMap.get(mainNumber).equals(mainScoreMap1.get(mainNumber))) {
                return "大题总分不一致";
            }
        }
        return null;
    }
}
