package com.syzton.sunread.service.exam;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javassist.NotFoundException;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.syzton.sunread.dto.exam.ExamDTO;
import com.syzton.sunread.dto.exam.VerifiedExamDTO;
import com.syzton.sunread.dto.exam.VerifyExamPassDTO;
import com.syzton.sunread.model.book.Review;
import com.syzton.sunread.model.exam.Answer;
import com.syzton.sunread.model.exam.CapacityExamHistory;
import com.syzton.sunread.model.exam.CapacityQuestion;
import com.syzton.sunread.model.exam.CapacityQuestion.CapacityQuestionType;
import com.syzton.sunread.model.exam.Exam;
import com.syzton.sunread.model.exam.Exam.ExamType;
import com.syzton.sunread.model.exam.ObjectiveAnswer;
import com.syzton.sunread.model.exam.ObjectiveQuestion;
import com.syzton.sunread.model.exam.ObjectiveQuestion.QuestionType;
import com.syzton.sunread.model.exam.SpeedQuestion;
import com.syzton.sunread.model.exam.SubjectiveQuestion;
import com.syzton.sunread.model.exam.SubjectiveQuestion.SubjectiveQuestionType;
import com.syzton.sunread.repository.exam.CapacityExamHistoryRepository;
import com.syzton.sunread.repository.exam.CapacityQuestionRepository;
import com.syzton.sunread.repository.exam.ExamRepository;
import com.syzton.sunread.repository.exam.ObjectiveQuestionRepository;
import com.syzton.sunread.repository.exam.SpeedQuestionRepository;
import com.syzton.sunread.repository.exam.SubjectiveQuestionRepository;
@Service
public class ExamRepositoryService implements ExamService {
private static final Logger LOGGER = LoggerFactory
.getLogger(ExamRepositoryService.class);
private ExamRepository repository;
private ObjectiveQuestionRepository objectQsRepo;
private SubjectiveQuestionRepository subjectQsRepo;
private CapacityQuestionRepository capacityQsRepo;
private CapacityExamHistoryRepository capacityExamRepo;
private SpeedQuestionRepository speedRepo;
@Autowired
public ExamRepositoryService(ExamRepository repository,
ObjectiveQuestionRepository objectQsRepo,SubjectiveQuestionRepository
subjectQsRepo,CapacityQuestionRepository capacityQsRepo,CapacityExamHistoryRepository capacityExamRep,SpeedQuestionRepository speedRepo) {
this.repository = repository;
this.objectQsRepo = objectQsRepo;
this.subjectQsRepo = subjectQsRepo;
this.capacityQsRepo = capacityQsRepo;
this.capacityExamRepo = capacityExamRep;
this.speedRepo = speedRepo;
}
@Transactional(rollbackFor = { NotFoundException.class })
@Override
public Exam add(Exam added) {
LOGGER.debug("Adding a new Book entry with information: {}", added);
return repository.save(added);
}
@Transactional(rollbackFor = { NotFoundException.class })
@Override
public Exam deleteById(Long id) throws NotFoundException {
LOGGER.debug("Deleting a to-do entry with id: {}", id);
Exam deleted = findById(id);
LOGGER.debug("Deleting to-do entry: {}", deleted);
repository.delete(deleted);
return deleted;
}
@Transactional(rollbackFor = { NotFoundException.class })
@Override
public Page<Exam> findAll(Pageable pageable) throws NotFoundException {
Page<Exam> examPages = repository.findAll(pageable);
return examPages;
}
@Transactional(rollbackFor = { NotFoundException.class })
@Override
public VerifyExamPassDTO findAllByExamTypeAndPassStatus(Long studentId,ExamType type) throws NotFoundException {
List<Exam> timeExams = repository.findByStudentIdOrderByCreationTimeDesc(studentId);
if(timeExams.size() == 0){
throw new NotFoundException("can't find exam record");
}
int passCount = 0;
int questionCount = 0;
int passRate = 0;
List<Exam> exams = repository.findByStudentIdAndExamTypeAndIsPassOrderByCreationTimeDesc(studentId,type,true);
List<ExamDTO> examDTOs = new ArrayList<ExamDTO>();
for(int i=0;i<exams.size();i++){
Exam exam = exams.get(i);
passCount = passCount+exam.getPassCount();
questionCount = questionCount+exam.getQuestionNum();
if(type.equals(ExamType.VERIFY)){
Set<Review> reviews = exam.getBook().getReviews();
VerifiedExamDTO examDTO = new VerifiedExamDTO(exam);
for(Review review : reviews){
if(review.getStudentId().equals(exam.getStudentId())){
examDTO.setComment(review.getContent());
break;
}
}
examDTOs.add(examDTO);
}else{
examDTOs.add(new ExamDTO(exam));
}
}
if(questionCount != 0){
passRate = passCount*100/questionCount;
}
String time = timeExams.get(0).getCreationTime().toString("yyyy");
VerifyExamPassDTO passDTO = new VerifyExamPassDTO(examDTOs,passRate,time);
return passDTO;
}
@Transactional(rollbackFor = { NotFoundException.class })
@Override
public VerifyExamPassDTO findAllByExamType(Long studentId,ExamType type) throws NotFoundException {
List<Exam> timeExams = repository.findByStudentIdOrderByCreationTimeDesc(studentId);
if(timeExams.size() == 0){
throw new NotFoundException("can't find exam record");
}
int passCount = 0;
int questionCount = 0;
int passRate = 0;
List<Exam> exams = repository.findByStudentIdAndExamTypeOrderByCreationTimeDesc(studentId,type);
List<ExamDTO> examDTOs = new ArrayList<ExamDTO>();
for(int i=0;i<exams.size();i++){
Exam exam = exams.get(i);
passCount = passCount+exam.getPassCount();
questionCount = questionCount+exam.getQuestionNum();
if(type.equals(ExamType.VERIFY)){
Set<Review> reviews = exam.getBook().getReviews();
VerifiedExamDTO examDTO = new VerifiedExamDTO(exam);
for(Review review : reviews){
if(review.getStudentId().equals(exam.getStudentId())){
examDTO.setComment(review.getContent());
break;
}
}
examDTOs.add(examDTO);
}else{
examDTOs.add(new ExamDTO(exam));
}
}
if(questionCount != 0){
passRate = passCount*100/questionCount;
}
String time = timeExams.get(0).getCreationTime().toString("yyyy");
VerifyExamPassDTO passDTO = new VerifyExamPassDTO(examDTOs,passRate,time);
return passDTO;
}
@Transactional(readOnly = true, rollbackFor = { NotFoundException.class })
@Override
public Exam findById(Long id) throws NotFoundException {
LOGGER.debug("Finding a book entry with id: {}", id);
Exam found = repository.findOne(id);
LOGGER.debug("Found book entry: {}", found);
if (found == null) {
throw new NotFoundException("No exam found with id: " + id);
}
return found;
}
@Override
public Exam handInVerifyPaper(Exam added) {
Exam exam = add(added);
Set<Answer> answers = exam.getAnswers();
for (Answer answer : answers) {
ObjectiveAnswer objectAnswer = (ObjectiveAnswer) answer;
if (isAnswerCorrect(objectAnswer)) {
exam.setPassCount(exam.getPassCount() + 1);
} else {
exam.setFailCount(exam.getFailCount() + 1);
}
}
int score = 0;
if((exam.getPassCount() + exam.getFailCount())==0){
score = 0;
}else{
score = exam.getPassCount() * 100
/ (exam.getPassCount() + exam.getFailCount());
}
exam.setExamScore(score);
if (score >= 60) {
exam.setPass(true);
repository.save(exam);
List<Exam> exams = repository.findByStudentIdAndBookIdAndExamTypeAndIsPass(added.getStudentId(), added.getBook().getId(), added.getExamType(),true);
if(exams.size()==1){
exam.setFirstPass(true);
}else{
exam.setSecondPass(true);
}
} else {
exam.setPass(false);
}
repository.save(exam);
return exam;
}
public int findFirstPassRate(Long studentId, DateTime from,DateTime to){
List<Exam> firstPassExam = repository.findByStudentIdAndFirstPassAndExamTypeAndCreationTimeBetween(studentId, true, ExamType.VERIFY, from, to);
List<Exam> allPassExam = repository.findByStudentIdAndExamTypeAndIsPassAndCreationTimeBetweenOrderByCreationTimeDesc(studentId, ExamType.VERIFY, true, from, to);
if(allPassExam == null||allPassExam.size()==0||firstPassExam==null||firstPassExam.size()==0){
return 0;
}else{
return firstPassExam.size()*100/allPassExam.size();
}
}
public int findSecondPassRate(Long studentId, DateTime from,DateTime to){
List<Exam> firstPassExam = repository.findByStudentIdAndSecondPassAndExamTypeAndCreationTimeBetween(studentId, true, ExamType.VERIFY, from, to);
List<Exam> allPassExam = repository.findByStudentIdAndExamTypeAndIsPassAndCreationTimeBetweenOrderByCreationTimeDesc(studentId, ExamType.VERIFY, true, from, to);
if(allPassExam == null||allPassExam.size()==0||firstPassExam==null||firstPassExam.size()==0){
return 0;
}else{
return firstPassExam.size()*100/allPassExam.size();
}
}
@Transactional(rollbackFor = { NotFoundException.class })
@Override
public Exam handInCapacityTest(Exam added) {
Exam exam = add(added);
Set<Answer> answers = exam.getAnswers();
CapacityExamHistory capacityHistory = new CapacityExamHistory();
for (Answer answer : answers) {
ObjectiveAnswer objectAnswer = (ObjectiveAnswer) answer;
updateCapacityHistory(capacityHistory,objectAnswer);
if (isAnswerCorrect(objectAnswer)) {
exam.setPassCount(exam.getPassCount() + 1);
} else {
exam.setFailCount(exam.getFailCount() + 1);
}
}
int score = exam.getPassCount() * 100
/ (exam.getPassCount() + exam.getFailCount());
exam.setQuestionNum(added.getQuestions().size());
exam.setExamScore(score);
if (score >= 60) {
exam.setPass(true);
} else {
exam.setPass(false);
}
return exam;
}
@Transactional(rollbackFor = { NotFoundException.class })
@Override
public Exam handInThinkTest(Exam added) {
return add(added);
}
@Override
public List<ObjectiveQuestion> takeVerifyTest(final Long bookId) {
return getRandomObjectiveQuestions(bookId,QuestionType.VERIFY);
}
@Override
public List<CapacityQuestion> takeCapacityTest(int level) {
List<CapacityQuestionType> list = new ArrayList<CapacityQuestionType>();
list.add(CapacityQuestionType.FIRST);
list.add(CapacityQuestionType.SECOND);
list.add(CapacityQuestionType.THIRD);
list.add(CapacityQuestionType.FOURTH);
list.add(CapacityQuestionType.FIFTH);
list.add(CapacityQuestionType.SIXTH);
list.add(CapacityQuestionType.SEVENTH);
list.add(CapacityQuestionType.EIGHTTH);
List<CapacityQuestion> questions = this.getRandomCapacityQuestion(list, Exam.EXAM_CAPACITY_QUESTION_PER_TYPE,level);
return questions;
}
@Override
public List<SubjectiveQuestion> takeThinkTest(Long bookId) {
List<SubjectiveQuestionType> list = new ArrayList<SubjectiveQuestionType>();
list.add(SubjectiveQuestionType.FIRST);
list.add(SubjectiveQuestionType.SECOND);
list.add(SubjectiveQuestionType.THIRD);
list.add(SubjectiveQuestionType.FOURTH);
list.add(SubjectiveQuestionType.FIFTH);
List<SubjectiveQuestion> questions = this.getRandomSubjectiveQuestion(
bookId, list, Exam.EXAM_SUBJECTIVE_QUESTION_PER_TYPE);
return questions;
}
private List<ObjectiveQuestion> getRandomObjectiveQuestions(
final Long bookId,final QuestionType questionType) {
List<ObjectiveQuestion> allList = objectQsRepo.findByBookIdAndObjectiveType(bookId, questionType);
long total = allList.size();
LOGGER.debug("###################################"+total);
int i = allList.size();
if(i<=Exam.EXAM_QUESTION){
return allList;
}
int from = new Random().nextInt(i-Exam.EXAM_QUESTION);
List<ObjectiveQuestion> list = allList.subList(from, from+Exam.EXAM_QUESTION);
return list;
}
private List<SpeedQuestion> getRandomSpeedQuestions(
final Long articleId) {
List<SpeedQuestion> allList = speedRepo.findByArticleId(articleId);
long total = allList.size();
LOGGER.debug("###################################"+total);
int i = allList.size();
if(i<=Exam.EXAM_QUESTION){
return allList;
}
int from = new Random().nextInt(i-Exam.EXAM_QUESTION);
List<SpeedQuestion> list = allList.subList(from, from+Exam.EXAM_QUESTION);
return list;
}
private int getRandomPage(int total, int size) {
if (total <= size) {
return 0;
}
Random random = new Random();
int randomPage = random.nextInt(total / size);
return randomPage;
}
private List<SubjectiveQuestion> getRandomSubjectiveQuestion(Long bookId,
List<SubjectiveQuestionType> typeList, int num) {
List<SubjectiveQuestion> list = new ArrayList<SubjectiveQuestion>();
Random random = new Random();
if (typeList != null) {
for (int i = 0; i < typeList.size(); i++) {
List<SubjectiveQuestion> tempList = subjectQsRepo
.findByQuestionTypeAndBookId(typeList.get(i), bookId);
if (tempList.size() > num) {
int z = random.nextInt(tempList.size());
for (int j = 0; j < num; j++) {
list.add(tempList.get(z));
z = (z + 1) % tempList.size();
}
} else {
list.addAll(tempList);
}
}
}
return list;
}
private List<CapacityQuestion> getRandomCapacityQuestion(
List<CapacityQuestionType> typeList, int num,int level) {
List<CapacityQuestion> list = new ArrayList<CapacityQuestion>();
Random random = new Random();
if (typeList != null) {
for (int i = 0; i < typeList.size(); i++) {
List<CapacityQuestion> tempList = capacityQsRepo
.findByQuestionTypeAndLevel(typeList.get(i),level);
if (tempList.size() > num) {
int z = random.nextInt(tempList.size());
for (int j = 0; j < num; j++) {
list.add(tempList.get(z));
z = (z + 1) % tempList.size();
}
} else {
list.addAll(tempList);
}
}
}
return list;
}
@Override
public List<Exam> getTodayVerifyTestStatus(Long bookId, Long studentId) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
DateTime dt = new DateTime(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH), 00, 00, 00, 000);
List<Exam> list = repository.findByStudentIdAndBookIdAndExamTypeAndCreationTimeAfter(studentId, bookId,ExamType.VERIFY,dt);
return list;
}
public boolean isPassVerifyTest(Long bookId,Long studentId){
List<Exam> list = repository.findByStudentIdAndBookIdAndExamTypeOrderByCreationTimeDesc(studentId,bookId,ExamType.VERIFY);
for(int i=0;i<list.size();i++){
if(list.get(i).isPass()){
return true;
}
}
return false;
}
@Override
public List<ObjectiveQuestion> takeWordTest(Long bookId) {
return getRandomObjectiveQuestions(bookId,QuestionType.WORD);
}
@Override
public List<SpeedQuestion> takeSpeedTest(long articleId) {
return getRandomSpeedQuestions(articleId);
}
@Override
public Exam handInWordPaper(Exam added) {
Exam exam = added;
Set<Answer> answers = exam.getAnswers();
for (Answer answer : answers) {
ObjectiveAnswer objectAnswer = (ObjectiveAnswer) answer;
if (isAnswerCorrect(objectAnswer)) {
exam.setPassCount(exam.getPassCount() + 1);
} else {
exam.setFailCount(exam.getFailCount() + 1);
}
}
int score = exam.getPassCount() * 100
/ (exam.getPassCount() + exam.getFailCount());
exam.setExamScore(score);
if (score >= 60) {
exam.setPass(true);
} else {
exam.setPass(false);
}
exam = add(exam);
return exam;
}
@Override
public Exam handInSpeedTest(Exam added) {
Exam exam = added;
Set<Answer> answers = exam.getAnswers();
for (Answer answer : answers) {
ObjectiveAnswer objectAnswer = (ObjectiveAnswer) answer;
if (isAnswerCorrect(objectAnswer)) {
exam.setPassCount(exam.getPassCount() + 1);
} else {
exam.setFailCount(exam.getFailCount() + 1);
}
}
int score = exam.getPassCount() * 100
/ (exam.getPassCount() + exam.getFailCount());
exam.setExamScore(score);
if (score >= 60) {
exam.setPass(true);
} else {
exam.setPass(false);
}
exam = add(exam);
return exam;
}
@Transactional
@Override
public int findPassVerifyExamPassRate(Long studentId, DateTime from,DateTime to) {
List<Exam> exams = repository.findByStudentIdAndExamTypeAndIsPassAndCreationTimeBetweenOrderByCreationTimeDesc(studentId, ExamType.VERIFY, true, from, to);
int pass = 0;
int total = 0;
int passRate = 0;
for(int i=0;i<exams.size();i++){
Exam exam = exams.get(i);
pass = pass + exam.getPassCount();
total = total + exam.getQuestionNum();
}
if(total!=0){
passRate = pass*100/total;
}
return passRate;
}
@Transactional
@Override
public Map<CapacityQuestionType, Integer> getStudentCapacityStatus(
Long studentId, DateTime from, DateTime to) {
List<CapacityExamHistory> capacityExams = capacityExamRepo.findByStudentIdAndCreationTimeBetween(studentId, from, to);
Map<CapacityQuestionType, Integer> map = new HashMap<CapacityQuestionType, Integer>();
int firstPass = 0;
int firstCount = 0;
int secondPass = 0;
int secondCount = 0;
int thirdPass = 0;
int thirdCount = 0;
int fourthPass = 0;
int fourthCount = 0;
int fifthPass = 0;
int fifthCount = 0;
int sixthPass = 0;
int sixthCount = 0;
int seventhPass = 0;
int seventhCount = 0;
int eightthPass = 0;
int eightthCount = 0;
for(int i=0;i<capacityExams.size();i++){
CapacityExamHistory exam = capacityExams.get(i);
firstPass = firstPass + exam.getFirstPass();
firstCount = firstCount + exam.getFirstFail()+exam.getFirstPass();
secondPass = secondPass + exam.getSecondPass();
secondCount = secondCount + exam.getSecondFail()+exam.getSecondPass();
thirdPass = thirdPass + exam.getThirdPass();
thirdCount = thirdCount + exam.getThirdFail()+exam.getThirdPass();
fourthPass = fourthPass + exam.getFourthPass();
fourthCount = fourthCount + exam.getFourthFail()+exam.getFourthPass();
fifthPass = fifthPass + exam.getFifthPass();
fifthCount = fifthCount + exam.getFifthFail()+exam.getFifthPass();
sixthPass = sixthPass + exam.getSixthPass();
sixthCount = sixthCount + exam.getSixthFail()+exam.getSixthPass();
seventhPass = seventhPass + exam.getSeventhPass();
seventhCount = seventhCount + exam.getSeventhFail()+exam.getSeventhPass();
eightthPass = eightthPass + exam.getEightthPass();
eightthCount = eightthCount + exam.getEightthFail()+exam.getEightthPass();
}
map.put(CapacityQuestionType.FIRST, firstCount==0?0:firstPass*100/firstCount);
map.put(CapacityQuestionType.SECOND, secondCount==0?0:secondPass*100/secondCount);
map.put(CapacityQuestionType.THIRD, thirdCount==0?0:thirdPass*100/thirdCount);
map.put(CapacityQuestionType.FOURTH, fourthCount==0?0:fourthPass*100/fourthCount);
map.put(CapacityQuestionType.FIFTH, fifthCount==0?0:fifthPass*100/fifthCount);
map.put(CapacityQuestionType.SIXTH, sixthCount==0?0:sixthPass*100/sixthCount);
map.put(CapacityQuestionType.SEVENTH, seventhCount==0?0:seventhPass*100/seventhCount);
map.put(CapacityQuestionType.EIGHTTH, eightthCount==0?0:eightthPass*100/eightthCount);
return map;
}
public boolean isAnswerCorrect(ObjectiveAnswer answer){
ObjectiveQuestion question = objectQsRepo.findOne(answer.getQuestion().getId());
if(answer.getOption().equals(question.getCorrectAnswer())){
return true;
}else{
return false;
}
}
private void updateCapacityHistory(CapacityExamHistory history,ObjectiveAnswer answer){
CapacityQuestion question = (CapacityQuestion) answer.getQuestion();
CapacityQuestionType type = question.getQuestionType();
if(type.equals(CapacityQuestionType.FIRST)){
if(isAnswerCorrect(answer)){
history.setFirstPass(history.getFirstPass()+1);
}else{
history.setFirstFail(history.getFirstFail()+1);
}
}else if(type.equals(CapacityQuestionType.SECOND)){
if(isAnswerCorrect(answer)){
history.setSecondPass(history.getSecondPass()+1);
}else{
history.setSecondFail(history.getSecondFail()+1);
}
}else if(type.equals(CapacityQuestionType.THIRD)){
if(isAnswerCorrect(answer)){
history.setThirdPass(history.getThirdPass()+1);
}else{
history.setThirdFail(history.getThirdFail()+1);
}
}else if(type.equals(CapacityQuestionType.FOURTH)){
if(isAnswerCorrect(answer)){
history.setFourthPass(history.getFourthPass()+1);
}else{
history.setFourthFail(history.getFourthFail()+1);
}
}else if(type.equals(CapacityQuestionType.FIFTH)){
if(isAnswerCorrect(answer)){
history.setFifthPass(history.getFifthPass()+1);
}else{
history.setFifthFail(history.getFifthFail()+1);
}
}else if(type.equals(CapacityQuestionType.SIXTH)){
if(isAnswerCorrect(answer)){
history.setSixthPass(history.getSixthPass()+1);
}else{
history.setSixthFail(history.getSixthFail()+1);
}
}else if(type.equals(CapacityQuestionType.SEVENTH)){
if(isAnswerCorrect(answer)){
history.setSeventhPass(history.getSeventhPass()+1);
}else{
history.setSeventhFail(history.getSeventhFail()+1);
}
}else if(type.equals(CapacityQuestionType.EIGHTTH)){
if(isAnswerCorrect(answer)){
history.setEightthPass(history.getEightthPass()+1);
}else{
history.setEightthFail(history.getEightthFail()+1);
}
}
}
}