package cn.com.qmth.stmms.biz.exam.service.impl;

import java.util.LinkedList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.com.qmth.stmms.biz.common.BaseQueryService;
import cn.com.qmth.stmms.biz.exam.dao.ExamQuestionDao;
import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
import cn.com.qmth.stmms.biz.exam.model.QuestionPK;
import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
import cn.com.qmth.stmms.biz.exam.service.query.ExamQuestionSearchQuery;

@Service
public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> implements ExamQuestionService {

    @Autowired
    private ExamQuestionDao questionDao;

    @Transactional
    @Override
    public ExamQuestion save(ExamQuestion question) {
        return questionDao.save(question);
    }

    @Transactional
    public void batchSave(List<ExamQuestion> list) {
        for (ExamQuestion question : list) {
            questionDao.save(question);
        }
    }

    @Transactional
    @Override
    public void deleteByExam(int examId) {
        questionDao.deleteByExamId(examId);
    }

    @Transactional
    @Override
    public void deleteByExamAndSubject(int examId, String subjectCode) {
        questionDao.deleteByExamIdAndSubjectCode(examId, subjectCode);
    }

    @Transactional
    @Override
    public void deleteByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective) {
        questionDao.deleteByExamIdAndSubjectCodeAndObjective(examId, subjectCode, objective);
    }

    @Transactional
    @Override
    public void deleteByExamIdAndSubjectCodeAndObjectiveAndMainNumber(int examId, String subjectCode, boolean objective,
            int mainNumber) {
        questionDao.deleteByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective, mainNumber);
    }

    @Override
    public ExamQuestion findOne(int examId, String subjectCode, boolean objective, int mainNumber, int subNumber) {
        QuestionPK pk = new QuestionPK();
        pk.setExamId(examId);
        pk.setSubjectCode(subjectCode);
        pk.setMainNumber(mainNumber);
        pk.setSubNumber(subNumber);
        pk.setObjective(objective);
        return questionDao.findOne(pk);
    }

    @Override
    public List<ExamQuestion> findByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective) {
        return questionDao.findByExamIdAndSubjectCodeAndObjective(examId, subjectCode, objective);
    }

    @Override
    public List<ExamQuestion> findByExamAndSubjectAndObjectiveAndMainNumber(int examId, String subjectCode,
            boolean objective, int mainNumber) {
        return questionDao.findByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective,
                mainNumber);
    }

    @Override
    public long countByExamAndSubject(int examId, String subjectCode) {
        return questionDao.countByExamIdAndSubjectCode(examId, subjectCode);
    }

    @Override
    public long countByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective) {
        return questionDao.countByExamIdAndSubjectCodeAndObjective(examId, subjectCode, objective);
    }

    @Override
    public ExamQuestionSearchQuery findByQuery(ExamQuestionSearchQuery query) {
        checkQuery(query);
        Page<ExamQuestion> result = questionDao.findAll(buildSpecification(query), query);
        fillResult(result, query);
        return query;
    }

    @Override
    public long countByQuery(ExamQuestionSearchQuery query) {
        return questionDao.count(buildSpecification(query));
    }

    private Specification<ExamQuestion> buildSpecification(final ExamQuestionSearchQuery query) {
        return new Specification<ExamQuestion>() {

            @Override
            public Predicate toPredicate(Root<ExamQuestion> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {

                List<Predicate> predicates = new LinkedList<Predicate>();
                if (query.getExamId() > 0) {
                    predicates.add(cb.equal(root.get("pk").get("examId"), query.getExamId()));
                }
                if (StringUtils.isNotEmpty(query.getSubjectCode())) {
                    predicates.add(cb.equal(root.get("pk").get("subjectCode"), query.getSubjectCode()));
                }
                if (query.getObjective() != null) {
                    predicates.add(cb.equal(root.get("pk").get("objective"), query.getObjective()));
                }
                if (query.getTotalCountGt() != null) {
                    predicates.add(cb.gt(root.get("totalCount").as(Integer.class), query.getTotalCountGt()));
                }
                if (query.getTotalScoreGt() != null) {
                    predicates.add(cb.gt(root.get("totalScore").as(Double.class), query.getTotalScoreGt()));
                }
                if (query.getZeroRateGt() != null) {
                    predicates.add(cb.ge(root.get("zeroCount").as(Integer.class),
                            cb.prod(root.get("totalCount").as(Integer.class), query.getZeroRateGt())));
                }
                return predicates.isEmpty() ? cb.conjunction()
                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }

    @Override
    public double scoreByExamIdAndSubjectCode(int examId, String subjectCode) {
        return questionDao.scoreByExamIdAndSubjectCode(examId, subjectCode);

    }

    @Override
    public double scoreByExamIdAndSubjectCodeAndObjective(int examId, String subjectCode, boolean objective) {
        return questionDao.scoreByExamIdAndSubjectCodeAndObjective(examId, subjectCode, objective);
    }

    @Override
    public double scoreByExamIdAndSubjectCodeAndMainNumberAndObjective(int examId, String subjectCode, int mainNumber,
            boolean objective) {
        return questionDao.scoreByExamIdAndSubjectCodeAndMainNumberAndObjective(examId, subjectCode, mainNumber,
                objective);
    }
}
