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

import java.sql.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.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.BaseQuery;
import cn.com.qmth.stmms.biz.common.BaseQueryService;
import cn.com.qmth.stmms.biz.exam.dao.MarkerDao;
import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
import cn.com.qmth.stmms.biz.exam.model.Marker;
import cn.com.qmth.stmms.biz.exam.query.MarkerSearchQuery;
import cn.com.qmth.stmms.biz.exam.service.MarkerService;
import cn.com.qmth.stmms.biz.mark.dao.MarkLibraryDao;
import cn.com.qmth.stmms.common.enums.LibraryStatus;

@Service("markerService")
public class MarkerServiceImpl extends BaseQueryService<Marker> implements MarkerService {

    @Autowired
    private MarkerDao markerDao;

    @Autowired
    private MarkLibraryDao libraryDao;

    @Transactional
    @Override
    public Marker save(Marker marker) {
        Marker previous = findByLoginName(marker.getLoginName());
        if (previous == null || (marker.getId() != null && previous.getId().equals(marker.getId()))) {
            return markerDao.save(marker);
        } else {
            return null;
        }
    }

    @Transactional
    @Override
    public void delete(Marker marker) {
        markerDao.delete(marker);
    }

    @Transactional
    @Override
    public void deleteById(Integer markerId) {
        markerDao.delete(markerId);
    }

    @Transactional
    @Override
    public void deleteByExamAndSubject(int examId, String subjectCode) {
        markerDao.deleteByExamIdAndSubjectCode(examId, subjectCode);
    }

    @Transactional
    @Override
    public void deleteByExam(int examId) {
        markerDao.deleteByExamId(examId);
    }

    @Override
    public Marker findById(Integer id) {
        return markerDao.findOne(id);
    }

    @Override
    public Marker findByLoginName(String loginName) {
        List<Marker> list = markerDao.findByLoginName(loginName);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }

    @Override
    public List<Marker> findByExamAndSubject(int examId, String subjectCode) {
        return markerDao.findByExamIdAndSubjectCode(examId, subjectCode);
    }

    @Override
    public long countByExam(int examId) {
        return markerDao.countByExamId(examId);
    }

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

    @Transactional
    @Override
    public int batchCreateCommon(int examId, int count, String password) {
        int result = 0;
        if (count > 0) {
            int start = 1;
            Marker previous = findLastCommonMarker(examId);
            if (previous != null) {
                start = previous.getNumber() + 1;
            }
            int end = start + count - 1;
            for (; start <= end; start++) {
                Marker marker = new Marker();
                marker.setCommon(true);
                marker.setExamId(examId);
                marker.setSubjectCode("");
                if(StringUtils.isEmpty(password)){
                    Random random = new Random();
                    for (int i=0;i<6;i++)
                    {
                        password+=random.nextInt(10);
                    }
                    marker.setPassword(password);
                    password = "";//随机码生产后将密码置空
                }else {
                    marker.setPassword(password);
                }
                marker.setEnable(true);
                marker.buildLoginName(start);
                marker.setName(marker.getLoginName());
                if (save(marker) != null) {
                    result++;
                }
            }
        }
        return result;
    }

    @Transactional
    @Override
    public int batchCreate(ExamSubject subject, int count, String password) {
        int result = 0;
        if (subject != null && count > 0) {
            int start = 1;
            Marker previous = findLastMarker(subject.getExamId(), subject.getCode());
            if (previous != null) {
                start = previous.getNumber() + 1;
            }
            int end = start + count - 1;
            for (; start <= end; start++) {
                Marker marker = new Marker();
                marker.setCommon(false);
                marker.setExamId(subject.getExamId());
                marker.setSubjectCode(subject.getCode());
                if(StringUtils.isEmpty(password)){
                    Random random = new Random();
                    for (int i=0;i<6;i++)
                    {
                        password+=random.nextInt(10);
                    }
                    marker.setPassword(password);
                    password = "";//随机码生产后将密码置空
                }else {
                    marker.setPassword(password);
                }
                marker.setEnable(true);
                marker.buildLoginName(start);
                marker.setName(marker.getLoginName());
                if (save(marker) != null) {
                    result++;
                }
            }
        }
        return result;
    }

    private Marker findLastMarker(int examId, String subjectCode) {
        BaseQuery<Marker> query = new BaseQuery<Marker>();
        query.setPageNumber(1);
        query.setPageSize(1);
        query.setSort(new Sort(Direction.DESC, "id"));
        List<Marker> list = markerDao.findByExamIdAndSubjectCode(examId, subjectCode, query);
        if (list != null && list.size() > 0) {
            return Marker.parseLoginName(list.get(0).getLoginName());
        } else {
            return null;
        }
    }

    private Marker findLastCommonMarker(int examId) {
        BaseQuery<Marker> query = new BaseQuery<Marker>();
        query.setPageNumber(1);
        query.setPageSize(1);
        query.setSort(new Sort(Direction.DESC, "id"));
        List<Marker> list = markerDao.findByExamIdAndCommon(examId, true, query);
        if (list != null && list.size() > 0) {
            return Marker.parseLoginName(list.get(0).getLoginName());
        } else {
            return null;
        }
    }

    @Override
    public List<Marker> getMarkCount(int examId) {
        List<Marker> list = new LinkedList<Marker>();
        List<Object[]> result = libraryDao.countByMarkerAndStatus(examId, LibraryStatus.MARKED);
        if (result != null) {
            for (Object[] array : result) {
                try {
                    Marker marker = findById((int) array[0]);
                    marker.setMarkedCount((long) array[1]);
                    list.add(marker);
                } catch (Exception e) {
                }
            }
        }
        return list;
    }

    @Override
    public MarkerSearchQuery findByQuery(final MarkerSearchQuery query) {
        checkQuery(query);
        Page<Marker> result = markerDao.findAll(buildSpecification(query), query);
        fillResult(result, query);
        return query;
    }

    private Specification<Marker> buildSpecification(final MarkerSearchQuery query) {
        return new Specification<Marker>() {

            @Override
            public Predicate toPredicate(Root<Marker> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<Predicate>();
                if (query.getExamId() > 0) {
                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
                }
                if (StringUtils.isNotBlank(query.getSubjectCode())) {
                    predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
                }
                if (StringUtils.isNotBlank(query.getLoginName())) {
                    predicates.add(cb.equal(root.get("loginName"), query.getLoginName()));
                }
                if (StringUtils.isNotBlank(query.getName())) {
                    predicates.add(cb.equal(root.get("name"), query.getName()));
                }
                cQuery.orderBy(cb.desc(root.get("lastLoginTime").as(Date.class)));
                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }
        };
    }

	@Override
	public List<Marker> findExamAndCommon(int examId, boolean commo) {
        BaseQuery<Marker> query = new BaseQuery<Marker>();
        query.setPageNumber(1);
        query.setPageSize(Integer.MAX_VALUE);
        query.setSort(new Sort(Direction.DESC, "id"));
		return markerDao.findByExamIdAndCommon(examId, commo, query);
	}
	
	@Override
	public Marker findByStudentId(int studentId){
	    return  markerDao.findByStudentId(studentId);
	}

	@Override
    public int batchSave(List<Marker> list){
        markerDao.save(list);
        return  list.size();
    }
    @Override
    public long countByLoginName(String loginName){
        return markerDao.countByLoginName(loginName);
    }

    @Override
    public List<Marker> findCommon(boolean commo) {
        return markerDao.findByCommon(commo);
    }
}
