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

import java.util.ArrayList;
import java.util.Date;
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.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.distributpaper.dao.TryLibraryDao;
import cn.com.qmth.stmms.biz.distributpaper.model.TryLibrary;
import cn.com.qmth.stmms.biz.distributpaper.query.TryLibrarySearchQuery;
import cn.com.qmth.stmms.biz.distributpaper.service.TryLibraryService;
import cn.com.qmth.stmms.biz.exam.model.SubjectiveBlock;
import cn.com.qmth.stmms.biz.exam.service.SubjectiveBlockService;
import cn.com.qmth.stmms.common.enums.ClassType;
import cn.com.qmth.stmms.common.enums.LibraryStatus;

@Service
public class TryLibraryServiceImpl extends BaseQueryService<TryLibrary> implements TryLibraryService {

    @Autowired
    private TryLibraryDao tryLibraryDao;

    @Autowired
    private SubjectiveBlockService subjectiveBlockService;

    @Transactional
    public TryLibrary save(TryLibrary tryLibrary) {
        return tryLibraryDao.save(tryLibrary);
    }

    public TryLibrary findById(Integer id) {
        return tryLibraryDao.findOne(id);
    }

    @Transactional
    public void deleteById(Integer id) {
        tryLibraryDao.delete(id);
    }

    @Transactional
    public void delete(TryLibrary tryLibrary) {
        tryLibraryDao.delete(tryLibrary);
    }

    public List<TryLibrary> findByExamIdAndBlockId(Integer examId, Integer blockId) {
        return tryLibraryDao.findByExamIdAndBlockId(examId, blockId);
    }

    public List<TryLibrary> findByBlockIdAndSecretNo(Integer blockId, Integer secretNo) {
        return tryLibraryDao.findByBlockIdAndSecretNo(blockId, secretNo);
    }

    public TryLibrarySearchQuery findByQuery(final TryLibrarySearchQuery query) {
        checkQuery(query);

        Page<TryLibrary> result = tryLibraryDao.findAll(new Specification<TryLibrary>() {

            @Override
            public Predicate toPredicate(Root<TryLibrary> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<Predicate>();
                if (query.getExamId() > 0) {
                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
                }
                if (query.getSubjectId() > 0) {
                    predicates.add(cb.equal(root.get("subjectId"), query.getSubjectId()));
                }
                if (query.getClassType() != null) {
                    predicates.add(cb.equal(root.get("classType").as(ClassType.class), query.getClassType()));
                }
                if (query.getBlockId() > 0) {
                    predicates.add(cb.equal(root.get("blockId"), query.getBlockId()));
                }
                if (query.getSecretNo() > 0) {
                    predicates.add(cb.equal(root.get("secretNo"), query.getSecretNo()));
                }
                if (query.getGetter() > 0) {
                    predicates.add(cb.equal(root.get("getter"), query.getGetter()));
                }
                if (query.getStatus() != null) {
                    predicates.add(cb.equal(root.get("status").as(LibraryStatus.class), query.getStatus()));
                }
                if (query.getMaxGetTime() != null) {
                    predicates.add(cb.lessThanOrEqualTo(root.get("getTime").as(Date.class), query.getMaxGetTime()));
                }
                if (query.getMinGetTime() != null) {
                    predicates.add(cb.greaterThan(root.get("getTime").as(Date.class), query.getMinGetTime()));
                }
                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }

        }, query);
        fillResult(result, query);
        return query;
    }

    @Override
    public List<TryLibrary> randomCheck(int examId, String subjectCode) {
        List<SubjectiveBlock> blockList = subjectiveBlockService.findBlockByExamIdAndSubjectCode(examId,subjectCode);
        List<TryLibrary> list = new ArrayList<TryLibrary>();
        for (SubjectiveBlock block : blockList) {
            List<TryLibrary> tryList = tryLibraryDao.findByExamIdAndBlockIdAndStatusAndIsChecked(examId, block.getId(),
                    LibraryStatus.MARKED, false);

            list.addAll(tryList);
        }
        return list;

    }

    public List<TryLibrary> findByExamIdAndBlockIdAndStatus(int examId, int blockId, LibraryStatus status) {
        return tryLibraryDao.findByExamIdAndBlockIdAndStatus(examId, blockId, status);
    }

    public List<TryLibrary> findByExamIdAndBlockIdAndGetterAndStatus(int examId, int blockId, int getter,
            LibraryStatus status) {
        return tryLibraryDao.findByExamIdAndBlockIdAndGetterAndStatus(examId, blockId, getter, status);
    }

    @Override
    public List<TryLibrary> findByExamIdAndSubjectCodeAndBlockIdAndSecretNoAndStatus(int examId,
            String subjectCode, int blockId, int secretNo, LibraryStatus status) {
        return tryLibraryDao.findByExamIdAndSubjectCodeAndBlockIdAndSecretNoAndStatus(examId, subjectCode, blockId, secretNo, status);
    }
}
