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.SubjectiveBlockDao;
import cn.com.qmth.stmms.biz.exam.model.SubjectiveBlock;
import cn.com.qmth.stmms.biz.exam.query.SubjectiveBlockSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.MarkStepService;
import cn.com.qmth.stmms.biz.exam.service.SubjectiveBlockCoreService;
import cn.com.qmth.stmms.biz.exam.service.SubjectiveBlockService;

@Service("subjectiveBlockService")
public class SubjectiveBlockServiceImpl extends BaseQueryService<SubjectiveBlock> implements SubjectiveBlockService {

    @Autowired
    private MarkStepService markStepService;

    @Autowired
    private SubjectiveBlockDao subjectiveBlockDao;

    @Autowired
    private SubjectiveBlockCoreService subjectBlockCoreService;

    @Transactional
    public SubjectiveBlock saveBlock(SubjectiveBlock block) {
        if (block.getId() != null && block.getId() > 0) {
            return subjectBlockCoreService.saveBlock(block);
        } else {
            SubjectiveBlock previous = findBlockByExamIdAndSubjectCodeAndNumber(block.getExamId(),
                    block.getSubjectCode(), block.getNumber(), false);
            if (previous != null) {
                block.setId(previous.getId());
            }
            return subjectBlockCoreService.saveBlock(block);
        }
    }

    @Transactional
    public void deleteBlockById(int blockId) {
        subjectBlockCoreService.deleteBlockById(blockId);
    }

    @Transactional
    public void deleteBlockByExamIdAndSubjectCode(int examId, String subjectCode) {
        List<SubjectiveBlock> list = findBlockByExamIdAndSubjectCode(examId, subjectCode);
        if (list != null) {
            for (SubjectiveBlock block : list) {
                deleteBlockById(block.getId());
            }
        }
    }

    public long countBlockByExamIdAndSubjectCode(int examId, String subjectCode) {
        return subjectiveBlockDao.countByExamIdAndSubjectCode(examId, subjectCode);
    }

    public long countSubjectByExamId(int examId) {
        return subjectiveBlockDao.countSubjectByExamId(examId);
    }

    public List<SubjectiveBlock> findBlockByExamIdAndSubjectCode(int examId, String subjectCode) {
        return subjectiveBlockDao.findByExamIdAndSubjectCode(examId, subjectCode);
    }

    public List<SubjectiveBlock> findBlockByExamIdAndSubjectCode(int examId, String subjectCode, boolean withStep) {
        List<SubjectiveBlock> list = subjectiveBlockDao.findByExamIdAndSubjectCode(examId, subjectCode);
        if (list != null && withStep) {
            for (SubjectiveBlock subjectiveBlock : list) {
                subjectiveBlock.setMarkStepList(markStepService.findByBlockId(subjectiveBlock.getId(), true));
            }
        }
        return list;
    }

    public SubjectiveBlock findBlockByExamIdAndSubjectCodeAndNumber(int examId, String subjectCode, int number,
            boolean withStep) {
        SubjectiveBlock block = null;
        List<SubjectiveBlock> list = subjectiveBlockDao
                .findByExamIdAndSubjectCodeAndNumber(examId, subjectCode, number);
        if (list != null && list.size() > 0) {
            block = list.get(0);
            if (withStep) {
                block.setMarkStepList(markStepService.findByBlockId(block.getId(), true));
            }
        }
        return block;
    }

    public List<SubjectiveBlock> findBlockByExamIdAndMultiSubjectCode(int examId, String subjectCodes) {
        String[] codeList = StringUtils.split(subjectCodes, ",");
        List<SubjectiveBlock> list = new LinkedList<SubjectiveBlock>();
        if (codeList != null && codeList.length > 0) {
            for (String code : codeList) {
                List<SubjectiveBlock> result = findBlockByExamIdAndSubjectCode(examId, code);
                if (result != null) {
                    list.addAll(result);
                }
            }
        }
        return list;
    }

    public List<SubjectiveBlock> findBlockByExamId(int examId) {
        return subjectiveBlockDao.findByExamId(examId);
    }

    public SubjectiveBlock findBlockById(int blockId) {
        return subjectBlockCoreService.findBlockById(blockId);
    }

    public SubjectiveBlock findBlockById(int blockId, boolean withStep) {
        SubjectiveBlock block = subjectBlockCoreService.findBlockById(blockId);
        if (block != null && withStep) {
            block.setMarkStepList(markStepService.findByBlockId(block.getId(), true));
        }
        return block;
    }

    public SubjectiveBlockSearchQuery findByQuery(final SubjectiveBlockSearchQuery query) {
        checkQuery(query);
        Page<SubjectiveBlock> result = subjectiveBlockDao.findAll(new Specification<SubjectiveBlock>() {

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

}
