package cn.com.qmth.stmms.biz.mark.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.model.MarkGroup;
import cn.com.qmth.stmms.biz.mark.dao.ArbitrateHistoryDao;
import cn.com.qmth.stmms.biz.mark.model.ArbitrateHistory;
import cn.com.qmth.stmms.biz.mark.query.ArbitrateHistorySearchQuery;
import cn.com.qmth.stmms.biz.mark.service.ArbitrateHistoryService;
import cn.com.qmth.stmms.common.enums.HistoryStatus;

@Service
public class ArbitrateHistoryServiceImpl extends BaseQueryService<ArbitrateHistory> implements ArbitrateHistoryService {

    public static final int UN_SELECTIVE_SCORE = -1;

    @Autowired
    private ArbitrateHistoryDao historyDao;

    @Transactional
    @Override
    public void delete(ArbitrateHistory history) {
        historyDao.delete(history);
    }

    @Transactional
    @Override
    public void deleteByStudent(Integer studentId) {
        historyDao.deleteByStudentId(studentId);
    }

    @Transactional
    @Override
    public void deleteByGroup(MarkGroup group) {
        historyDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                group.getNumber());
    }

    @Transactional
    @Override
    public ArbitrateHistory save(ArbitrateHistory history) {
        return historyDao.save(history);
    }

    @Override
    public ArbitrateHistory findById(Integer id) {
        return historyDao.findOne(id);
    }

    @Override
    public long countByQuery(final ArbitrateHistorySearchQuery query) {
        return historyDao.count(buildSpecification(query));
    }

    @Override
    public ArbitrateHistorySearchQuery findByQuery(final ArbitrateHistorySearchQuery query) {
        checkQuery(query);
        Page<ArbitrateHistory> result = historyDao.findAll(buildSpecification(query), query);
        fillResult(result, query);
        return query;
    }

    private Specification<ArbitrateHistory> buildSpecification(final ArbitrateHistorySearchQuery query) {
        return new Specification<ArbitrateHistory>() {

            @Override
            public Predicate toPredicate(Root<ArbitrateHistory> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<Predicate>();
                if (query.getExamId() != null) {
                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
                }
                if (StringUtils.isNotBlank(query.getSubjectCode())) {
                    predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
                }
                if (query.getGroupNumber() != null) {
                    predicates.add(cb.equal(root.get("groupNumber"), query.getGroupNumber()));
                }
                if (StringUtils.isNotBlank(query.getExamNumber())) {
                    predicates.add(cb.equal(root.get("examNumber"), query.getExamNumber()));
                }
                if (query.getStudentId() != null) {
                    predicates.add(cb.equal(root.get("studentId"), query.getStudentId()));
                }
                if (query.getUserId() != null) {
                    predicates.add(cb.equal(root.get("userId"), query.getUserId()));
                }
                if (query.getStatus() != null) {
                    predicates.add(cb.equal(root.get("status").as(HistoryStatus.class), query.getStatus()));
                }
                if (StringUtils.isNotBlank(query.getSecretNumber())) {
                    predicates.add(cb.equal(root.get("secretNumber"), query.getSecretNumber()));
                }
                if (query.isUnselective()) {
                    predicates.add(cb.equal(root.get("totalScore"), UN_SELECTIVE_SCORE));
                }
                if (query.getStartScroe() != null) {
                    Predicate predicate1 = cb.ge(root.get("totalScore"), query.getStartScroe());
                    predicates.add(predicate1);
                }
                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }
        };
    }

}
