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

import java.util.ArrayList;
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.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;

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.model.FormallyHistory;
import cn.com.qmth.stmms.biz.distributpaper.model.FormallyLibrary;
import cn.com.qmth.stmms.biz.distributpaper.model.TryHistory;
import cn.com.qmth.stmms.biz.distributpaper.model.TryLibrary;
import cn.com.qmth.stmms.biz.distributpaper.service.FormallyHistoryService;
import cn.com.qmth.stmms.biz.distributpaper.service.FormallyLibraryService;
import cn.com.qmth.stmms.biz.distributpaper.service.TryHistoryService;
import cn.com.qmth.stmms.biz.distributpaper.service.TryLibraryService;
import cn.com.qmth.stmms.biz.exam.model.Marker;
import cn.com.qmth.stmms.biz.exam.model.SubjectiveBlock;
import cn.com.qmth.stmms.biz.exam.service.MarkerService;
import cn.com.qmth.stmms.biz.exam.service.SubjectiveBlockService;
import cn.com.qmth.stmms.biz.subjectheader.dao.RandomLibraryDao;
import cn.com.qmth.stmms.biz.subjectheader.model.RandomLibrary;
import cn.com.qmth.stmms.biz.subjectheader.query.RandomLibrarySearchQuery;
import cn.com.qmth.stmms.biz.subjectheader.service.RandomLibraryService;
import cn.com.qmth.stmms.common.enums.LibraryStatus;
import cn.com.qmth.stmms.common.enums.LibraryType;
import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;

@Service
public class RandomLibraryServiceImpl implements RandomLibraryService {

    @Autowired
    private RandomLibraryDao randomLibraryDao;

    @Autowired
    private FormallyLibraryService formallyLibraryService;

    @Autowired
    private FormallyHistoryService formallyHistoryService;

    @Autowired
    private TryLibraryService tryLibraryService;

    @Autowired
    private TryHistoryService tryHistoryService;

    @Autowired
    private MarkerService markerService;

    @Autowired
    private SubjectiveBlockService subjectiveBlockService;

    @Transactional
    public RandomLibrary save(RandomLibrary randomLibrary) {
        randomLibraryDao.save(randomLibrary);
        return buildRandomLibrary(randomLibrary);
    }

    public RandomLibrary findById(Integer id) {
        RandomLibrary randomLibrary = randomLibraryDao.findOne(id);
        return buildRandomLibrary(randomLibrary);
    }

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

    @Transactional
    public void delete(RandomLibrary randomLibrary) {
        randomLibraryDao.delete(randomLibrary);
    }

    public RandomLibrarySearchQuery findByQuery(final RandomLibrarySearchQuery query) {
        Page<RandomLibrary> result = randomLibraryDao.findAll(new Specification<RandomLibrary>() {

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

                if (query.getSecretNo() != null) {
                    predicates.add(cb.equal(root.get("secretNo"), query.getSecretNo()));
                }
                if (query.getBlockId() != null) {
                    predicates.add(cb.equal(root.get("blockId"), query.getBlockId()));
                }
                if (query.getType() != null) {
                    predicates.add(cb.equal(root.get("type").as(LibraryType.class),
                            LibraryType.findByValue(query.getType())));
                }
                if (query.getMarkerId() != null) {
                    predicates.add(cb.equal(root.get("markerId"), query.getMarkerId()));
                }
                if (query.getStatus() != null) {
                    predicates.add(cb.equal(root.get("status"), query.getStatus()));
                }
                // 发放时间处理
                Predicate issueDate;

                if (query.getStartTime() != null && query.getEndTime() != null) {
                    Expression<Date> start = cb.literal(query.getStartTime());
                    Expression<Date> end = cb.literal(query.getEndTime());
                    issueDate = cb.between(root.get(ci_.getSingularAttribute("markTime", Date.class)), start, end);
                    predicates.add(issueDate);
                }

                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }
        }, query);
        for (RandomLibrary randomLibrary : result) {
            buildRandomLibrary(randomLibrary);
        }

        query.setResult(result.getContent());
        query.setTotalCount(result.getTotalElements());
        query.setTotalPage(result.getTotalPages());
        return query;
    }

    @Transactional
    public void randomCheck(Integer examId, String subjectCode, RandomLibrarySearchQuery query) {
        if (query.getType() != null) {
            if (query.getType() == 1) {
                // 试评
                List<TryLibrary> list = new ArrayList<TryLibrary>();
                List<TryLibrary> libList = tryLibraryService.randomCheck(examId, subjectCode);
                if (query.getMarkerId() != null) {
                    for (TryLibrary library : libList) {
                        if (library.getGetter().intValue() == query.getMarkerId().intValue()) {
                            list.add(library);
                        }
                    }
                } else if (query.getStartTime() != null && query.getEndTime() != null) {
                    for (TryLibrary library : libList) {
                        if (library.getGetTime().getTime() >= query.getStartTime().getTime()
                                && library.getGetTime().getTime() <= query.getEndTime().getTime()) {
                            list.add(library);
                        }
                    }
                } else if (query.getBlockId() != null) {
                    for (TryLibrary library : libList) {
                        if (library.getBlockId().intValue() == query.getBlockId().intValue()) {
                            list.add(library);
                        }
                    }
                } else if (query.getSecretNo() != null) {
                    for (TryLibrary library : libList) {
                        if (library.getSecretNo().intValue() == query.getSecretNo().intValue()) {
                            list.add(library);
                        }
                    }
                } else {
                    list.addAll(libList);
                }
                int size = list.size();
                if (size > 0) {
                    int[] random = random(size);
                    for (int i = 0; i < random.length; i++) {
                        TryLibrary lib = list.get(i);
                        RandomLibrary randomLibrary = new RandomLibrary();
                        randomLibrary.setLibraryId(lib.getId());
                        randomLibrary.setBlockId(lib.getBlockId());
                        randomLibrary.setMarkerId(lib.getGetter());
                        randomLibrary.setSecretNo(lib.getSecretNo());
                        randomLibrary.setStatus(LibraryStatus.WAITING);
                        randomLibrary.setType(LibraryType.TRY);
                        randomLibrary.setCheckTime(new Date());
                        randomLibrary.setMarkTime(lib.getGetTime());
                        randomLibraryDao.save(randomLibrary);

                        lib.setChecked(true);
                        tryLibraryService.save(lib);
                    }
                }
            } else {
                // 正评
                List<FormallyLibrary> list = new ArrayList<FormallyLibrary>();
                List<FormallyLibrary> libList = formallyLibraryService.randomCheck(examId, subjectCode);
                if (query.getMarkerId() != null) {
                    for (FormallyLibrary library : libList) {
                        if (library.getGetter().intValue() == query.getMarkerId().intValue()) {
                            list.add(library);
                        }
                    }
                } else if (query.getStartTime() != null && query.getEndTime() != null) {
                    for (FormallyLibrary library : libList) {
                        if (library.getGetTime().getTime() >= query.getStartTime().getTime()
                                && library.getGetTime().getTime() <= query.getEndTime().getTime()) {
                            list.add(library);
                        }
                    }
                } else if (query.getBlockId() != null) {
                    for (FormallyLibrary library : libList) {
                        if (library.getBlockId().intValue() == query.getBlockId().intValue()) {
                            list.add(library);
                        }
                    }
                } else if (query.getSecretNo() != null) {
                    for (FormallyLibrary library : libList) {
                        if (library.getSecretNo().intValue() == query.getSecretNo().intValue()) {
                            list.add(library);
                        }
                    }
                } else {
                    list.addAll(libList);
                }
                int size = list.size();
                if (size > 0) {
                    int[] random = random(size);
                    for (int i = 0; i < random.length; i++) {
                        FormallyLibrary lib = list.get(i);
                        RandomLibrary randomLibrary = new RandomLibrary();
                        randomLibrary.setLibraryId(lib.getId());
                        randomLibrary.setBlockId(lib.getBlockId());
                        randomLibrary.setMarkerId(lib.getGetter());
                        randomLibrary.setSecretNo(lib.getSecretNo());
                        randomLibrary.setStatus(LibraryStatus.WAITING);
                        randomLibrary.setType(LibraryType.FORMALLY);
                        randomLibrary.setCheckTime(new Date());
                        randomLibrary.setMarkTime(lib.getGetTime());
                        randomLibraryDao.save(randomLibrary);

                        lib.setChecked(true);
                        formallyLibraryService.save(lib);
                    }
                }
            }
        }
    }

    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 RandomLibrary buildRandomLibrary(RandomLibrary randomLibrary) {
        if (randomLibrary.getType().getValue() == 1) {
            TryLibrary library = tryLibraryService.findById(randomLibrary.getLibraryId());
            SubjectiveBlock subjectiveBlock = subjectiveBlockService.findBlockById(library.getBlockId(), true);
            randomLibrary.setSubjectiveBlock(subjectiveBlock);

            List<TryHistory> tryHistoryList = tryHistoryService.findByLibraryId(library.getId());
            randomLibrary.setTryHistoryList(tryHistoryList);
            randomLibrary.setPictureConfig(subjectiveBlock.getPictureConfig());
            // randomLibrary.setPictureUrls(PictureUrlBuilder.getSliceUrls(library.getExamId(),
            // library.getCampusCode(),
            // subjectiveBlock.getSubjectCode(), library.getExamNumber(),
            // library.getPicCount()));

        } else {
            FormallyLibrary library = formallyLibraryService.findById(randomLibrary.getLibraryId());
            SubjectiveBlock subjectiveBlock = subjectiveBlockService.findBlockById(library.getBlockId(), true);
            randomLibrary.setSubjectiveBlock(subjectiveBlock);

            List<FormallyHistory> formallyHistoryList = formallyHistoryService.findByLibraryId(library.getId());
            randomLibrary.setFormallyHistoryList(formallyHistoryList);
            randomLibrary.setPictureConfig(subjectiveBlock.getPictureConfig());
            // randomLibrary.setPictureUrls(PictureUrlBuilder.getSliceUrls(library.getExamId(),
            // library.getCampusCode(),
            // subjectiveBlock.getSubjectCode(), library.getExamNumber(),
            // library.getPicCount()));
        }

        Marker marker = markerService.findById(randomLibrary.getMarkerId());
        randomLibrary.setMarker(marker);
        return randomLibrary;
    }
}
