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

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.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
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.ExamDao;
import cn.com.qmth.stmms.biz.exam.model.Exam;
import cn.com.qmth.stmms.biz.exam.query.ExamSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ExamService;
import cn.com.qmth.stmms.common.enums.ExamStatus;

@Service
public class ExamServiceImpl extends BaseQueryService<Exam> implements ExamService {

    @Autowired
    private ExamDao examDao;

    @Transactional
    // @CachePut(value = "exam_cache", key = "#exam.id", condition =
    // "#exam!=null && #exam.id!=null")
    public Exam save(Exam exam) {
        Integer id = exam.getId();
        if (id != null) {
            exam.setUpdateTime(new Date());
        } else {
            exam.setCreateTime(new Date());
        }
        return examDao.save(exam);
    }

    // @Cacheable(value = "exam_cache", key = "#id", condition = "#id!=null")
    public Exam findById(Integer id) {
        return examDao.findOne(id);
    }

    @Transactional
    // @CacheEvict(value = "exam_cache", beforeInvocation = true, allEntries =
    // true)
    public void updateStatus(int id, ExamStatus status) {
        examDao.updateStatus(id, status);
    }

    @Transactional
    // @CacheEvict(value = "exam_cache", beforeInvocation = true, allEntries =
    // true)
    public void deleteById(Integer id) {
        examDao.delete(id);
    }

    @Override
    // @CacheEvict(value = "exam_cache", beforeInvocation = true, allEntries =
    // true)
    public void delete(Exam exam) {
        examDao.delete(exam);
    }

    @Override
    public ExamSearchQuery findByQuery(final ExamSearchQuery query) {
        checkQuery(query);
        if (query.getOrderByCreateTimeDesc() != null) {
            query.setSort(new Sort(query.getOrderByCreateTimeDesc() ? Direction.DESC : Direction.ASC, "createTime"));
        } else if (query.getOrderByIdDesc() != null) {
            query.setSort(new Sort(query.getOrderByIdDesc() ? Direction.DESC : Direction.ASC, "id"));
        }

        Page<Exam> result = examDao.findAll(new Specification<Exam>() {

            @Override
            public Predicate toPredicate(Root<Exam> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<Predicate>();

                if (query.getSchoolId() != null) {
                    predicates.add(cb.equal(root.get("schoolId"), query.getSchoolId()));
                }
                if (query.getCreatorId() != null) {
                    predicates.add(cb.equal(root.get("creatorId"), query.getCreatorId()));
                }
                if (StringUtils.isNotBlank(query.getName())) {
                    predicates.add(cb.like(root.get("name").as(String.class), query.getName() + "%"));
                }

                if (query.getStatusSet() != null && query.getStatusSet().size() > 0) {
                    List<Predicate> statusPredicates = new LinkedList<Predicate>();
                    for (ExamStatus status : query.getStatusSet()) {
                        statusPredicates.add(cb.equal(root.get("status"), status));
                    }
                    if (!statusPredicates.isEmpty()) {
                        predicates.add(cb.or(statusPredicates.toArray(new Predicate[statusPredicates.size()])));
                    }
                }

                if (query.getIds() != null && query.getIds().size() > 0) {
                    List<Predicate> idsPredicates = new LinkedList<Predicate>();
                    for (Integer id : query.getIds()) {
                        idsPredicates.add(cb.equal(root.get("id"), id));
                    }
                    if (!idsPredicates.isEmpty()) {
                        predicates.add(cb.or(idsPredicates.toArray(new Predicate[idsPredicates.size()])));
                    }
                }

                return predicates.isEmpty() ? cb.conjunction()
                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        }, query);
        fillResult(result, query);
        return query;
    }

    @Override
    public List<Exam> findByStatus(ExamStatus status) {
        return examDao.findByStatus(status);
    }

    @Override
    public List<Exam> findByCreatorAndStatus(Integer id, ExamStatus status) {
        return examDao.findByCreatorAndStatus(id, status);
    }

    @Override
    public List<Exam> findBySchoolId(Integer schoolId) {
        return examDao.findBySchoolIdOrderByIdDesc(schoolId);
    }

}
