/* * Copyright (c) 2005-2011 Grameen Foundation USA * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * See also http://www.apache.org/licenses/LICENSE-2.0.html for an * explanation of the license and how it is applied. */ package org.mifos.platform.questionnaire.ui.model; import org.apache.commons.lang.StringUtils; import org.mifos.platform.questionnaire.service.dtos.ChoiceDto; import org.mifos.platform.questionnaire.service.QuestionDetail; import org.mifos.platform.questionnaire.service.QuestionType; import org.mifos.platform.util.CollectionUtils; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import static org.apache.commons.lang.StringUtils.EMPTY; import static org.apache.commons.lang.StringUtils.isNotEmpty; import static org.mifos.platform.util.CollectionUtils.isEmpty; import static org.mifos.platform.util.MapEntry.makeEntry; @SuppressWarnings("PMD") public class Question implements Serializable { private static final long serialVersionUID = -2584259958410679795L; private static Map<String, QuestionType> stringToQuestionTypeMap; private static Map<QuestionType, String> questionTypeToStringMap; private QuestionDetail questionDetail; private String currentChoice; private String currentSmartChoice; @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="SE_BAD_FIELD") private List<String> currentSmartChoiceTags; private int initialNumberOfChoices; private String originalText; static { populateStringToQuestionTypeMap(); populateQuestionTypeToStringMap(); } public Question() { this(null); } public Question(QuestionDetail questionDetail) { this.questionDetail = questionDetail; this.currentSmartChoiceTags = new ArrayList<String>(); } @javax.validation.constraints.NotNull @javax.validation.constraints.Pattern(regexp="^.*[^\\s]+.*$") @javax.validation.constraints.Size(max = 1000) public String getText() { return questionDetail.getText(); } public void setText(String text) { questionDetail.setText(text); questionDetail.trimText(); } @javax.validation.constraints.Pattern(regexp="^.*[^\\s]+.*$") @javax.validation.constraints.NotNull public String getType() { return questionTypeToStringMap.get(questionDetail.getType()); } public void setType(String type) { questionDetail.setType(stringToQuestionTypeMap.get(type)); } public String getId() { return questionDetail.getId().toString(); } public void setId(String id) { questionDetail.setId(Integer.valueOf(id)); } public QuestionDetail getQuestionDetail() { return questionDetail; } public void setQuestionDetail(QuestionDetail questionDetail) { this.questionDetail=questionDetail; initializeSmartChoiceTags(); } public List<ChoiceDto> getChoices() { return this.questionDetail.getAnswerChoices(); } public String getCommaSeparateChoices() { return CollectionUtils.toString(this.questionDetail.getAnswerChoices()); } public String getCurrentChoice() { return currentChoice; } public void setCurrentChoice(String currentChoice) { this.currentChoice = currentChoice; } public void addAnswerChoice() { questionDetail.addAnswerChoice(new ChoiceDto(getCurrentChoice())); setCurrentChoice(null); currentSmartChoiceTags.add(EMPTY); } public void removeChoice(int choiceIndex) { questionDetail.removeAnswerChoice(choiceIndex); currentSmartChoiceTags.remove(choiceIndex); } public void removeChoiceTag(String choiceTagIndex) { String[] indices = choiceTagIndex.split("_"); int choiceIndex = Integer.valueOf(indices[0]); int tagIndex = Integer.valueOf(indices[1]); questionDetail.removeTagForChoice(choiceIndex, tagIndex); } public void addAnswerSmartChoice() { questionDetail.addAnswerChoice(new ChoiceDto(getCurrentSmartChoice())); currentSmartChoiceTags.add(EMPTY); setCurrentSmartChoice(null); } public void addSmartChoiceTag(int choiceIndex) { String currentSmartChoiceTag = getCurrentSmartChoiceTag(choiceIndex); if (isNotEmpty(currentSmartChoiceTag)) { questionDetail.addTag(choiceIndex, currentSmartChoiceTag); currentSmartChoiceTags.set(choiceIndex, EMPTY); } } public void setChoicesIfApplicable() { QuestionType type = questionDetail.getType(); if (!answerChoicesApplicableFor(type)) { resetChoices(); } } public boolean answerChoicesAreInvalid() { return answerChoicesApplicableFor(questionDetail.getType()) && getChoices().size() < 2; } public Integer getNumericMin() { return questionDetail.getNumericMin(); } public Integer getNumericMax() { return questionDetail.getNumericMax(); } public void setNumericMin(Integer numericMin) { questionDetail.setNumericMin(numericMin); } public void setNumericMax(Integer numericMax) { questionDetail.setNumericMax(numericMax); } public boolean numericBoundsAreInvalid() { boolean result = false; if (QuestionType.NUMERIC.equals(questionDetail.getType())) { Integer min = getNumericMin(); Integer max = getNumericMax(); result = min != null && max != null && min > max; } return result; } public String getCurrentSmartChoice() { return currentSmartChoice; } public void setCurrentSmartChoice(String currentSmartChoice) { this.currentSmartChoice = currentSmartChoice; } public List<String> getCurrentSmartChoiceTags() { return currentSmartChoiceTags; } public String getCurrentSmartChoiceTag(int index) { if (index >= currentSmartChoiceTags.size()) { currentSmartChoiceTags.add(EMPTY); } return currentSmartChoiceTags.get(index); } public boolean isSmartSelect() { return questionDetail.isSmartSelect(); } public int getInitialNumberOfChoices() { return initialNumberOfChoices; } public boolean isActive() { return questionDetail.isActive(); } public boolean isEditable() { return questionDetail.isEditable(); } public void setActive(boolean active) { questionDetail.setActive(active); } private boolean answerChoicesApplicableFor(QuestionType type) { return QuestionType.MULTI_SELECT.equals(type) || QuestionType.SINGLE_SELECT.equals(type) || QuestionType.SMART_SELECT.equals(type) || QuestionType.SMART_SINGLE_SELECT.equals(type); } private void resetChoices() { questionDetail.setAnswerChoices(new ArrayList<ChoiceDto>()); } private void initializeSmartChoiceTags() { List<ChoiceDto> choices = getChoices(); if (isEmpty(choices)) { choices = new ArrayList<ChoiceDto>(); } this.currentSmartChoiceTags = new ArrayList<String>(); this.initialNumberOfChoices = choices.size(); this.originalText = getText(); for (int i = 0; i < initialNumberOfChoices; i++) { this.currentSmartChoiceTags.add(EMPTY); } } private static void populateStringToQuestionTypeMap() { stringToQuestionTypeMap = CollectionUtils.asMap( makeEntry("freeText", QuestionType.FREETEXT), makeEntry("date", QuestionType.DATE), makeEntry("multiSelect", QuestionType.MULTI_SELECT), makeEntry("singleSelect", QuestionType.SINGLE_SELECT), makeEntry("smartSelect", QuestionType.SMART_SELECT), makeEntry("number", QuestionType.NUMERIC), makeEntry("smartSingleSelect", QuestionType.SMART_SINGLE_SELECT) ); } private static void populateQuestionTypeToStringMap() { questionTypeToStringMap = CollectionUtils.asMap( makeEntry(QuestionType.FREETEXT, "freeText"), makeEntry(QuestionType.DATE, "date"), makeEntry(QuestionType.NUMERIC, "number"), makeEntry(QuestionType.MULTI_SELECT, "multiSelect"), makeEntry(QuestionType.SMART_SELECT, "smartSelect"), makeEntry(QuestionType.SINGLE_SELECT, "singleSelect"), makeEntry(QuestionType.SMART_SINGLE_SELECT, "smartSingleSelect") ); } public boolean textHasChanged() { return !StringUtils.equals(originalText, getText()); } void setChoices() { setChoicesIfApplicable(); } public boolean isSmartChoiceDuplicated(int choiceIndex) { boolean result = false; String currentSmartChoiceTag = getCurrentSmartChoiceTag(choiceIndex); if (isNotEmpty(currentSmartChoiceTag)) { result = questionDetail.isSmartChoiceDuplicated(choiceIndex, currentSmartChoiceTag); } return result; } public boolean isTagsLimitReached(int choiceIndex) { return questionDetail.isTagsLimitReached(choiceIndex); } }