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.FormallyLibraryDao;
import cn.com.qmth.stmms.biz.distributpaper.dao.StandardLibraryDao;
import cn.com.qmth.stmms.biz.distributpaper.model.FormallyLibrary;
import cn.com.qmth.stmms.biz.distributpaper.model.StandardLibrary;
import cn.com.qmth.stmms.biz.distributpaper.service.StandardLibraryService;
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.StandardLibrarySearchQuery;
import cn.com.qmth.stmms.common.enums.LibraryStatus;

@Service
public class StandardLibraryServiceImpl implements StandardLibraryService {

    @Autowired
    private StandardLibraryDao standardLibraryDao;

    @Autowired
    private FormallyLibraryDao formallyLibraryDao;

    @Autowired
    private SubjectiveBlockService subjectiveBlockService;

    @Transactional
    public StandardLibrary save(StandardLibrary standardLibrary) {
        return standardLibraryDao.save(standardLibrary);
    }

    public StandardLibrary findById(Integer id) {
        StandardLibrary standardLibrary = standardLibraryDao.findOne(id);
        return buildStandardLibrary(standardLibrary);
    }

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

    @Transactional
    public void delete(StandardLibrary standardLibrary) {
        standardLibraryDao.delete(standardLibrary);
    }

    public List<StandardLibrary> findByExamIdAndBlockId(Integer examId, Integer blockId) {
        List<StandardLibrary> list = standardLibraryDao.findByExamIdAndBlockId(examId, blockId);
        for (StandardLibrary standardLibrary : list) {
            buildStandardLibrary(standardLibrary);
        }
        return list;
    }

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

    @Transactional
    public StandardLibrary incrGetCount(Integer id) {
        standardLibraryDao.incrGetCount(id);
        return findById(id);
    }

    @Override
    public StandardLibrarySearchQuery findByQuery(final StandardLibrarySearchQuery query) {
        Page<StandardLibrary> result = standardLibraryDao.findAll(new Specification<StandardLibrary>() {

            @Override
            public Predicate toPredicate(Root<StandardLibrary> 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 (StandardLibrary standardLibrary : result) {
            buildStandardLibrary(standardLibrary);
        }
        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(count, size);

        for (int i : random) {
            FormallyLibrary formally = libList.get(i);
            StandardLibrary standardLibrary = new StandardLibrary();
            standardLibrary.setBlockId(formally.getBlockId());
            standardLibrary.setExamId(formally.getExamId());
            standardLibrary.setGetCount(0);
            standardLibrary.setPicCount(formally.getPicCount());
            standardLibrary.setCreator(subjectheaderId);
            standardLibrary.setCreateTime(new Date());
            standardLibrary.setCampusCode(formally.getCampusCode());
            standardLibrary.setSecretNo(formally.getSecretNo());
            standardLibrary.setStatus(LibraryStatus.WAITING);
            standardLibrary.setSubjectCode(formally.getSubjectCode());
            standardLibraryDao.save(standardLibrary);
        }
    }

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

        if (count > 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 StandardLibrary buildStandardLibrary(StandardLibrary standardLibrary) {
        if (standardLibrary.getBlockId() != null) {
            SubjectiveBlock subjectiveBlock = subjectiveBlockService.findBlockById(standardLibrary.getBlockId(), true);
            standardLibrary.setSubjectiveBlock(subjectiveBlock);
        }
        return standardLibrary;
    }

    public List<StandardLibrary> findByBlockId(int blockId) {
        return standardLibraryDao.findByBlockId(blockId);
    }
}
