package com.twasyl.slideshowfx.server.beans.quiz;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import java.util.Arrays;
import java.util.List;
/**
* This class represents a quiz that can be performed during a presentation.
*
* @author Thierry Wasylczenko
* @version 1.0
* @since SlideshowFX 1.0
*/
public class Quiz {
private LongProperty id = new SimpleLongProperty();
private ObjectProperty<Question> question = new SimpleObjectProperty<>();
private ListProperty<Answer> answers = new SimpleListProperty<>(FXCollections.observableArrayList());
/**
* The property for the ID of this quiz.
* @return The property for the ID of this quiz.
*/
public LongProperty idProperty() { return id; }
/**
* The ID of this quiz.
* @return The ID of this quiz.
*/
public long getId() { return id.get(); }
/**
* Set the ID for this quiz.
* @param id The new ID for this quiz.
*/
public void setId(long id) { this.id.set(id); }
/**
* Get the question of this quiz.
* @return The question of this quiz.
*/
public Question getQuestion() { return question.get(); }
/**
* The question of this quiz.
* @return The property associated to this quiz.
*/
public ObjectProperty<Question> questionProperty() { return question; }
/**
* Set the question of this quiz.
* @param question The question of this quiz.
*/
public void setQuestion(Question question) {
this.question.set(question);
}
/**
* The property containing the possible answers of this quiz.
* @return The property containing the possible answers for this quiz.
*/
public ListProperty<Answer> answersProperty() { return answers; }
/**
* Get the possible answers for this quiz.
* @return The list of possible answers.
*/
public ObservableList<Answer> getAnswers() { return answers.get(); }
/**
* Set the possible answers for this quiz.
* @param answers The list of possible answers for this quiz.
*/
public void setAnswers(ObservableList<Answer> answers) { this.answers.set(answers); }
/**
* Get all correct answers for this quiz.
* @return The list containing only the correct answers for this quiz.
*/
public FilteredList<Answer> getCorrectAnswers() { return this.getAnswers().filtered(answer -> answer.isCorrect()); }
/**
* Performs a check to know if the quiz is answered correctly. This method checks if all correct answers contained
* in this quiz has its ID referenced in the given {@code answersIDs} collection.
*
* @param answersIDs All answers' ID the user has checked.
* @return <code>true</code> if all correct answers of this quiz has its ID referenced in {@code answersIDs},
* false otherwise
*/
public boolean checkAnswers(Long ... answersIDs) {
boolean correct = answersIDs != null && answersIDs.length > 0;
// Avoid unnecessary treatment and variable assignment
if(correct) {
final List<Answer> correctAnswers = this.getAnswers().filtered(answer -> answer.isCorrect());
/* If the size of the list of expected answers are not the same that the size of the given ansewers,
* it is unnecessary to continue.
*/
if(correct = correctAnswers.size() == answersIDs.length) {
final List<Long> answersIDsList = Arrays.asList(answersIDs);
int index = 0;
// The "real" number of correct answers received.
int numberOfCorrectAnswersReceived = 0;
/*
* Loop on every correct answer while everything is correct
*/
while (index < correctAnswers.size() && correct) {
correct = answersIDsList.contains(correctAnswers.get(index).getId());
if(correct) numberOfCorrectAnswersReceived++;
index++;
}
correct = numberOfCorrectAnswersReceived == correctAnswers.size();
}
}
return correct;
}
/**
* Convert this Quiz object into a JSON object.
* @return The JSON object representing this quiz
*/
public JsonObject toJSON() {
final JsonObject object = new JsonObject();
object.put("id", this.getId());
object.put("correctAnswers", this.getCorrectAnswers().size());
if(this.getQuestion() != null) {
final JsonObject questionObject = new JsonObject();
questionObject.put("id", this.getQuestion().getId());
questionObject.put("text", this.getQuestion().getText());
object.put("question", questionObject);
}
if(!this.getAnswers().isEmpty()) {
final JsonArray answersArray = new JsonArray();
for(Answer answer : this.getAnswers()) {
answersArray.add(new JsonObject()
.put("id", answer.getId())
.put("text", answer.getText())
.put("correct", answer.isCorrect()));
}
object.put("answers", answersArray);
}
return object;
}
/**
* Converts this{@link Quiz} as a JSON representation.
* @return The JSON string representation of this quiz.
*/
public String toJSONString() {
return toJSON().encode();
}
/**
* Build a Quiz object from the given JSON string.
* @param json The JSON string representing the quiz.
* @return The created Quiz object.
* @throws java.lang.NullPointerException if {@code json} is {@code null}.
* @throws java.lang.IllegalArgumentException if {@code json} is empty.
*/
public static Quiz build(final String json) {
if(json == null) throw new NullPointerException("The JSON string can not be null");
if(json.trim().isEmpty()) throw new IllegalArgumentException("The JSON string is empty");
final JsonObject object = new JsonObject(json);
final Quiz quiz = new Quiz();
quiz.setId(object.getLong("id"));
final JsonObject questionJson = object.getJsonObject("question");
if(questionJson != null) {
final Question question = new Question();
question.setQuiz(quiz);
question.setText(questionJson.getString("text"));
question.setId(questionJson.getLong("id"));
quiz.setQuestion(question);
}
final JsonArray answersJson = object.getJsonArray("answers");
if(answersJson != null) {
answersJson.forEach(answerJson -> {
final Answer answer = new Answer();
answer.setQuiz(quiz);
answer.setId(((JsonObject) answerJson).getLong("id"));
answer.setText(((JsonObject) answerJson).getString("text"));
answer.setCorrect(((JsonObject) answerJson).getBoolean("correct"));
quiz.getAnswers().add(answer);
});
}
return quiz;
}
}