/**
* Copyright 2012 Neurowork Consulting S.L.
*
* This file is part of eMobc.
*
* QuizController.java
* eMobc Android Framework
*
* eMobc is free software: you can redistribute it and/or modify
* it under the terms of the Affero GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* eMobc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the Affero GNU General Public License
* along with eMobc. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.emobc.android.levels.impl.quiz;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import android.util.Log;
/**
* @author Jorge E. Villaverde
* @version 0.1
* @since 0.1
*/
public class QuizController implements Serializable {
/**
*
*/
private static final long serialVersionUID = 7877510063743276015L;
public static final String QUIZ_CONTROLLER_TAG = "_QUIZ_CONTROLLER_TAG_";
/*--------- Attributes ----------*/
//Quiz
private List<QuizLevelDataItem> data;
private int quizIndex; //Index of quiz
private QuizLevelDataItem actualQuiz;
//Questions
private List<String> ids;//ids of quiz questions
private int questionIndex; //Index of question
private QuestionDataItem currQuestion;
private String idNextQuestion;
private List<QuizAnswerDataItem> currAnswers;
private int currAnswer; //Current answer selected
//Results
private QuizResults results = new QuizResults(0);
/*------- Constructor --------*/
public QuizController(){
data = new ArrayList<QuizLevelDataItem>();
}
/*--------- Methods ----------*/
public void addQuiz(QuizLevelDataItem quiz){
data.add(quiz);
}
/**
* Starts the quiz. Must be called before start your quiz. Then
* you can call other methods like getQuestion for get the actual question.
*
* @param time Time for make the quiz, in seconds
*/
public void start(int time){
this.quizIndex=0;
initQuiz(data.get(quizIndex));
if (actualQuiz.isAdventureMode()){
this.results = new QuizResults(0);
}
}
/**
* Initialize the Quiz Controller to start the quiz
* @param quiz The quiz to be started by the Quiz Controller
*/
private void initQuiz(QuizLevelDataItem quiz){
this.actualQuiz = quiz;
this.questionIndex = 0;
if(actualQuiz.isAdventureMode()){
idNextQuestion = actualQuiz.getFirst();
this.currQuestion = actualQuiz.getQuestion(this.idNextQuestion);
}else{
ids = actualQuiz.getQuestionIds();
Collections.shuffle(ids);//Shuffle questions
this.currQuestion = actualQuiz.getQuestion(ids.get(questionIndex));
}
if(currQuestion != null){
this.currAnswers = currQuestion.getAnswers();
Collections.shuffle(currAnswers);
}else{
Log.w("QuizController", "No se ha encontrado la pregunta para el Quiz");
}
}
/**
* Return if there is more questions available. If not, you should call finish() method
* for finish the quiz and confirm the last answer.
* @return True if there are more questions. False if the actual question is the last one
*/
public boolean hasNext(){
if (hasNextQuestionActualQuiz()){
return true;
}else{
return hasNextQuiz();
}
}
/**
* Return if there are more question in the actual quiz
* @return
*/
private boolean hasNextQuestionActualQuiz(){
if (actualQuiz.isAdventureMode()){
return idNextQuestion!=null;
}else{
return this.questionIndex<actualQuiz.size()-1;
}
}
/**
* Return if there are more quiz after the current quiz
* @return
*/
private boolean hasNextQuiz(){
return this.quizIndex<data.size()-1;
}
/**
* Skip to the next quiz and initialize the controller for start it.
*/
private void nextQuiz(){
this.quizIndex++;
initQuiz(data.get(quizIndex));
}
/**
* Skips to the next quiz question and confirms your last answer set with
* setAnswer() method.
* You should be call this method after checking with hasNext method.
* If the quiz is an adventure, you must use setAnswer before call this
* method.
*/
public void next(){
//Saves answer results
if(currQuestion == null)
return;
QuizAnswerDataItem answer = currQuestion.getAnswers().get(currAnswer);
if (answer.isCorrect()){
this.results.setAnswer(currQuestion.getWeight(), true);
}else{
this.results.setAnswer(currQuestion.getWeight(), false);
}
//Skips to the next quiz question
if (hasNextQuestionActualQuiz()){
nextQuestionActualQuiz();
}else{
nextQuiz();
}
}
/**
* Skips to the next quiz question in current quiz depending on the
* quiz mode: quiz or adventure and save the answer results.
*/
private void nextQuestionActualQuiz(){
if (actualQuiz.isAdventureMode()){
this.currQuestion = actualQuiz.getQuestion(this.idNextQuestion);
}else{
this.questionIndex++;
this.currQuestion = actualQuiz.getQuestion(ids.get(questionIndex));
}
this.currAnswers = currQuestion.getAnswers();
Collections.shuffle(currAnswers);
}
/**
* Return the actual question
* @return
*/
public String getQuestion(){
if(currQuestion != null)
return currQuestion.getText();
return "";
}
/**
* Return the actual question image
* @return The path or url of the image.
*/
public String getImage(){
if(currQuestion != null)
return currQuestion.getImage();
return "";
}
/**
* Return a list of String with answers of actual question
* @return
*/
public List<String> getAnswers(){
if(currAnswers == null)
return null;
Iterator<QuizAnswerDataItem> i = currAnswers.iterator();
List<String> toReturn = new ArrayList<String>();
while (i.hasNext()){
QuizAnswerDataItem actual = (QuizAnswerDataItem) i.next();
toReturn.add(actual.getAnsText());
}
return toReturn;
}
/**
* Set the answer for the actual question with his index. You must call this method
* before call next() if your quiz is an adventure. For confirm your answer you
* have to call next() method later.
*
* @param index Answer index from 0 to getAnswers().size()-1;
*/
public void setAnswer(int index){
currAnswer = index;
QuizAnswerDataItem answer = currQuestion.getAnswers().get(currAnswer);
this.idNextQuestion = answer.getNext();
}
/**
* Return the actual quiz results. You can call this method anytime.
*
* @return
*/
public QuizResults getResult(){
return this.results;
}
/**
* Call this method for finish the quiz. It's needed to confirm the
* last answer which you set with setAnswer method.
*/
public void finish(){
//Saves answer results
QuizAnswerDataItem answer = currQuestion.getAnswers().get(currAnswer);
if (answer.isCorrect()){
this.results.setAnswer(currQuestion.getWeight(), true);
}else{
this.results.setAnswer(currQuestion.getWeight(), false);
}
}
}