package cn.com.qmth.stmms.biz.report.utils.module;

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

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;

import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
import cn.com.qmth.stmms.biz.report.model.ReportSubject;
import cn.com.qmth.stmms.biz.report.model.ReportSubjectGroup;
import cn.com.qmth.stmms.biz.report.service.ReportSubjectGroupService;
import cn.com.qmth.stmms.biz.report.service.ReportSubjectService;
import cn.com.qmth.stmms.biz.report.utils.Module;
import cn.com.qmth.stmms.biz.report.utils.QuestionCalculatorProvider;
import cn.com.qmth.stmms.biz.report.utils.ReportContext;
import cn.com.qmth.stmms.biz.report.utils.unit.BaseCalculatorUnit;
import cn.com.qmth.stmms.biz.report.utils.unit.LevelRange;
import cn.com.qmth.stmms.biz.report.utils.unit.QuestionCounter;
import cn.com.qmth.stmms.biz.utils.SpringContextHolder;

/**
 * 按科目统计全样本小题难度等级与区分度等级
 * 
 * @author luoshi
 *
 */
public class SubjectQuestionLevelModule implements Module {

    protected ReportContext context;

    protected QuestionCalculatorProvider provider;

    protected Map<String, List<ExamQuestion>> objectiveQuestions, subjectiveQuestions;

    protected Map<String, QuestionCounter> difficulityLevels, discriminationLevels;

    protected LevelRange[] difficulityLevelConfig, discriminationLevelConfig;

    protected Map<String, Set<String>> paperTypes;

    public SubjectQuestionLevelModule(ReportContext context, QuestionCalculatorProvider provider) {
        this.context = context;
        this.provider = provider;
        this.objectiveQuestions = new HashMap<String, List<ExamQuestion>>();
        this.subjectiveQuestions = new HashMap<String, List<ExamQuestion>>();
        this.difficulityLevels = new HashMap<String, QuestionCounter>();
        this.discriminationLevels = new HashMap<String, QuestionCounter>();
        this.difficulityLevelConfig = context.getDifficulityLevelConfig();
        this.discriminationLevelConfig = context.getDiscriminationLevelConfig();
        this.paperTypes = new HashMap<String, Set<String>>();
    }

    @Override
    public void process(ExamStudent student) {
        if (!student.isUpload() || student.isAbsent()) {
            return;
        }
        String key = student.getSubjectCode() + "\t" + StringUtils.trimToEmpty(student.getPaperType());
        List<ExamQuestion> olist = objectiveQuestions.get(key);
        if (olist == null) {
            olist = new ArrayList<ExamQuestion>();
            objectiveQuestions.put(key, olist);
            olist.addAll(student.getObjectiveQuestionList());
        }
        List<ExamQuestion> slist = subjectiveQuestions.get(student.getSubjectCode());
        if (slist == null) {
            slist = new ArrayList<ExamQuestion>();
            subjectiveQuestions.put(student.getSubjectCode(), slist);
            slist.addAll(student.getSubjectiveQuestionList());
        }
    }

    @Override
    public void save() {
        beforeSave();
        ReportSubjectService subjectService = SpringContextHolder.getBean(ReportSubjectService.class);
        ReportSubjectGroupService groupService = SpringContextHolder.getBean(ReportSubjectGroupService.class);
        for (Entry<String, QuestionCounter> entry : difficulityLevels.entrySet()) {
            String key = entry.getKey();
            String s[] = key.split("\t");
            String subjectCode = s[0];
            QuestionCounter difficulityCounter = entry.getValue();
            QuestionCounter discriminationCounter = discriminationLevels.get(key);
            JSONObject difficulityLevel = new JSONObject();
            for (int i = 0; i < difficulityCounter.levelCount; i++) {
                JSONObject value = new JSONObject();
                value.accumulate("questionCount", difficulityCounter.totalCount[i]);
                value.accumulate("fullScore", difficulityCounter.totalScore[i]);
                String level = null;
                switch (i) {
                case 0:
                    level = "high";
                    break;
                case 1:
                    level = "middle";
                    break;
                case 2:
                    level = "low";
                    break;
                }
                if (level != null) {
                    difficulityLevel.accumulate(level, value);
                }
            }
            JSONObject discriminationLevel = new JSONObject();
            for (int i = 0; i < discriminationCounter.levelCount; i++) {
                JSONObject value = new JSONObject();
                value.accumulate("questionCount", discriminationCounter.totalCount[i]);
                value.accumulate("fullScore", discriminationCounter.totalScore[i]);
                String level = null;
                switch (i) {
                case 0:
                    level = "excellent";
                    break;
                case 1:
                    level = "good";
                    break;
                case 2:
                    level = "general";
                    break;
                case 3:
                    level = "bad";
                    break;
                }
                if (level != null) {
                    discriminationLevel.accumulate(level, value);
                }
            }
            if (s.length == 1 || s.length == 2) {
                if (s.length == 2) {
                    String paperType = StringUtils.trimToNull(s[1]);
                    Set<String> paperTypes = this.paperTypes.get(subjectCode);
                    if (paperType != null && !contains(paperTypes, paperType)) {
                        return;
                    }
                }
                ReportSubject r = subjectService.findOne(context.getExamId(), subjectCode);
                r.setDifficulityLevel(difficulityLevel.toString());
                r.setDiscriminationLevel(discriminationLevel.toString());
                subjectService.save(r);
            }
            if (s.length >= 4) {
                Boolean objective = Boolean.parseBoolean(s[1]);
                String paperType = StringUtils.trimToNull(s[2]);
                Integer mainNumber = Integer.parseInt(s[3]);
                ReportSubjectGroup r = groupService.findOne(context.getExamId(), subjectCode, objective, paperType,
                        mainNumber);
                r.setDifficulityLevel(difficulityLevel.toString());
                r.setDiscriminationLevel(discriminationLevel.toString());
                groupService.save(r);
            }
        }
    }

    private boolean contains(Set<String> paperTypes, String paperType) {
        for (String s : paperTypes) {
            if (paperType.equalsIgnoreCase(s)) {
                return true;
            }
        }
        return false;
    }

    protected void beforeSave() {

        // 遍历客观题
        for (Entry<String, List<ExamQuestion>> entry : objectiveQuestions.entrySet()) {
            String[] keys = entry.getKey().split("\t");
            String subjectCode = keys[0];
            String paperType = keys.length > 1 ? StringUtils.trimToNull(keys[1]) : null;
            if (paperType != null) {
                Set<String> set = paperTypes.get(subjectCode);
                if (set == null) {
                    set = new HashSet<String>();
                    paperTypes.put(subjectCode, set);
                }
                set.add(paperType);
            }
            for (ExamQuestion question : entry.getValue()) {
                if (question.getTotalScore() == null || question.getTotalScore() == 0) {
                    continue;
                }
                BaseCalculatorUnit calculator = provider.getCalculator(question);
                if (calculator == null) {
                    continue;
                }
                // 按全卷维度统计
                findDifficulityLevelCounter(entry.getKey()).process(question, calculator.difficulty);
                findDiscriminationLevelCounter(entry.getKey()).process(question, calculator.discrimination);
                // 按大题维度统计
                findDifficulityLevelCounter(getGroupKey(question)).process(question, calculator.difficulty);
                findDiscriminationLevelCounter(getGroupKey(question)).process(question, calculator.discrimination);
            }
        }
        // 遍历主观题
        for (Entry<String, List<ExamQuestion>> entry : subjectiveQuestions.entrySet()) {
            String subjectCode = entry.getKey();
            for (ExamQuestion question : entry.getValue()) {
                if (question.getTotalScore() == null || question.getTotalScore() == 0) {
                    continue;
                }
                BaseCalculatorUnit calculator = provider.getCalculator(question);
                if (calculator == null) {
                    continue;
                }
                // 按全卷维度统计
                Set<String> paperTypeSet = paperTypes.get(subjectCode);
                if (paperTypeSet == null || paperTypeSet.isEmpty()) {
                    // 不区分paperType
                    String key = subjectCode + "\t";
                    findDifficulityLevelCounter(key).process(question, calculator.difficulty);
                    findDiscriminationLevelCounter(key).process(question, calculator.discrimination);
                } else {
                    // 遍历已存在的paperType
                    for (String paperType : paperTypeSet) {
                        String key = subjectCode + "\t" + paperType;
                        findDifficulityLevelCounter(key).process(question, calculator.difficulty);
                        findDiscriminationLevelCounter(key).process(question, calculator.discrimination);
                    }
                }
                // 按大题维度统计
                findDifficulityLevelCounter(getGroupKey(question)).process(question, calculator.difficulty);
                findDiscriminationLevelCounter(getGroupKey(question)).process(question, calculator.discrimination);
            }
        }
    }

    protected String getGroupKey(ExamQuestion question) {
        return question.getSubjectCode() + "\t" + question.isObjective() + "\t"
                + StringUtils.trimToEmpty(question.getPaperType()) + "\t" + question.getMainNumber();
    }

    protected QuestionCounter findDifficulityLevelCounter(String key) {
        QuestionCounter counter = difficulityLevels.get(key);
        if (counter == null) {
            counter = new QuestionCounter(difficulityLevelConfig);
            difficulityLevels.put(key, counter);
        }
        return counter;
    }

    protected QuestionCounter findDiscriminationLevelCounter(String key) {
        QuestionCounter counter = discriminationLevels.get(key);
        if (counter == null) {
            counter = new QuestionCounter(discriminationLevelConfig);
            discriminationLevels.put(key, counter);
        }
        return counter;
    }

}
