/*
 * ================================================================== $Id:
 * codetemplates.xml,v 1.1 2006/04/24 09:18:57 饶国发 Exp $ Created [2014-9-20
 * 上午11:18:43] by 饶国发
 * ================================================================== qrzk
 * ================================================================== qrzk
 * License v1.0 Copyright (c) Wuhan G-Soft Technology CO.,LTD., 2010-2012
 * ==================================================================
 * 武汉威鹏科技有限公司拥有该文件的使用、复制、修改和分发的许可权 如果你想得到更多信息，请访问 <http://www.wptech.net.cn>
 * 
 * Wuhan WP-Soft Technology CO.,LTD. owns permission to use, copy, modify and
 * distribute this documentation. For more information on qrzk, please see
 * <http://www.wptech.net.cn>.
 * ==================================================================
 */

package com.qmth.qrzk.repository.pager.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.qmth.qrzk.dao.IQuestionDao;
import com.qmth.qrzk.repository.common.base.BaseDao;
import com.qmth.qrzk.repository.common.mapper.PaperSimilarityMapper;
import com.qmth.qrzk.repository.common.mapper.QuestionMapper;
import com.qmth.qrzk.repository.exception.BizException;
import com.qmth.qrzk.repository.pager.model.PagerConstruct;
import com.qmth.qrzk.repository.pager.model.PagerConstructDetail;
import com.qmth.qrzk.repository.pager.model.PagerConstructQtype;
import com.qmth.qrzk.repository.pager.model.PaperSkeleton;
import com.qmth.qrzk.repository.pager.model.PaperSkeletonDetail;
import com.qmth.qrzk.repository.service.query.AvailableQuesQueryParams;
import com.qmth.qrzk.repository.service.query.PagerQueryParams;
import com.qmth.qrzk.repository.service.query.PaperSimilarityQueryParams;
import com.qmth.qrzk.repository.task.PaperTask;
import com.qmth.qrzk.repository.user.model.Code;
import com.qmth.qrzk.repository.user.model.Question;
import com.qmth.qrzk.repository.user.model.QuestionOption;
import com.qmth.qrzk.repository.user.model.QuestionType;
import com.qmth.qrzk.repository.user.model.SimilarPaper;
import com.qmth.qrzk.repository.user.model.SimilarPaperQuestion;
import com.qmth.qrzk.repository.user.model.SimilarQuestion;
import com.qmth.qrzk.repository.user.model.User;
import com.qmth.qrzk.repository.user.service.impl.PaperSkeletonService;
import com.qmth.qrzk.repository.user.service.impl.QuestionServiceImpl;
import com.qmth.qrzk.repository.utils.Consts;
import com.qmth.qrzk.repository.utils.DateHelper;
import com.qmth.qrzk.repository.utils.General;
import com.qmth.qrzk.repository.utils.ParamUtils;
import com.qmth.qrzk.repository.utils.StringSimilarityUtils;
import com.qmth.qrzk.repository.utils.zujuan.OldQuestionSet;

/**
 * <p>
 * PagerConstructService.java
 * </p>
 * <p>
 * 组卷service（试卷）
 * </p>
 * 
 * @author $Author: 饶国发 $
 * @version $Revision: V5.1 $
 */
@Service
public class PagerConstructService {

	@Autowired
	private BaseDao dao;

	@Autowired
	private PaperSkeletonService paperSkeletonSrv;

	@Autowired
	private ZujuanService zujuanService;

	@Autowired
	private QuestionServiceImpl questionService;
	
	@Autowired
	@Qualifier("paperSimilarityMapper")
	private PaperSimilarityMapper paperSimilarityMapper;
	
	@Autowired
	@Qualifier("questionMapper")
	private QuestionMapper questionMapper;
	
	@Autowired
	@Qualifier("questionDaoImpl")
	private IQuestionDao questionDao;

	/***
	 * 根据课程信息获取细目表
	 * <p>
	 * </p>
	 * 
	 * @param courseId
	 * @return
	 */
	public List<PaperSkeleton> findSkectionsByCourse(int courseId, int bookId) {
		Map<String, Integer> param = new HashMap<String, Integer>();
		param.put("courseId", courseId);
		param.put("bookId", bookId);
		return dao.getList("findSkectionsByCourse", param);
	}

	public int countBlankQuesNum(int paperId) {
		return dao.get("countBlankQuesNumByPaperId", paperId);
	}

	public PagerConstruct generateBlankPaper(PaperTask task, User curUser) {
		PagerConstruct pager = task.getPagerConstruct();
		if (pager == null) {
			PaperSkeleton skel = paperSkeletonSrv.queryById(task.getPaperSkeleton().getId());
			List<QuestionType> quesTypeArr = skel.getQuesTypeArr();
			Map<String, List<PaperSkeletonDetail>> skelDetailMap = new HashMap<String, List<PaperSkeletonDetail>>();
			for (PaperSkeletonDetail d : skel.getSkeletonDetailArr()) {
				QuestionType qt = quesTypeArr.get(d.getQuesTypeNo() - 1);
				String key = qt.getId() + "_" + qt.getDefaultScore();
				List<PaperSkeletonDetail> dList = skelDetailMap.get(key);
				if (dList == null) {
					dList = new ArrayList<PaperSkeletonDetail>();
					skelDetailMap.put(key, dList);
				}
				dList.add(d);
			}

			pager = new PagerConstruct();
			pager.setTaskId(task.getId());
			pager.setName(task.getTaskNo());
			String head = Consts.DEFAULT_HEAD.replace("XXXX", DateHelper.formatDate(new Date(), "yyyy")).replace("XX",
					DateHelper.formatDate(new Date(), "M"));
			pager.setHead(head);
			pager.setSkeletonId(skel.getId());
			pager.setResourse(2);// 手工组卷
			pager.setStatus(Consts.PaperStatus.DRAFT);// 草稿
			pager.setCreatedBy(curUser.getId());

			List<PagerConstructQtype> pcqtList = new ArrayList<PagerConstructQtype>();
			pager.setQtypeList(pcqtList);
			for (int j = 0; j < quesTypeArr.size(); j++) {
				QuestionType qt = quesTypeArr.get(j);
				PagerConstructQtype pcqt = new PagerConstructQtype();
				pcqt.setName(qt.getName());
				pcqt.setQuestionTypeId(qt.getId());
				pcqt.setSortNo(j + 1);
				pcqt.setScore(qt.getDefaultScore());
				pcqt.setCreatedBy(curUser.getId());
				List<PaperSkeletonDetail> dList = skelDetailMap.get(qt.getId() + "_" + qt.getDefaultScore());

				List<PagerConstructDetail> pcdList = new ArrayList<PagerConstructDetail>();
				pcqt.setConstructDetails(pcdList);
				for (int m = 0; dList != null && m < dList.size(); m++) {
					PaperSkeletonDetail detail = dList.get(m);
					for (int t = 0; t < detail.getQuesNum(); t++) {
						PagerConstructDetail pcDetail = new PagerConstructDetail();
						pcDetail.setQuestionScore(qt.getDefaultScore());
						pcDetail.setSortNo(m + 1);
						pcDetail.setCreatedBy(curUser.getId());
						pcDetail.setQuestionId(0);
						pcdList.add(pcDetail);
					}
				}
				pcqt.setQuestionSum(pcdList.size());
				pcqt.setQuestionScores(pcqt.getQuestionSum() * pcqt.getScore());
				pcqtList.add(pcqt);
			}

			/******************** 分割线，上面是组卷逻辑，下面就要开始保存组好试卷了 ******************/
			dao.insert("addPagerConstruct", pager);
			for (PagerConstructQtype pcqt : pager.getQtypeList()) {
				pcqt.setPagerConstructId(pager.getId());
				dao.insert("addPagerConstructQtype", pcqt);
				for (PagerConstructDetail detail : pcqt.getConstructDetails()) {
					detail.setPagerConstructId(pager.getId());
					detail.setPagerQtypeId(pcqt.getId());
					dao.insert("addPagerConstructDetail", detail);
				}
			}
		}

		pager = zujuanService.getWholePaperInfoForShow(pager.getId());
		task.setPagerConstruct(pager);
		return pager;
	}

	/**
	 * 智能组一张试卷
	 * 
	 * @param task
	 * @param curUser
	 * @param enableLeak
	 *            - 是否允许缺少试题
	 * @return
	 * @throws BizException
	 */
	public PagerConstruct autoAdd(PaperTask task, User curUser, boolean enableLeak) throws BizException {
		PagerConstruct pager = task.getPagerConstruct();
		if (pager == null) {
			pager = autoZujuan(paperSkeletonSrv.queryById(task.getPaperSkeleton().getId()), 1, curUser, task.getId(),
					task.getTaskNo(), Consts.DEFAULT_HEAD.replace("XXXX", DateHelper.formatDate(new Date(), "yyyy"))
							.replace("XX", DateHelper.formatDate(new Date(), "M")),
					enableLeak).get(0);
			/******************** 分割线，上面是组卷逻辑，下面就要开始保存组好试卷了 ******************/
			dao.insert("addPagerConstruct", pager);
			for (PagerConstructQtype pcqt : pager.getQtypeList()) {
				pcqt.setPagerConstructId(pager.getId());
				dao.insert("addPagerConstructQtype", pcqt);
				for (PagerConstructDetail detail : pcqt.getConstructDetails()) {
					detail.setPagerConstructId(pager.getId());
					detail.setPagerQtypeId(pcqt.getId());
					dao.insert("addPagerConstructDetail", detail);
				}
			}
		}
		pager = zujuanService.getWholePaperInfoForShow(pager.getId());
		task.setPagerConstruct(pager);
		return pager;
	}

	/**
	 * 
	 * <p>
	 * </p>
	 * 组卷
	 * 
	 * @param skeleton_id
	 *            ,细目表id
	 * @param zj_sum
	 *            ，组卷数量
	 * @param i_same
	 *            重复题限制数量（暂时未使用）
	 * @param i_old
	 *            旧题数量限制（暂时未使用）
	 * @return
	 * @throws BizException
	 */
	public List<PagerConstruct> dealZujuan(int skeleton_id, String head, int zj_sum, User user, int i_same, int i_old)
			throws BizException {
		PaperSkeleton skel = paperSkeletonSrv.queryById(skeleton_id);
		List<PagerConstruct> paperList = autoZujuan(skel, zj_sum, user, null, null, head, false);
		/******************** 分割线，上面是组卷逻辑，下面就要开始保存组好试卷了 ******************/
		for (PagerConstruct pager : paperList) {
			dao.insert("addPagerConstruct", pager);
			for (PagerConstructQtype pcqt : pager.getQtypeList()) {
				pcqt.setPagerConstructId(pager.getId());
				dao.insert("addPagerConstructQtype", pcqt);
				for (PagerConstructDetail detail : pcqt.getConstructDetails()) {
					detail.setPagerConstructId(pager.getId());
					detail.setPagerQtypeId(pcqt.getId());
					dao.insert("addPagerConstructDetail", detail);
				}
			}
		}
		return paperList;
	}

	/**
	 * 智能组卷通用方法
	 * 
	 * @param skel
	 *            - 组卷细目表
	 * @param number
	 *            - 试卷数量
	 * @param user
	 *            - 当前用户
	 * @param taskId
	 *            - 任务ID
	 * @param name
	 *            - 试卷名称
	 * @param header
	 *            - 试卷抬头
	 * @param enableLeak
	 *            - 是否允许缺少试题，若不允许则直接抛出异常
	 * @return
	 * @throws BizException
	 */
	private List<PagerConstruct> autoZujuan(PaperSkeleton skel, int number, User user, Integer taskId, String name,
			String header, boolean enableLeak) throws BizException {
		List<QuestionType> quesTypeArr = skel.getQuesTypeArr();
		Map<String, List<PaperSkeletonDetail>> skelDetailMap = new HashMap<String, List<PaperSkeletonDetail>>();
		for (PaperSkeletonDetail d : skel.getSkeletonDetailArr()) {
			QuestionType qt = quesTypeArr.get(d.getQuesTypeNo() - 1);
			String key = qt.getId() + "_" + qt.getDefaultScore();
			List<PaperSkeletonDetail> dList = skelDetailMap.get(key);
			if (dList == null) {
				dList = new ArrayList<PaperSkeletonDetail>();
				skelDetailMap.put(key, dList);
			}
			dList.add(d);
		}

		List<Question> newQuestionList = this.dao.getList("queryNewQuestion", skel);// 所有可用的新题
		Map<String, List<Question>> newQuestionMap = new HashMap<String, List<Question>>();
		for (Question q : newQuestionList) {
			String key = getZujuanKey(q);
			List<Question> quesList = newQuestionMap.get(key);
			if (quesList == null) {
				quesList = new ArrayList<Question>();
				newQuestionMap.put(key, quesList);
			}
			quesList.add(q);
		}
		List<Question> oldQuestionList = this.dao.getList("query3YearOldQuestion", skel);// 所有使用超过3年的旧题
		OldQuestionSet oldSet = new OldQuestionSet(0.2);
		for (Question q : oldQuestionList) {
			oldSet.addQuestion(q, getZujuanKey(q));
		}
		Set<Integer> usedSet = new HashSet<Integer>();
		Map<String, List<Question>> chosenQuesMap = new HashMap<String, List<Question>>();

		List<PagerConstruct> paperList = new ArrayList<PagerConstruct>();
		for (int i = 0; i < number; i++) {
			// Set<Integer> quesIdSetForCurPager = new
			// HashSet<Integer>();当前试卷中已被选中的试题
			PagerConstruct pager = new PagerConstruct();
			pager.setTaskId(taskId);
			// 若没有指定名称，则取细目表名称+序号
			pager.setName(name != null ? name : skel.getName() + General.toUpperLetter(i + 1));
			pager.setHead(header);
			pager.setSkeletonId(skel.getId());
			pager.setResourse(1);// 智能组卷
			pager.setStatus(Consts.PaperStatus.DRAFT);// 草稿
			pager.setCreatedBy(user.getId());
			pager.setMaxOldCount(0);
			pager.setMaxSameCount(0);
			paperList.add(pager);

			List<PagerConstructQtype> pcqtList = new ArrayList<PagerConstructQtype>();
			pager.setQtypeList(pcqtList);
			for (int j = 0; j < quesTypeArr.size(); j++) {
				QuestionType qt = quesTypeArr.get(j);
				PagerConstructQtype pcqt = new PagerConstructQtype();
				pcqt.setName(qt.getName());
				pcqt.setQuestionTypeId(qt.getId());
				pcqt.setSortNo(j + 1);
				pcqt.setScore(qt.getDefaultScore());
				pcqt.setCreatedBy(user.getId());
				List<PaperSkeletonDetail> dList = skelDetailMap.get(qt.getId() + "_" + qt.getDefaultScore());

				List<PagerConstructDetail> pcdList = new ArrayList<PagerConstructDetail>();
				pcqt.setConstructDetails(pcdList);
				for (int m = 0; dList != null && m < dList.size(); m++) {
					PaperSkeletonDetail detail = dList.get(m);
					for (int t = 0; t < detail.getQuesNum(); t++) {
						PagerConstructDetail pcDetail = new PagerConstructDetail();
						pcDetail.setQuestionScore(qt.getDefaultScore());
						pcDetail.setSortNo(m + 1);
						pcDetail.setCreatedBy(user.getId());
						Random rand = new Random();
						
						String key = getZujuanKey(qt, detail);
						Question ques = null;
						{
							List<Question> quesList = newQuestionMap.get(key);
							// 循环从新题列表中取题尝试
							while (quesList != null && quesList.size() > 0) {
								//ques = quesList.remove(0);
								ques = quesList.remove(rand.nextInt(quesList.size()));
								if (usedSet.contains(ques.getId())) {
									// 当前试题已用过，继续取下一题
									continue;
								} else {
									break;//从新题列表中找到，并且已用题目里面没有，则跳出while
								}
							}
						}
						if (ques == null) {
							// 循环从旧题列表中尝试取题
							while (true) {
								ques = oldSet.selectQuestion(key);
								if (ques != null) {
									if (usedSet.contains(ques.getId())) {
										// 当前试题已用过，继续取下一题
										continue;
									} else {
										break;
									}
								} else {
									// 取题失败，直接退出
									break;
								}
							}
						}
						if (ques == null) {
							if (enableLeak) {
								// 允许缺题的情况下，自动构建空白试题对象
								ques = new Question();
								ques.setId(0);
							} else {
								throw new BizException(getTip(qt, detail) + "的题量不够，请补充试题");
							}
							// 以下判断内容直接忽略，暂不考虑重复试题
							// if (i == 0) {
							// if (curOldQuesList == null ||
							// curOldQuesList.size() == 0) {
							// throw new BizException(getTip(qt, detail) +
							// "的题量不够，请补充试题。");
							// } else {
							// throw new BizException("要使用的旧题量已超过了旧题数量限制");
							// }
							// } else {
							// if (i_same > 0) {//
							// 这个时候一定能在已选中的题中找到可用的题，因为第1套试卷已经组好了。
							// List<Question> chosenQuesList =
							// chosenQuesMap.get(key);
							// for (Question q : chosenQuesList) {
							// if (quesIdSetForCurPager.contains(q.getId())) {
							// continue;
							// } else {
							// ques = q;
							// i_same--;
							// break;
							// }
							// }
							// } else {
							// throw new BizException("要重复使用的题量已超过了重复题限制数量");
							// }
							// }
						} else {
							// 取题成功，记录结果
							usedSet.add(ques.getId());

							List<Question> chosenQuesList = chosenQuesMap.get(key);
							if (chosenQuesList == null) {
								chosenQuesList = new ArrayList<Question>();
								chosenQuesMap.put(key, chosenQuesList);
							}
							chosenQuesList.add(ques);
						}
						// quesIdSetForCurPager.add(ques.getId());
						pcDetail.setQuestionId(ques.getId());
						pcdList.add(pcDetail);
					}
				}
				pcqt.setQuestionSum(pcdList.size());
				pcqt.setQuestionScores(pcqt.getQuestionSum() * pcqt.getScore());
				pcqtList.add(pcqt);
			}
		}

		return paperList;
	}

	private static String getZujuanKey(Question q) {
		StringBuilder key = new StringBuilder(String.valueOf(q.getTypeId()));
		if (!ParamUtils.IgnoreScoreWhenZj) {
			key.append("_score_").append(q.getScore());
		}
		if (!ParamUtils.IgnoreChapterWhenZj) {
			key.append("_chapter_").append(q.getChapter());
		}
		if (!ParamUtils.IgnoreDiffWhenZj) {
			key.append("_difficulty_").append(q.getEstimateDifficultyCode());
		}
		if (!ParamUtils.IgnoreAbilityWhenZj) {
			key.append("_ability_").append(q.getAbilityCode());
		}
		return key.toString();
	}

	private static String getZujuanKey(QuestionType qt, PaperSkeletonDetail detail) {
		StringBuilder key = new StringBuilder(String.valueOf(qt.getId()));
		if (!ParamUtils.IgnoreScoreWhenZj) {
			key.append("_score_").append(qt.getDefaultScore());
		}
		if (!ParamUtils.IgnoreChapterWhenZj) {
			key.append("_chapter_").append(detail.getChapterNo());
		}
		if (!ParamUtils.IgnoreDiffWhenZj) {
			key.append("_difficulty_").append(detail.getEstimateDifficultyCode());
		}
		if (!ParamUtils.IgnoreAbilityWhenZj) {
			key.append("_ability_").append(detail.getAbilityCode());
		}
		return key.toString();
	}

	private static StringBuffer getTip(QuestionType qt, PaperSkeletonDetail detail) {
		StringBuffer tip = new StringBuffer();
		tip.append("题型为 ").append(qt.getName()).append(" ");
		if (!ParamUtils.IgnoreScoreWhenZj) {
			tip.append("、分值为 ").append(General.formatScore(qt.getDefaultScore())).append(" ");
		}
		if (!ParamUtils.IgnoreChapterWhenZj) {
			tip.append("、章节为 ").append(detail.getChapterNo()).append(" ");
		}
		if (!ParamUtils.IgnoreDiffWhenZj) {
			tip.append("、预计难度为 ").append(detail.getEstimateDifficultyText()).append(" ");
		}
		if (!ParamUtils.IgnoreAbilityWhenZj) {
			tip.append("、认知层次为 ").append(detail.getAbilityText()).append(" ");
		}
		return tip;
	}

	public void savePaper(PagerConstruct paper) {
		dao.update("updatePagerConstruct", paper);
		for (PagerConstructQtype qt : paper.getQtypeList()) {
			dao.update("updatePagerConstructQtype", qt);
			for (PagerConstructDetail detail : qt.getConstructDetails()) {
				dao.update("updatePagerConstructDetail", detail);
			}
		}
	}

	public List<Question> queryAvailableQues(AvailableQuesQueryParams queryParams) {
		PagerConstructQtype pcqtype = dao.get("getPagerConstructQtypesById", queryParams.getPcqtId());
		PagerConstruct construct = dao.get("findPagerConstructById", pcqtype.getPagerConstructId());
		queryParams.setScore(pcqtype.getScore());
		queryParams.setQtId(pcqtype.getQuestionTypeId());
		queryParams.setCourseId(construct.getSkeleton().getCourseId());
		queryParams.setBookId(construct.getSkeleton().getBookId());
		queryParams.setConstructId(construct.getId());
		List<Question> quesList = dao.getPagerList("queryAvailableQues", queryParams);
		return quesList;
	}

	public Question randomQues(int pcqtId, int detailId, String curQuesIdListStr, String rndListStr) {
		PagerConstructQtype pcqtype = dao.get("getPagerConstructQtypesById", pcqtId);
		PagerConstruct paper = dao.get("findPagerConstructById", pcqtype.getPagerConstructId());
		Question quesCondition = new Question();
		quesCondition.setCourseId(paper.getSkeleton().getCourseId());
		quesCondition.setBookId(paper.getSkeleton().getBookId());
		quesCondition.setTypeId(pcqtype.getQuestionTypeId());
		quesCondition.setScore(pcqtype.getScore());

		List<Question> quesList = questionService.zjGetAllQuestions(quesCondition, paper.getId(),
				Consts.QuesOperTypeForZj.CHANGE_INTO_PAPER, detailId);
		if (quesList == null || quesList.size() == 0) {
			return null;
		}
		Question ques = null;
		String[] rndList = rndListStr.split(",");
		List<Integer> rndedList = new ArrayList<Integer>();
		for (String rnded : rndList) {
			if (!General.isEmpty(rnded)) {
				rndedList.add(Integer.parseInt(rnded));
			}
		}
		if (rndedList.size() == 0) {// 如果之前没有取过，就取第一个
			ques = quesList.get(0);
		} else {
			Map<Integer, Integer> repeatNumMap = new HashMap<Integer, Integer>();
			Map<Integer, Question> quesMap = new HashMap<Integer, Question>();

			for (Question q : quesList) {
				repeatNumMap.put(q.getId(), 0);
				quesMap.put(q.getId(), q);
			}
			List<Integer> curQuesIdList = new ArrayList<Integer>();
			for (String qIdStr : curQuesIdListStr.split(",")) {
				int qId = General.toInteger(qIdStr, 0);
				if (!curQuesIdList.contains(qId)) {
					curQuesIdList.add(qId);
				}
				repeatNumMap.remove(qId);// 把当前试题列表重复的试题从repeatNumMap去掉，保证随机取时不会取到重复的数据
			}
			if (repeatNumMap.size() == 0) {
				return null;
			}
			for (int i = 0; i < rndedList.size() - 1; i++) {
				int qIdTmp = rndedList.get(i);
				if (!curQuesIdList.contains(qIdTmp)) {
					Integer repeatNum = repeatNumMap.get(qIdTmp);
					if (repeatNum == null) {
						repeatNum = 0;
					}
					repeatNum++;
					repeatNumMap.put(qIdTmp, repeatNum);
				}
			}
			List<Map.Entry<Integer, Integer>> entryList = new ArrayList<Map.Entry<Integer, Integer>>(
					repeatNumMap.entrySet());
			Collections.sort(entryList, new Comparator<Map.Entry<Integer, Integer>>() {

				@Override
				public int compare(Entry<Integer, Integer> o1, Entry<Integer, Integer> o2) {
					return o1.getValue() - o2.getValue();
				}
			});
			ques = quesMap.get(entryList.get(0).getKey());
		}
		General.quesWordToHtmlForShow(ques);
		return ques;
	}

	public Map<String, Object> questionStat(int paperId, int questionId) {
		Map<String, Object> statResult = new HashMap<String, Object>();
		{// 获取不在当前试卷下的其他试卷信息
			Map<String, Object> param = new HashMap<String, Object>();
			param.put("paperId", paperId);
			param.put("questionId", questionId);
			List<PagerConstruct> papers = dao.getList("statQuestionInPaper", param);
			statResult.put("papers", papers);
			statResult.put("papersSize", (papers != null) ? papers.size() : 0);
		}
		{// 获取试题的详情，为了传输熟虑考虑，去掉试题的题干和答案数据
			Question qustion = dao.getObject("searchQuestionWithOptionsById", questionId);
			// QuestionType qt = dao.get("selectQuestionTypeById",
			// qustion.getTypeId());
			List<Code> codeList = dao.getList("findAllCodes");
			Map<String, String> codeMap = new HashMap<String, String>();
			for (Code code : codeList) {
				codeMap.put(code.getItemType() + "|" + code.getItemCode(), code.getItemValue());
			}
			qustion.setEstimateDifficultyText(
					codeMap.get("QUESTION_DIFFICULTY|" + qustion.getEstimateDifficultyCode()));
			qustion.setMeasuredDifficultyText(
					codeMap.get("QUESTION_DIFFICULTY|" + qustion.getMeasuredDifficultyCode()));
			qustion.setGradeText(codeMap.get("GRADE|" + qustion.getGradeCode()));
			qustion.setAbilityText(codeMap.get("ABILITY|" + qustion.getAbilityCode()));
			qustion.setAssessmentDemandText(codeMap.get("ASSESSMENT_DEMAND|" + qustion.getAssessmentDemand()));
			qustion.setBodyWord(null);
			qustion.setBody(null);
			qustion.setBodySummary(null);

			qustion.setAnswer(null);
			qustion.setAnswerSummary(null);
			qustion.setOptions(null);
			qustion.setAnswerWord(null);
			qustion.setAnswerSheet(null);
			statResult.put("qustion", qustion);
		}
		return statResult;
	}

	/**
	 * 启用试卷方法
	 * 
	 * @param quesId
	 * @param date
	 *            yyyy-mm
	 * @return
	 */
	public void saveOpenPaper(String paperCode, String date) {
		List<PagerConstruct> paperList = dao.getList("getPapersByPaperCode",paperCode);
		for(PagerConstruct paper:paperList){
			// 说明已经启用
			if (paper.getStartTime() == null && General.isNotEmpty(date)) {
				paper.setStartTime(DateHelper.parseYearString(date));
				dao.update("updatePagerConstruct", paper);
				// 同时更新所有试题启用时间
				dao.update("updateQuestionStartTime", paper);
			}
		}
	}

	/**
	 * <p>
	 * 统计一张试卷中所有相似试题
	 * </p>
	 * @author songyue
	 * @date 2016-05-12
	 */
	public List<SimilarQuestion> checkSimilarity(int paperId) {
		List<SimilarQuestion> similarQuestionList = new ArrayList<SimilarQuestion>();
		List<SimilarQuestion> resultList = new ArrayList<SimilarQuestion>();
		PagerConstruct paper = zujuanService.findById(paperId);
		if (paper == null) {
			return null;
		}
		List<PagerConstructQtype> qtypes = dao.getList("findPagerConstructQtypesByPaperId", paperId);
		for (PagerConstructQtype qt : qtypes) {
			for (PagerConstructDetail pcd : qt.getConstructDetails()) {
				Question ques = pcd.getQuestion();
				if (ques != null && pcd.getQuestionId() != 0) {
					List<QuestionOption> quesOption = ques.getOptions();
					String option = "";
					if (quesOption != null && quesOption.size() > 0) {
						for (QuestionOption op : quesOption) {
							option += op.getSummary();
						}
					}
					SimilarQuestion simlarQuestion = new SimilarQuestion();
					simlarQuestion.setSimilarQuestionName(qt.getName() + "-" + pcd.getSortNo().intValue());
					simlarQuestion.setSimilarQuestionNo(ques.getQuestionNo());
					simlarQuestion.setSimilarQuestionBody(ques.getBodySummary() + option);
					similarQuestionList.add(simlarQuestion);
				}
			}
		}
		int size = similarQuestionList.size();
		double similarity = 0;
		for (int i = 0; i < size; i++) {
			for (int j = i + 1; j < size; j++) {
				SimilarQuestion similarques1 = similarQuestionList.get(i);
				SimilarQuestion similarques2 = similarQuestionList.get(j);
				if ((similarity = StringSimilarityUtils.getSimilarityWithCosinesBySeg(similarques1.getSimilarQuestionBody(),
						similarques2.getSimilarQuestionBody()) * 100) >= 60) {
					SimilarQuestion similarResult = new SimilarQuestion();
					similarResult.setSimilarQuestionName(
							similarques1.getSimilarQuestionName() + "," + similarques2.getSimilarQuestionName());
					similarResult.setSimilarity(String.format("%.2f", similarity));
					resultList.add(similarResult);
				}
			}
		}
		Collections.sort(resultList);
		return resultList;
	}
	
	/**
	 * <p>
	 * 检查试题选项相似度
	 * </p>
	 * @author songyue
	 * @date 2016-08-12
	 */
	public List<SimilarQuestion> checkSimilarityOption(int quesId) {
		long start = System.currentTimeMillis();
		List<SimilarQuestion> similarQuestionList = new ArrayList<SimilarQuestion>();
		List<SimilarQuestion> resultList = new ArrayList<SimilarQuestion>();
		Question ques = questionMapper.searchById(quesId);
		if (ques == null) {
			return null;
		}else if (ques != null) {
			List<QuestionOption> quesOption = ques.getOptions();
			if (quesOption != null && quesOption.size() > 0) {
				for (QuestionOption op : quesOption) {
					SimilarQuestion simlarQuestion = new SimilarQuestion();
					simlarQuestion.setSimilarQuestionName(op.getOptionNoString() + "选项");
					simlarQuestion.setSimilarQuestionNo(ques.getQuestionNo());
					simlarQuestion.setSimilarQuestionBody(extratHtmlNew(op.getContentHtml()));
					similarQuestionList.add(simlarQuestion);
				}
			} else {
				return null;
			}
		}
		int size = similarQuestionList.size();
		double similarity = 0;
		for (int i = 0; i < size; i++) {
			for (int j = i + 1; j < size; j++) {
				SimilarQuestion similarques1 = similarQuestionList.get(i);
				SimilarQuestion similarques2 = similarQuestionList.get(j);
				if ((similarity = StringSimilarityUtils.getSimilarityWithCosinesBySeg(similarques1.getSimilarQuestionBody(),
						similarques2.getSimilarQuestionBody()) * 100) >= 0) {
					SimilarQuestion similarResult = new SimilarQuestion();
					similarResult.setSimilarQuestionName(
							similarques1.getSimilarQuestionName() + "," + similarques2.getSimilarQuestionName());
					similarResult.setSimilarity(String.format("%.2f", similarity));
					resultList.add(similarResult);
				}
			}
		}
		Collections.sort(resultList);
		long end = System.currentTimeMillis();
		System.out.println("选项相似度检查耗时--->" + (end - start)/1000.0);
		return resultList;
	}
	
	public static String extratHtmlNew(String html){
		String htmlStr = "";
		htmlStr = General.repairHtmlFormula(html);
		htmlStr = General.extractText(htmlStr);
		return htmlStr;
	}
	
	/**
	 * <p>查询相似试卷</p>
	 * @author songyue
	 * @date 2016-05-20
	 */
	public List<SimilarPaper> queryPaperSimilarity(PaperSimilarityQueryParams paperparam) {
		return paperSimilarityMapper.queryPaperSimilarity(paperparam);
	}
	
	/**
	 * <p>查询相似试卷试题</p>
	 * @author songyue
	 * @date 2016-08-08
	 */
	public List<Question> queryPaperQuestionSimilarity(String similarPaperNo,String whichQuestion) {
		return questionMapper.searchPaperQuestionForSimilar(similarPaperNo, whichQuestion);
	}
	
	/**
	 * 
	 * <p>查询相似试卷数量</p>
	 * @author songyue
	 * @date 2016-05-20
	 */
	public int queryPaperSimilarityCount(PaperSimilarityQueryParams paperparam) {
		return paperSimilarityMapper.queryPaperSimilarityCount(paperparam);
	}
	
	/**
	 * <p>清空相似试卷</p>
	 * @author songyue
	 * @date 2016-05-20
	 */
	public int delAllPaperSimilarity(){
		return dao.delete("delAllPaperSimilarity", null);
	}
	
	/**
	 * <p>清空相似试卷试题</p>
	 * @author songyue
	 * @date 2016-05-20
	 */
	public int delAllPaperQuestionSimilarity(){
		return dao.delete("delAllPaperQuestionSimilarity", null);
	}
	
	/**
	 * <p>新增相似试卷</p>
	 * @author songyue
	 * @date 2016-05-20
	 */
	public int addPaperSimilarity(List<SimilarPaper> list){
		return dao.insert("addPaperSimilarity", list);
	}
	
	/**
	 * <p>新增相似试卷试题</p>
	 * @author songyue
	 * @date 2016-08-03
	 */
	public int addPaperQuestionSimilarity(List<SimilarPaperQuestion> list){
		return dao.insert("addPaperQuestionSimilarity", list);
	}
	
	/**
	 * 检查试卷相似度
	 * @author songyue
	 * @date 2016-05-20
	 */
	public List<SimilarPaper> checkSimilarity() {
		List<PagerConstruct> paperList = zujuanService.queryPagers(new PagerQueryParams());
		List<SimilarPaper> similarPaperList = new ArrayList<SimilarPaper>();
		List<SimilarPaper> resultList = new ArrayList<SimilarPaper>();
		for (PagerConstruct paper : paperList) {
			List<Question> questionList = new ArrayList<Question>();
			if (paper != null) {
				List<PagerConstructQtype> qtypes = dao.getList("findPagerConstructQtypesByPaperId", paper.getId());
				PaperTask task = dao.get("getPaperTaskById", paper.getTaskId());
				String paperBody = "";
				String courseName = "";
				String bookName = "";
				String courseCode = "";
				for (PagerConstructQtype qt : qtypes) {
					for (PagerConstructDetail pcd : qt.getConstructDetails()) {
						Question ques = pcd.getQuestion();
						//Question ques = questionDao.searchById(pcd.getQuestionId());
						if(ques != null){
							ques.setQuestionName(qt.getName() + pcd.getSortNo().toString());
							ques.setTypeName(qt.getName());
							questionList.add(ques);
						}
						if (ques != null && !StringUtils.isBlank(ques.getBodySummary()) && pcd.getQuestionId() != 0) {
							paperBody += ques.getBodySummary();
							List<QuestionOption> quesOption = ques.getOptions();
							String option = "";
							if (quesOption != null && quesOption.size() > 0) {
								for (QuestionOption op : quesOption) {
									option += op.getSummary();
								}
							}
							paperBody += option;
						}
						courseName = task.getCourse().getName();
						bookName = task.getBook().getName();
						courseCode = task.getBook().getCode();
					}
				}
				SimilarPaper similarPaper = new SimilarPaper();
				similarPaper.setSimilarPaperNo(paper.getName());
				similarPaper.setSimilarPaperBody(paperBody);
				similarPaper.setBookName(bookName);
				similarPaper.setCourseName(courseName);
				similarPaper.setCreatedBy(paper.getCreatedBy().toString());
				similarPaper.setCreatedByName(paper.getCreatedByName());
				similarPaper.setTaskId(paper.getTaskId().toString());
				similarPaper.setTaskNo(task.getTaskNo());
				similarPaper.setCourseNo(courseCode);
				similarPaper.setQuestionList(questionList);
				similarPaperList.add(similarPaper);
			}
		}
		paperList.removeAll(paperList);
		paperList = null;
		int size = similarPaperList.size();
		double similarity = 0;
		for (int i = 0; i < size; i++) {
			for (int j = i + 1; j < size; j++) {
				SimilarPaper similarPaper1 = similarPaperList.get(i);
				SimilarPaper similarPaper2 = similarPaperList.get(j);
				// 检查同课程、同教材的试卷相似度（全文比对）
				if (!StringUtils.isBlank(similarPaper1.getSimilarPaperBody())
						&& !StringUtils.isBlank(similarPaper2.getSimilarPaperBody())
						&& similarPaper1.getCourseName().equals(similarPaper2.getCourseName())) {
					if ((similarity = StringSimilarityUtils.getSimilarityWithCosinesBySeg(similarPaper1.getSimilarPaperBody(),
							similarPaper2.getSimilarPaperBody()) * 100) >= 60) {
						SimilarPaper similarResult = new SimilarPaper();
						similarResult.setSimilarPaperNo(
								similarPaper1.getSimilarPaperNo() + "," + similarPaper2.getSimilarPaperNo());
						similarResult.setSimilarity(String.format("%.2f", similarity));
						similarResult.setSimilarPaperBody(
								similarPaper1.getSimilarPaperBody() + "||" + similarPaper2.getSimilarPaperBody());
						similarResult.setCourseName(similarPaper1.getCourseName());
						similarResult.setBookName(similarPaper1.getBookName());
						similarResult.setCreatedBy(similarPaper1.getCreatedBy() + "," + similarPaper2.getCreatedBy());
						similarResult.setCreatedByName(
								similarPaper1.getCreatedByName() + "," + similarPaper2.getCreatedByName());
						similarResult.setTaskId(similarPaper1.getTaskId() + "," + similarPaper2.getTaskId());
						similarResult.setTaskNo(similarPaper1.getTaskNo() + "," + similarPaper2.getTaskNo());
						similarResult.setCourseNo(similarPaper1.getCourseNo());
						// 检查同课程、同教材的试卷相似度（具体试题比对）
						int p1_size = similarPaper1.getQuestionList().size();
						int p2_size = similarPaper2.getQuestionList().size();
						List<Question> QuestionList1 = similarPaper1.getQuestionList();
						List<Question> QuestionList2 = similarPaper2.getQuestionList();
						List<SimilarPaperQuestion> similarQuestionList1 = new ArrayList<SimilarPaperQuestion>();
						List<SimilarPaperQuestion> similarQuestionList2 = new ArrayList<SimilarPaperQuestion>();
						for (int m = 0; m < p1_size; m++) {
							for (int k = m + 1; k < p2_size; k++) {
								// 检查试卷下的试题
								Question similarques1 = QuestionList1.get(m);
								Question similarques2 = QuestionList2.get(k);
								
								if (similarques1.getTypeName().equals(similarques2.getTypeName())) {
									if ((similarity = StringSimilarityUtils.getSimilarityWithCosinesByWords(
											getQuestionAllBody(similarques1), getQuestionAllBody(similarques2))
											* 100) > 60) {
										SimilarPaperQuestion similarPaperQuestion1 = new SimilarPaperQuestion();
										SimilarPaperQuestion similarPaperQuestion2 = new SimilarPaperQuestion();
										similarPaperQuestion1.setSimilarQuestionId(
												similarques1.getId().toString());
										similarPaperQuestion1.setSimilarQuestionNo(
												similarques1.getQuestionName());
										similarPaperQuestion1.setSimilarity(String.format("%.2f", similarity));
										//similarPaperQuestion1.setSimilarPaperId(similarPaper1.getId()+","+similarPaper2.getId());
										similarPaperQuestion1.setSimilarPaperNo(similarPaper1.getSimilarPaperNo()+","+similarPaper2.getSimilarPaperNo());
										similarPaperQuestion1.setWhichQuestion("A");
										similarPaperQuestion2.setSimilarQuestionId(
												similarques2.getId().toString());
										similarPaperQuestion2.setSimilarQuestionNo(
												similarques2.getQuestionName());
										similarPaperQuestion2.setSimilarity(String.format("%.2f", similarity));
										//similarPaperQuestion2.setSimilarPaperId(similarPaper1.getId()+","+similarPaper2.getId());
										similarPaperQuestion2.setSimilarPaperNo(similarPaper1.getSimilarPaperNo()+","+similarPaper2.getSimilarPaperNo());
										similarPaperQuestion2.setWhichQuestion("B");
										similarQuestionList1.add(similarPaperQuestion1);
										similarQuestionList2.add(similarPaperQuestion2);
									}
								}
							}
						}
						similarResult.setSimilarPaperQuesList1(similarQuestionList1);
						similarResult.setSimilarPaperQuesList2(similarQuestionList2);
						resultList.add(similarResult);
					}
				}
				
			}
		}
		similarPaperList.removeAll(similarPaperList);
		similarPaperList = null;
		Collections.sort(resultList);
		return resultList;
	}
	
	public String getQuestionAllBody(Question ques){
		String questionBody = "";
		if (ques != null && !StringUtils.isBlank(ques.getBodySummary()) && ques.getId() != 0) {
			questionBody += ques.getBodySummary();
			List<QuestionOption> quesOption = ques.getOptions();
			String option = "";
			if (quesOption != null && quesOption.size() > 0) {
				for (QuestionOption op : quesOption) {
					option += op.getSummary();
				}
			}
			questionBody += option;
		}
		return questionBody;
	}
}
