/*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
* This file is part of Entando software.
* Entando is a free software;
* You can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; version 2.
*
* See the file License for the specific language governing permissions
* and limitations under the License
*
*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
*/
package com.agiletec.plugins.jpsurvey.apsadmin.survey;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.agiletec.aps.system.ApsSystemUtils;
import com.agiletec.aps.system.services.lang.Lang;
import com.agiletec.aps.util.ApsProperties;
import com.agiletec.apsadmin.system.ApsAdminSystemConstants;
import com.agiletec.plugins.jpsurvey.aps.system.services.collect.IResponseManager;
import com.agiletec.plugins.jpsurvey.aps.system.services.collect.model.SingleQuestionResponse;
import com.agiletec.plugins.jpsurvey.aps.system.services.survey.model.Choice;
import com.agiletec.plugins.jpsurvey.aps.system.services.survey.model.Question;
import com.agiletec.plugins.jpsurvey.aps.system.services.survey.model.Survey;
import com.agiletec.plugins.jpsurvey.aps.system.services.survey.model.SurveyRecord;
public class QuestionAction extends AbstractSurveyAction implements IQuestionAction {
@Override
public void validate() {
super.validate();
this.checkExistingIds();
this.fetchLocalizedFields();
}
private void checkExistingIds() {
if (null == this.getStrutsAction()) {
this.addActionError(this.getText("message.surveyAction.sysError", new String[]{"strutsAction"}));
} else {
if (null == this.getQuestionId() && this.getStrutsAction() == ApsAdminSystemConstants.EDIT) {
this.addActionError(this.getText("message.surveyAction.sysError", new String[]{"questionId"}));
}
if (null == this.getSingleChoice() && this.getStrutsAction() == ApsAdminSystemConstants.EDIT) {
this.addActionError(this.getText("message.surveyAction.sysError", new String[]{"isSingleChoice"}));
}
}
}
// private boolean hasResponseNumberFieldErrors() {
// List<String> minRespErrors = (List<String>) this.getFieldErrors().get("minResponseNumber");
// List<String> maxRespErrors = (List<String>) this.getFieldErrors().get("maxResponseNumber");
// return ((minRespErrors != null && (minRespErrors).size() > 0) ||
// (maxRespErrors != null && maxRespErrors.size() > 0));
// }
//
//
// private void checkResponseNumberFields() {
// List<Choice> list = new ArrayList<Choice>();
// Question question = null;
// int currentChoicesNumber = 0;
// if (this.hasActionErrors()) return;
// if (this.hasResponseNumberFieldErrors()) {
// return; // Ci sono errori sui size che vanno corretti prima
// }
// // abort response size checks if the override is present or when creating new questions
// if (this.getStrutsAction() == ApsAdminSystemConstants.ADD ||
// (null != this.getOverrideResponseNumberFieldsCheck() && this.getOverrideResponseNumberFieldsCheck())) return;
// try {
// if (null == this.getMinResponseNumber()) setMinResponseNumber(0);
// if (null == this.getMaxResponseNumber()) setMaxResponseNumber(0);
// int min = this.getMinResponseNumber();
// int max = this.getMaxResponseNumber();
// if (this.getSingleChoice() == SINGLE_CHOICE_ID) return;
// question = this.getSurveyManager().loadQuestion(this.getQuestionId());
// if (null != question) {
// list = question.getChoices();
// this.setQuestion(question);
// }
// if (null != list) {
// currentChoicesNumber = list.size();
// // if we have no choices then these checks are useless
// if (min == 0 && max == 0 && currentChoicesNumber == 0) return;
// if (min == 0 && currentChoicesNumber > 0) {
// this.addFieldError(this.getText("jpsurvey_minResponseNumber"),this.getText("message.questionAction.zeroValue",new String[]{this.getText("jpsurvey_minResponseNumber")}));
// }
// // check for errors condition in multiple-choice questions
// if (min > currentChoicesNumber && currentChoicesNumber > 0) {
// this.addActionError(this.getText("message.questionAction.outOfBounds",new String[]{this.getText("minResponseNumber")}));
// }
// if (max > currentChoicesNumber && currentChoicesNumber > 0) {
// this.addActionError(this.getText("message.questionAction.outOfBounds",new String[]{this.getText("maxResponseNumber")}));
// }
// } else {
// // check for improper values in response numbers
// if (min > 0 || max > 0) {
// this.addActionError(this.getText("message.questionAction.TypeNotAllowed"));
// }
// }
// } catch (Throwable t) {
// ApsSystemUtils.logThrowable(t, this, "checkResponseNumberFields");
// throw new RuntimeException("Error in valition answers allowed",t);
// }
// }
/**
* Used to get all the localized field coming from the form
*/
private void fetchLocalizedFields() {
Iterator<Lang> itr = this.getLangManager().getLangs().iterator();
while (itr.hasNext()) {
Lang currentLang = itr.next();
Lang defaultLanguage = this.getLangManager().getDefaultLang();
String currentLangCode = currentLang.getCode();
String questionKey = "question-" + currentLangCode;
String question = this.getRequest().getParameter(questionKey);
if (null != question && question.trim().length() > 0) {
this.getQuestions().put(currentLangCode, question.trim());
} else {
if (currentLang.getCode().equals(defaultLanguage.getCode())) {
this.addActionError(this.getText("message.jpsurvey.defaultLangRequired", new String[]{defaultLanguage.getDescr(),this.getText("question")}));
}
}
}
}
public boolean isEditable(Integer surveyId) {
boolean res = false;
try {
if (null == surveyId) return true;
Survey survey = this.getSurveyManager().loadSurvey(surveyId);
res =! survey.isElegibleForVoting(null);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "isEditable");
throw new RuntimeException("Error checking the \"editable\" state of the survey with id " + surveyId, t);
}
return res;
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.ISurveyAction#getResponseOccurences()
*/
public int getResponseOccurences(Integer choiceId) {
List<SingleQuestionResponse> list = null;
try {
if (choiceId == null) return 0;
list = this.getResponseManager().aggregateResponseByIds(null, null, choiceId, null);
if (null != list) {
return list.size();
} else {
return 0;
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "getResponseOccurences");
throw new RuntimeException("Error loading statistics related to choice ID "+choiceId,t);
}
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.IQuestionAction#addNewQuestion()
*/
public String addNewQuestion() {
SurveyRecord survey = null;
Question fakeQuestion = new Question();
try {
if (this.getQuestionId() == null ) {
setStrutsAction(ApsAdminSystemConstants.ADD);
// we have no choice but to load the titles from the survey
survey = this.getSurveyManager().loadSurvey(this.getSurveyId());
if (null != survey) {
fakeQuestion.setId(-1);
fakeQuestion.setSurveyId(this.getSurveyId());
fakeQuestion.setExtraInfo(survey.isQuestionnaire(), survey.getTitles());
this.setQuestion(fakeQuestion);
}
} else {
if (this.getActionErrors().isEmpty()) return this.editSingleQuestion();
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "getResponseOccurences");
throw new RuntimeException("Error adding a new question. ",t);
}
return SUCCESS;
}
@Override
public String editSingleQuestion() {
Question question = null;
this.setStrutsAction(ApsAdminSystemConstants.EDIT);
try {
if (null != this.getQuestionId()) {
question = this.getSurveyManager().loadQuestion(this.getQuestionId());
if (null == question) {
this.addActionError(this.getText("message.questionAction.nullquestion", new String[]{String.valueOf(this.getQuestionId())}));
return INPUT;
} else {
this.setQuestion(question);
this.setTitles(question.getSurveyTitles());
this.setQuestionId(question.getId());
this.setSurveyId(question.getSurveyId());
this.setQuestions(question.getQuestions());
this.setPos(question.getPos());
this.setSingleChoice(question.isSingleChoice() ? SINGLE_CHOICE_ID : MULTIPLE_CHOICE_ID);
if (!question.isSingleChoice()) {
this.setMinResponseNumber(question.getMinResponseNumber());
this.setMaxResponseNumber(question.getMaxResponseNumber());
}
Map<Integer, Integer> stats = getResponseManager().loadQuestionStatistics(this.getQuestionId());
// load statistics for the current question
this.setChoiceStats(stats);
}
} else {
this.addActionError(this.getText("message.surveyAction.cannotProceed"));
return INPUT;
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "editSingleQuestion");
return FAILURE;
}
return SUCCESS;
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.IQuestionAction#saveQuestion()
*/
public String saveQuestion() {
Question question = null;
try {
if (this.getStrutsAction() == ApsAdminSystemConstants.ADD) {
question = new Question();
question.setSurveyId(this.getSurveyId());
question.setSingleChoice(true);
}
if (this.getStrutsAction() == ApsAdminSystemConstants.EDIT) {
question = this.getSurveyManager().loadQuestion(this.getQuestionId());
question.setSingleChoice(this.getSingleChoice() == SINGLE_CHOICE_ID);
if (!question.isSingleChoice()) {
question.setMaxResponseNumber(this.getMaxResponseNumber());
question.setMinResponseNumber(this.getMinResponseNumber());
// THIS WILL NOT PRESERVE THE SINGLE/MULTIPLE CHOICE OPTION
// check if the min and max answer are present
if (question.getChoices().size() < this.getMinResponseNumber()) {
// the choices are fewer than those mandatory
this.addActionError(this.getText("message.question.tooFewChoices",
new String[]{String.valueOf(question.getChoices().size()), String.valueOf(this.getMinResponseNumber())}));
return "wrongAnswerNumber";
}
if (this.getMinResponseNumber() > this.getMaxResponseNumber()) {
// the number of mandatory choices is smaller than the number of the allowed ones.
this.addActionError(this.getText("message.question.incorrectChoicesRange",
new String[]{String.valueOf(this.getMinResponseNumber()), String.valueOf(this.getMaxResponseNumber())}));
return "wrongAnswerNumber";
}
if (question.getChoices().size() < this.getMaxResponseNumber()) {
// the number of choices is smaller than the one a user can pick
this.addActionError(this.getText("message.question.fewChoices",
new String[]{String.valueOf(question.getChoices().size()), String.valueOf(this.getMaxResponseNumber())}));
return "wrongAnswerNumber";
}
} else {
question.setMaxResponseNumber(0);
question.setMinResponseNumber(0);
}
}
question.setQuestions(this.getQuestions());
if (this.getStrutsAction() == ApsAdminSystemConstants.ADD) {
this.getSurveyManager().saveQuestionInSortedPosition(question);
this.setQuestionId(question.getId());
this.setStrutsAction(ApsAdminSystemConstants.EDIT);
return "editSingleQuestion";
}
if (this.getStrutsAction() == ApsAdminSystemConstants.EDIT) {
this.getSurveyManager().updateQuestion(question);
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "saveQuestion");
return FAILURE;
}
return SUCCESS;
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.IQuestionAction#deleteQuestion()
*/
public String deleteQuestion() {
try {
if (null != this.getQuestionId()) {
this.getResponseManager().deleteResponseByQuestionId(this.getQuestionId());
this.getSurveyManager().deleteQuestion(this.getQuestionId());
} else {
this.addActionError(this.getText("message.surveyAction.cannotProceed"));
return INPUT;
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "deleteQuestion");
return FAILURE;
}
return SUCCESS;
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.IQuestionAction#moveQuestionUp()
*/
public String moveQuestionUp() {
return this.moveQuestion(true);
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.IQuestionAction#moveQuestionDown()
*/
public String moveQuestionDown() {
return this.moveQuestion(false);
}
private String moveQuestion(boolean up) {
try {
if (null != getQuestionId()) {
this.getSurveyManager().swapQuestionPosition(this.getQuestionId(), up);
} else {
this.addActionError(this.getText("message.surveyAction.cannotProceed"));
return INPUT;
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "moveQuestion");
return FAILURE;
}
return SUCCESS;
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.IQuestionAction#trashQuestion()
*/
public String trashQuestion() {
Question question = null;
try {
if (null != this.getQuestionId()) {
question = this.getSurveyManager().loadQuestion(this.getQuestionId());
} else {
this.addActionError(this.getText("message.surveyAction.sysError", new String[]{"questionId"}));
return INPUT;
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "trashQuestion");
return FAILURE;
}
this.setQuestion(question);
return SUCCESS;
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.IQuestionAction#addFreeText()
*/
public String addFreeText() {
List<Choice> choiceList = null;
String result = this.saveQuestion();
if (result.equals(FAILURE)) return FAILURE;
if (result.equals(INPUT)) return INPUT;
try {
if (null != this.getQuestionId()) {
choiceList = getSurveyManager().getQuestionChoices(this.getQuestionId());
if (null!= choiceList) {
Iterator<Choice> itr = choiceList.iterator();
while (itr.hasNext()) {
Choice current = itr.next();
if (current.isFreeText()) {
this.addActionError(this.getText("message.questionAction.noMoreFreeText"));
return "noMoreFreeText";
}
}
}
} else {
return INPUT;
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "addFreeText");
return FAILURE;
}
return SUCCESS;
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.IQuestionAction#addChoice()
*/
public String addChoice() {
String result = this.saveQuestion();
if (result.equals(FAILURE)) return FAILURE;
if (result.equals(INPUT)) return INPUT;
if (this.getStrutsAction() != ApsAdminSystemConstants.EDIT) {
this.addActionError("jpsurvey: wrong struts action (" + this.getStrutsAction() + ") detected in 'addChoice', only EDIT allowed");
return INPUT;
}
return SUCCESS;
}
/**
* Trampoline to the list of the submitted free text
* @return
*/
public String freeTextListEntry() {
return SUCCESS;
}
/* (non-Javadoc)
* @see com.agiletec.plugins.jpsurvey.apsadmin.survey.IQuestionAction#editChoice()
*/
public String editChoice() {
return SUCCESS;
}
public String getDefaultLangCode() {
return this.getLangManager().getDefaultLang().getCode();
}
public void setQuestionId(Integer questionId) {
this._questionId = questionId;
}
public Integer getQuestionId() {
return _questionId;
}
public void setStrutsAction(Integer strutsAction) {
this._strutsAction = strutsAction;
}
public Integer getStrutsAction() {
return _strutsAction;
}
public void setChoices(List<Choice> choices) {
this._choices = choices;
}
public List<Choice> getChoices() {
return _choices;
}
public void setSurveyId(Integer surveyId) {
this._surveyId = surveyId;
}
public Integer getSurveyId() {
return _surveyId;
}
public void setPos(Integer pos) {
this._pos = pos;
}
public Integer getPos() {
return _pos;
}
public void setMinResponseNumber(Integer minResponseNumber) {
this._minResponseNumber = minResponseNumber;
}
public Integer getMinResponseNumber() {
return _minResponseNumber;
}
public void setMaxResponseNumber(Integer maxResponseNumber) {
this._maxResponseNumber = maxResponseNumber;
}
public Integer getMaxResponseNumber() {
return _maxResponseNumber;
}
public void setQuestions(ApsProperties questions) {
this._questions = questions;
}
public ApsProperties getQuestions() {
return _questions;
}
public void setSingleChoice(Integer singleChoice) {
this._singleChoice = singleChoice;
}
public Integer getSingleChoice() {
return _singleChoice;
}
public void setChoiceStats(Map<Integer, Integer> choiceStats) {
this._choiceStats = choiceStats;
}
public Map<Integer, Integer> getChoiceStats() {
return _choiceStats;
}
public void setOverrideResponseNumberFieldsCheck(
Boolean overrideResponseNumberFieldsCheck) {
this._overrideResponseNumberFieldsCheck = overrideResponseNumberFieldsCheck;
}
public Boolean getOverrideResponseNumberFieldsCheck() {
return _overrideResponseNumberFieldsCheck;
}
public void setResponseManager(IResponseManager responseManager) {
this._responseManager = responseManager;
}
protected IResponseManager getResponseManager() {
return _responseManager;
}
public void setTitles(ApsProperties titles) {
this._titles = titles;
}
public ApsProperties getTitles() {
return _titles;
}
public void setQuestion(Question question) {
this._question = question;
}
public Question getQuestion() {
return _question;
}
// management variables
private Integer _strutsAction;
private Boolean _overrideResponseNumberFieldsCheck;
private Question _question;
private ApsProperties _titles = new ApsProperties(); // used when adding a new question
private ApsProperties _questions = new ApsProperties();
// field variables
private Integer _questionId;
private Integer _surveyId;
private Integer _pos;
private Integer _singleChoice;
private Integer _minResponseNumber;
private Integer _maxResponseNumber;
private List<Choice> _choices;
private Map<Integer, Integer> _choiceStats;
// managers
private IResponseManager _responseManager;
}