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

import java.util.Date;
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.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.com.qmth.stmms.biz.exam.model.Exam;
import cn.com.qmth.stmms.biz.exam.service.ExamService;
import cn.com.qmth.stmms.biz.user.dao.UserDao;
import cn.com.qmth.stmms.biz.user.model.User;
import cn.com.qmth.stmms.biz.user.service.UserService;
import cn.com.qmth.stmms.biz.user.service.query.UserSearchQuery;
import cn.com.qmth.stmms.common.enums.Role;
import cn.com.qmth.stmms.common.enums.UserType;

/**
 * 用户Service
 * 
 * @author LS
 * 
 */
@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
    
    @Autowired
    private ExamService examService;

    @Override
    public User findByLoginName(String loginName) {
        List<User> list = userDao.findByLoginName(loginName);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }
    @Override
    public User findByLoginNameAndStatus(String loginName) {
        List<User> list = userDao.findByLoginNameAndStatus(loginName,1);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }

    @Override
    public List<User> findByLoginNameAndPassword(String loginName, String password) {
        return userDao.findByLoginNameAndPassword(loginName, password);
    }

    public List<User> findBySchoolIdAndRole(int schoolId, Role role) {
        if (role != null) {
            return userDao.findBySchoolIdAndRoleNamesContaining(schoolId, role.getName());
        } else {
            return userDao.findBySchoolId(schoolId);
        }
    }

    public User findById(Integer id) {
        return userDao.findOne(id);
    }

    public User findSchoolAdmin(int schoolId) {
        UserSearchQuery query = new UserSearchQuery();
        query.setSchoolId(schoolId);
        query.addIncludeRole(Role.SCHOOL_ADMIN);
        query.setPageNumber(1);
        query.setPageSize(1);
        query = searchByQuery(query);
        if (query.getCurrentCount() > 0) {
            return query.getResult().get(0);
        } else {
            return null;
        }
    }

    public UserSearchQuery searchByQuery(final UserSearchQuery query) {
        if (query.getPageNumber() < 1) {
            query.setPageNumber(1);
        }
        if (query.getPageSize() < 1) {
            query.setPageSize(10);
        }

        Page<User> result = userDao.findAll(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<Predicate>();
                if (query.getSchoolId() > 0) {
                    predicates.add(cb.equal(root.get("schoolId"), query.getSchoolId()));
                }
                if (query.getType() != null) {
                    predicates.add(cb.equal(root.get("type"), query.getType().getValue()));
                }
                if (StringUtils.isNotBlank(query.getLoginName())) {
                    predicates.add(cb.like(root.get("loginName").as(String.class), query.getLoginName() + "%"));
                }
                if (StringUtils.isNotBlank(query.getName())) {
                    predicates.add(cb.like(root.get("name").as(String.class), query.getName() + "%"));
                }
                if (query.getIncludeRoles() != null && query.getIncludeRoles().size() > 0) {
                    for (Role role : query.getIncludeRoles()) {
                        predicates.add(cb.like(root.get("roleNames").as(String.class), "%" + role.getName() + "%"));
                    }
                }
                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                        .size()]));
            }
        }, query);
        if (result != null) {
            query.setTotalCount(result.getTotalElements());
            query.setTotalPage(result.getTotalPages());
            query.setResult(result.getContent());
            query.setCurrentCount(result.getNumberOfElements());
        } else {
            query.setTotalCount(0);
            query.setTotalPage(0);
            query.setCurrentCount(0);
        }
        return query;
    }

    @Transactional
    public User save(User user) {
        if (user.getId() != null && user.getId() > 0) {
            user.setUpdatedTime(new Date());
        } else {
            user.setCreatedTime(new Date());
        }
        return userDao.save(user);
    }

    @Transactional
    public void deleteById(int id) {
        userDao.delete(id);
    }

    @Transactional
    public void delete(User user) {
        if (user != null) {
            userDao.delete(user);
        }
    }

    @Transactional
	@Override
	public void deleteSubjectViewerByExamId(Integer examId) {
    	Exam exam = examService.findById(examId);
    	UserSearchQuery query = new UserSearchQuery();
    	query.setSchoolId(exam.getSchoolId());
    	query.setType(UserType.VIEWER);
        query.addIncludeRole(Role.SUBJECT_VIEWER);
        query.setLoginName(examId+"-");
        query = this.searchByQuery(query);
        if (query.getCurrentCount() > 0) {
        	userDao.delete(query.getResult());
        }
	}

	@Override
	public User findSchoolViewer(int schoolId) {
        UserSearchQuery query = new UserSearchQuery();
        query.setSchoolId(schoolId);
        query.addIncludeRole(Role.SCHOOL_VIEWER);
        query.setType(UserType.SCHOOLVIEWER);
        query.setPageNumber(1);
        query.setPageSize(1);
        query = searchByQuery(query);
        if (query.getCurrentCount() > 0) {
            return query.getResult().get(0);
        } else {
            return null;
        }
	}
}
