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.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.ObjectiveBlockDao;
import cn.com.qmth.stmms.biz.exam.dao.ObjectiveQuestionDao;
import cn.com.qmth.stmms.biz.exam.model.ObjectiveBlock;
import cn.com.qmth.stmms.biz.exam.model.ObjectiveQuestion;
import cn.com.qmth.stmms.biz.exam.query.ObjectiveBlockSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.ObjectiveBlockService;

@Service
public class ObjectiveBlockServiceImpl extends BaseQueryService<ObjectiveBlock> implements ObjectiveBlockService {

    @Autowired
    private ObjectiveBlockDao objectiveBlockDao;

    @Autowired
    private ObjectiveQuestionDao objectiveQuestionDao;

    private Sort NUMBER_SORT = new Sort(Direction.ASC, "number");

    @Override
    public List<ObjectiveBlock> findBlockByExamIdAndSubjectCode(int examId, String subjectCode, boolean withQuestion) {
        List<ObjectiveBlock> list = objectiveBlockDao.findByExamIdAndSubjectCode(examId, subjectCode, NUMBER_SORT);
        if (withQuestion && list != null) {
            for (ObjectiveBlock block : list) {
                block.setQuestionList(findQuestionByBlockId(block.getId()));
            }
        }
        return list;
    }

    @Override
    public ObjectiveBlock findBlockById(int blockId, boolean withQuestion) {
        ObjectiveBlock block = objectiveBlockDao.findOne(blockId);
        if (block != null && withQuestion) {
            block.setQuestionList(objectiveQuestionDao.findByBlockId(blockId));
        }
        return block;
    }

    public List<ObjectiveQuestion> findQuestionByBlockId(int blockId) {
        return objectiveQuestionDao.findByBlockId(blockId);
    }

    @Override
    public List<ObjectiveBlock> findBlockByExamId(int examId) {
        return objectiveBlockDao.findByExamId(examId);
    }

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

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

    @Transactional
    private ObjectiveBlock saveBlockAndQuestion(ObjectiveBlock block) {
        ObjectiveBlock item = objectiveBlockDao.save(block);
        if (block.getQuestionList() != null) {
            objectiveQuestionDao.deleteByBlockId(item.getId());
            // int number = 0;
            for (ObjectiveQuestion question : block.getQuestionList()) {
                // question.setNumber(++number);
                question.setBlockId(item.getId());
                objectiveQuestionDao.save(question);
            }
        }
        return item;
    }

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

    @Override
    public List<ObjectiveBlock> findBlockByExamIdAndSubjectCode(int examId, String subjectCode) {
        return objectiveBlockDao.findByExamIdAndSubjectCode(examId, subjectCode, NUMBER_SORT);
    }

    @Override
    public ObjectiveBlock findBlockByExamIdAndSubjectCodeAndNumber(int examId, String subjectCode, int number) {
        List<ObjectiveBlock> list = objectiveBlockDao.findByExamIdAndSubjectCodeAndNumber(examId, subjectCode, number);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }

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

    @Transactional
    public void deleteBlock(ObjectiveBlock objectiveBlock) {
        objectiveQuestionDao.deleteByBlockId(objectiveBlock.getId());
        objectiveBlockDao.delete(objectiveBlock);
    }

    public ObjectiveBlockSearchQuery findByQuery(final ObjectiveBlockSearchQuery query) {
        checkQuery(query);
        Page<ObjectiveBlock> result = objectiveBlockDao.findAll(new Specification<ObjectiveBlock>() {

            @Override
            public Predicate toPredicate(Root<ObjectiveBlock> 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;
    }

}
