package org.mifos.application.questionnaire.struts;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.mifos.accounts.loan.struts.action.Criteria;
import org.mifos.application.util.helpers.ActionForwards;
import org.mifos.customers.client.util.helpers.ClientConstants;
import org.mifos.framework.util.helpers.Constants;
import org.mifos.framework.util.helpers.SessionUtils;
import org.mifos.platform.questionnaire.exceptions.BadNumericResponseException;
import org.mifos.platform.questionnaire.exceptions.MandatoryAnswerNotFoundException;
import org.mifos.platform.questionnaire.service.QuestionGroupDetail;
import org.mifos.platform.questionnaire.service.QuestionGroupDetails;
import org.mifos.platform.questionnaire.service.QuestionGroupInstanceDetail;
import org.mifos.platform.questionnaire.service.QuestionnaireServiceFacade;
import org.mifos.platform.util.CollectionUtils;
import org.mifos.platform.validations.ValidationException;
import org.mifos.security.util.UserContext;
public class QuestionnaireFlowAdapter {
private ActionForwards joinFlowAt;
private String event;
private String source;
private String cancelToURL;
private QuestionnaireServiceFacadeLocator serviceLocator;
private QuestionGroupFilter questionGroupFilter;
public QuestionnaireFlowAdapter(String event, String source, ActionForwards joinFlowAt, String cancelToURL,
QuestionnaireServiceFacadeLocator serviceLocator) {
this(event, source, joinFlowAt, cancelToURL, serviceLocator, getDefaultQuestionGroupFilter());
}
public QuestionnaireFlowAdapter(String event, String source, ActionForwards joinFlowAt, String cancelToURL,
QuestionnaireServiceFacadeLocator serviceLocator, QuestionGroupFilter questionGroupFilter) {
this.event = event;
this.source = source;
this.joinFlowAt = joinFlowAt;
this.cancelToURL = cancelToURL;
this.serviceLocator = serviceLocator;
this.questionGroupFilter = questionGroupFilter;
}
public ActionForward fetchAppliedQuestions(ActionMapping mapping, QuestionResponseCapturer form, HttpServletRequest request,
ActionForwards defaultForward) {
joinFlowAt = defaultForward;
if (CollectionUtils.isEmpty(form.getQuestionGroups())) {
List<QuestionGroupDetail> questionGroups = getQuestionGroups(request);
if (CollectionUtils.isEmpty(questionGroups)) {
//NOTE: this is done, because the ActionForm is stored in session and when recycled still has the previous questionGroup lists!
form.setQuestionGroups(null);
return mapping.findForward(defaultForward.toString());
}
/**
* TODO if user goes back before "joinFlowAt" and continues, then Question group capture form will be reinitialized!
* We can use the flowkey to check need for reset. consider modifying QuestionResponseCapturerForm set flowkey and
* then compare the request attribute's flowkey to check! Unfortunately, usage of flowkey may not be consistent!
* Another situation, although very unlikely, is admin associates another question group with event and source in the meantime!
* In that case, the questionGroups need to be merged!
*/
form.setQuestionGroups(questionGroups);
}
setQuestionnaireAttributesToRequest(request, form);
return mapping.findForward(ActionForwards.captureQuestionResponses.toString());
}
public ActionErrors validateResponses(HttpServletRequest request, QuestionResponseCapturer form) {
List<QuestionGroupDetail> groups = form.getQuestionGroups();
QuestionnaireServiceFacade questionnaireServiceFacade = serviceLocator.getService(request);
if ((groups == null) || (questionnaireServiceFacade == null)) {
return null;
}
ActionErrors errors = new ActionErrors();
try {
questionnaireServiceFacade.validateResponses(groups);
} catch (ValidationException e) {
if (e.hasChildExceptions()) {
for (ValidationException ve : e.getChildExceptions()) {
if (ve instanceof MandatoryAnswerNotFoundException) {
errors.add(ClientConstants.ERROR_REQUIRED, new ActionMessage(ClientConstants.ERROR_REQUIRED, ve.getIdentifier()));
} else if (ve instanceof BadNumericResponseException) {
populateNumericError((BadNumericResponseException) ve, errors);
}
}
}
}
setQuestionnaireAttributesToRequest(request, form);
return errors;
}
private void populateNumericError(BadNumericResponseException exception, ActionErrors actionErrors) {
String title = exception.getIdentifier();
Integer allowedMinValue = exception.getAllowedMinValue();
Integer allowedMaxValue = exception.getAllowedMaxValue();
if (exception.areMinMaxBoundsPresent()) {
ActionMessage actionMessage = new ActionMessage(ClientConstants.INVALID_NUMERIC_RANGE_RESPONSE, allowedMinValue, allowedMaxValue, title);
actionErrors.add(ClientConstants.INVALID_NUMERIC_RANGE_RESPONSE, actionMessage);
} else if (exception.isMinBoundPresent()) {
ActionMessage actionMessage = new ActionMessage(ClientConstants.INVALID_NUMERIC_MIN_RESPONSE, allowedMinValue, title);
actionErrors.add(ClientConstants.INVALID_NUMERIC_MIN_RESPONSE, actionMessage);
} else if (exception.isMaxBoundPresent()) {
ActionMessage actionMessage = new ActionMessage(ClientConstants.INVALID_NUMERIC_MAX_RESPONSE, allowedMaxValue, title);
actionErrors.add(ClientConstants.INVALID_NUMERIC_MAX_RESPONSE, actionMessage);
} else {
ActionMessage actionMessage = new ActionMessage(ClientConstants.INVALID_NUMERIC_RESPONSE, title);
actionErrors.add(ClientConstants.INVALID_NUMERIC_RESPONSE, actionMessage);
}
}
public void saveResponses(HttpServletRequest request, QuestionResponseCapturer form, int associateWithId) {
List<QuestionGroupDetail> questionResponses = form.getQuestionGroups();
if (CollectionUtils.isNotEmpty(questionResponses)) {
QuestionnaireServiceFacade questionnaireServiceFacade = serviceLocator.getService(request);
//MifosUser loggedinUser = ((MifosUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal());
if (questionnaireServiceFacade != null) {
UserContext userContext = (UserContext) SessionUtils.getAttribute(Constants.USER_CONTEXT_KEY, request.getSession());
Integer eventSourceId = questionnaireServiceFacade.getEventSourceId(event, source);
QuestionGroupDetails questionGroupDetails = new QuestionGroupDetails(userContext.getId(), associateWithId, eventSourceId, questionResponses);
questionnaireServiceFacade.saveResponses(questionGroupDetails);
}
}
}
public ActionForward rejoinFlow(ActionMapping mapping) {
return mapping.findForward(joinFlowAt.toString());
}
private Object getContextUri(HttpServletRequest request) {
return request.getRequestURI().replace(request.getContextPath(), "");
}
private List<QuestionGroupDetail> getQuestionGroups(HttpServletRequest request) {
QuestionnaireServiceFacade questionnaireServiceFacade = serviceLocator.getService(request);
Criteria<QuestionGroupDetail> criteria = new Criteria<QuestionGroupDetail>() {
@Override
public QuestionGroupDetail filter(Integer questionGroupId, List<QuestionGroupDetail> questionGroupDetails) {
QuestionGroupDetail result = null;
for (QuestionGroupDetail questionGroupDetail : questionGroupDetails) {
if (questionGroupId.equals(questionGroupDetail.getId())) {
result = questionGroupDetail;
break;
}
}
return result;
}
};
return questionnaireServiceFacade != null ? questionGroupFilter.doFilter(questionnaireServiceFacade.getQuestionGroups(event, source), criteria) : null;
}
public List<QuestionGroupInstanceDetail> getQuestionGroupInstances(HttpServletRequest request, Integer entityId) {
QuestionnaireServiceFacade questionnaireServiceFacade = serviceLocator.getService(request);
Criteria<QuestionGroupInstanceDetail> criteria = new Criteria<QuestionGroupInstanceDetail>() {
@Override
public QuestionGroupInstanceDetail filter(Integer questionGroupId, List<QuestionGroupInstanceDetail> questionGroupInstanceDetails) {
QuestionGroupInstanceDetail result = null;
for (QuestionGroupInstanceDetail questionGroupInstanceDetail : questionGroupInstanceDetails) {
if (questionGroupId.equals(questionGroupInstanceDetail.getQuestionGroupDetail().getId())) {
result = questionGroupInstanceDetail;
break;
}
}
return result;
}
};
return questionnaireServiceFacade != null ? questionGroupFilter.doFilter(questionnaireServiceFacade.
getQuestionGroupInstancesWithUnansweredQuestionGroups(entityId, event, source), criteria): new ArrayList<QuestionGroupInstanceDetail>();
}
private void setQuestionnaireAttributesToRequest(HttpServletRequest request, QuestionResponseCapturer form) {
request.setAttribute("questionsHostForm", form);
request.setAttribute("origFlowRequestURI", getContextUri(request));
request.setAttribute("cancelToURL", cancelToURL);
}
public ActionForward editResponses(ActionMapping mapping, HttpServletRequest request, QuestionResponseCapturer form) {
setQuestionnaireAttributesToRequest(request, form);
return mapping.findForward(ActionForwards.captureQuestionResponses.toString());
}
private static QuestionGroupFilter getDefaultQuestionGroupFilter() {
return new QuestionGroupFilter() {
@Override
public <T> List<T> doFilter(List<T> t, Criteria<T> criteria) {
return t; // no filtering by default
}
};
}
}