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

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.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.distributpaper.dao.CaseLibraryDao;
import cn.com.qmth.stmms.biz.distributpaper.dao.FormallyLibraryDao;
import cn.com.qmth.stmms.biz.distributpaper.model.CaseLibrary;
import cn.com.qmth.stmms.biz.distributpaper.model.FormallyLibrary;
import cn.com.qmth.stmms.biz.distributpaper.service.CaseLibraryService;
import cn.com.qmth.stmms.biz.exam.model.SubjectiveBlock;
import cn.com.qmth.stmms.biz.exam.service.SubjectiveBlockService;
import cn.com.qmth.stmms.biz.subjectheader.query.CaseLibrarySearchQuery;
import cn.com.qmth.stmms.common.enums.LibraryStatus;

@Service
public class CaseLibraryServiceImpl implements CaseLibraryService {

    @Autowired
    private CaseLibraryDao caseLibraryDao;

    @Autowired
    private FormallyLibraryDao formallyLibraryDao;

    @Autowired
    private SubjectiveBlockService subjectiveBlockService;

    @Transactional
    public CaseLibrary save(CaseLibrary caseLibrary) {
        return caseLibraryDao.save(caseLibrary);
    }

    public CaseLibrary findById(Integer id) {
        CaseLibrary caseLibrary = caseLibraryDao.findOne(id);
        return buildCaseLibrary(caseLibrary);
    }

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

    @Transactional
    public void delete(CaseLibrary caseLibrary) {
        caseLibraryDao.delete(caseLibrary);
    }

    public List<CaseLibrary> findByExamIdAndBlockId(Integer examId, Integer blockId) {
        List<CaseLibrary> list = caseLibraryDao.findByExamIdAndBlockId(examId, blockId);
        for (CaseLibrary caseLibrary : list) {
            buildCaseLibrary(caseLibrary);
        }
        return list;
    }

    public CaseLibrary findByBlockIdAndSecretNo(Integer blockId, Integer secretNo) {
        List<CaseLibrary> list = caseLibraryDao.findByBlockIdAndSecretNo(blockId, secretNo);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }

    @Transactional
    public CaseLibrary incrGetCount(Integer id) {
        caseLibraryDao.incrGetCount(id);
        return findById(id);
    }

    @Override
    public CaseLibrarySearchQuery findByQuery(final CaseLibrarySearchQuery query) {
        Page<CaseLibrary> result = caseLibraryDao.findAll(new Specification<CaseLibrary>() {

            @Override
            public Predicate toPredicate(Root<CaseLibrary> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<Predicate>();
                // EntityType<CaseLibrary> ci_ = root.getModel();

                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()));
                }
                if (query.getBlockId() != null) {
                    predicates.add(cb.equal(root.get("blockId"), query.getBlockId()));
                }

                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }
        }, query);
        for (CaseLibrary caseLibrary : result) {
            buildCaseLibrary(caseLibrary);
        }
        query.setResult(result.getContent());
        query.setTotalCount(result.getTotalElements());
        query.setTotalPage(result.getTotalPages());
        return query;
    }

    @Override
    @Transactional
    public void example(int examId, String subjectCode, int blockId, int count, int subjectheaderId) {
        List<FormallyLibrary> libList = formallyLibraryDao.findByExamIdAndSubjectCodeAndBlockId(examId, subjectCode,
                blockId);
        int size = libList.size();
        int[] random = random(size);

        for (int i : random) {
            FormallyLibrary formally = libList.get(i);
            CaseLibrary caseLib = new CaseLibrary();
            caseLib.setBlockId(formally.getBlockId());
            caseLib.setExamId(formally.getExamId());
            caseLib.setGetCount(0);
            caseLib.setPicCount(formally.getPicCount());
            caseLib.setSampler(subjectheaderId);
            caseLib.setSampleTime(new Date());
            caseLib.setCampusCode(formally.getCampusCode());
            caseLib.setSecretNo(formally.getSecretNo());
            caseLib.setStatus(LibraryStatus.WAITING);
            caseLib.setSubjectCode(formally.getSubjectCode());
            caseLibraryDao.save(caseLib);
        }
    }

    private int[] random(int size) {
        int random[];
        if (size < 10) {
            random = new int[size];
        } else {
            random = new int[10];
        }
        // 全部初始化为-1
        for (int i = 0; i < random.length; i++) {
            random[i] = -1;
        }

        if (size > 0) {
            Random rand = new Random();
            int num = 0;
            for (int i = 0; i < random.length; i++) {
                do {
                    num = rand.nextInt(size);
                } while (!getDistinctNum(num, random));
                random[i] = num;

            }
        }
        return random;
    }

    private boolean getDistinctNum(int num, int[] random) {
        boolean result = false;
        for (int i = 0; i < random.length; i++) {
            if (num == random[i]) {
                result = false;
                break;
            } else {
                result = true;
            }
        }
        return result;
    }

    private CaseLibrary buildCaseLibrary(CaseLibrary caseLibrary) {
        if (caseLibrary.getBlockId() != null) {
            SubjectiveBlock subjectiveBlock = subjectiveBlockService.findBlockById(caseLibrary.getBlockId(), true);
            caseLibrary.setSubjectiveBlock(subjectiveBlock);
        }
        return caseLibrary;
    }

    public List<CaseLibrary> findByBlockId(int blockId) {
        return caseLibraryDao.findByBlockId(blockId);
    }
}
