package cn.com.qmth.stmms.biz.subjectheader.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.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.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.query.SubjectHeaderSearchQuery;
import cn.com.qmth.stmms.biz.subjectheader.dao.SubjectHeaderDao;
import cn.com.qmth.stmms.biz.subjectheader.model.SubjectHeader;
import cn.com.qmth.stmms.biz.subjectheader.service.SubjectHeaderService;

@Service
public class SubjectHeaderServiceImpl extends BaseQueryService<SubjectHeader> implements SubjectHeaderService {

    @Autowired
    private SubjectHeaderDao subjectHeaderDao;

    @Override
    public SubjectHeader findById(int id) {
        return subjectHeaderDao.findOne(id);
    }

    @Override
    public List<SubjectHeader> findByExamId(int examId) {
        return subjectHeaderDao.findByExamId(examId);
    }

    @Override
    public List<SubjectHeader> findByExamIdAndSubjectCode(int examId, String subjectCode) {
        return subjectHeaderDao.findByExamIdAndSubjectCode(examId, subjectCode);
    }

    @Override
    public SubjectHeader findByLoginName(String loginName) {
        List<SubjectHeader> list = subjectHeaderDao.findByLoginName(loginName);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }

    @Override
    public long countByExamId(int examId) {
        return subjectHeaderDao.countByExamId(examId);
    }

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

    @Transactional
    @Override
    public SubjectHeader save(SubjectHeader sh) {
        SubjectHeader previous = findByLoginName(sh.getLoginName());
        if (previous == null || (sh.getId() != null && previous.getId().equals(sh.getId()))) {
            return subjectHeaderDao.save(sh);
        } else {
            return null;
        }
    }

    @Transactional
    @Override
    public void delete(SubjectHeader sh) {
        subjectHeaderDao.delete(sh);
    }

    @Transactional
    @Override
    public void deleteById(int id) {
        subjectHeaderDao.delete(id);
    }

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

    @Override
    public SubjectHeaderSearchQuery findByQuery(final SubjectHeaderSearchQuery query) {
        checkQuery(query);
        Page<SubjectHeader> result = subjectHeaderDao.findAll(buildSpecification(query), query);
        fillResult(result, query);
        return query;
    }

    private Specification<SubjectHeader> buildSpecification(final SubjectHeaderSearchQuery query) {
        return new Specification<SubjectHeader>() {

            @Override
            public Predicate toPredicate(Root<SubjectHeader> 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 (StringUtils.isNotBlank(query.getSubjectCode())) {
                    predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
                }
                if (StringUtils.isNotBlank(query.getLoginName())) {
                    predicates.add(cb.equal(root.get("loginName"), query.getLoginName()));
                }
                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }
        };
    }

    @Transactional
    @Override
    public int batchCreate(ExamSubject subject, int count, String password) {
        int result = 0;
        if (subject != null && count > 0) {
            int start = 1;
            SubjectHeader previous = findLastHeader(subject);
            if (previous != null) {
                start = previous.getNumber() + 1;
            }
            int end = start + count - 1;
            for (; start <= end; start++) {
                SubjectHeader header = new SubjectHeader();
                header.setExamId(subject.getExamId());
                header.setSubjectCode(subject.getCode());
                header.setPassword(password);
                header.buildLoginName(start);
                if (save(header) != null) {
                    result++;
                }
            }
        }
        return result;
    }

    private SubjectHeader findLastHeader(ExamSubject subject) {
        SubjectHeaderSearchQuery query = new SubjectHeaderSearchQuery();
        query.setExamId(subject.getExamId());
        query.setSubjectCode(subject.getCode());
        query.setPageNumber(1);
        query.setPageSize(1);
        query.setSort(new Sort(Direction.DESC, "loginName"));
        query = findByQuery(query);
        if (query.getCurrentCount() > 0) {
            return SubjectHeader.parseLoginName(query.getResult().get(0).getLoginName());
        } else {
            return null;
        }
    }

}
