package net.sf.egonet.web.page;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
import java.util.Iterator;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.link.Link;
import com.google.common.collect.Lists;
import net.sf.egonet.model.Alter;
import net.sf.egonet.model.Answer;
import net.sf.egonet.model.Question;
import net.sf.egonet.persistence.Answers;
import net.sf.egonet.persistence.Interviewing;
import net.sf.egonet.persistence.Interviews;
import net.sf.egonet.web.panel.AnswerFormFieldPanel;
import net.sf.egonet.web.panel.InterviewingPanel;
import static net.sf.egonet.web.page.InterviewingQuestionIntroPage.possiblyReplaceNextQuestionPageWithPreface;
public class InterviewingAlterPairPage extends InterviewingPage {
public static class Subject implements Serializable, Comparable<Subject> {
// TODO: need a way for one of these to represent a question intro: firstAlter -> null
public Long interviewId;
public Question question;
public ArrayList<Question> questionList; // used for multiple questions per page
public Alter firstAlter;
public ArrayList<Alter> secondAlters; // only one alter when not list style, never empty
public TreeSet<Question> sectionQuestions;
public Alter getSecondAlter() {
return question.getAskingStyleList() ? null : secondAlters.get(0);
}
@Override
public String toString() {
return question.getType()+" : "+question.getTitle()+" : "+firstAlter.getName()+
(getSecondAlter() == null ? "" : " : "+getSecondAlter().getName());
}
@Override
public int hashCode() {
return question.hashCode()+firstAlter.hashCode()+
(question.getAskingStyleList() ? 0 : getSecondAlter().hashCode());
}
@Override
public boolean equals(Object object) {
return object instanceof Subject && equals((Subject) object);
}
public boolean equals(Subject subject) {
return interviewId.equals(subject.interviewId) &&
question.equals(subject.question) &&
firstAlter.equals(subject.firstAlter) &&
(question.getAskingStyleList() || getSecondAlter().equals(subject.getSecondAlter()));
}
@Override
public int compareTo(Subject subject) {
if(sectionQuestions.contains(subject.question)) {
int firstAlterCompare = firstAlter.compareTo(subject.firstAlter);
if(firstAlterCompare != 0) {
return firstAlterCompare;
}
boolean list = question.getAskingStyleList() || subject.question.getAskingStyleList();
int secondAlterCompare = list ? 0 : getSecondAlter().compareTo(subject.getSecondAlter());
if(secondAlterCompare != 0) {
return secondAlterCompare;
}
}
return question.compareTo(subject.question);
}
public Question lastQuestionInList() {
if ( questionList==null || questionList.isEmpty())
return(null);
return ( questionList.get(questionList.size()-1));
}
public Question firstQuestionInList() {
if ( questionList==null || questionList.isEmpty())
return(null);
return ( questionList.get(0));
}
}
private Subject subject;
private InterviewingPanel interviewingPanel;
private boolean gotoNextUnAnswered;
private boolean multipleQuestionsPerPage;
public InterviewingAlterPairPage(Subject subject)
{
super(subject.interviewId);
this.subject = subject;
gotoNextUnAnswered = multipleQuestionsPerPage = false;
build();
setQuestionId("Question: " + subject.question.getTitle());
}
private void build() {
Button nextUnanswered;
Form form = new Form("form") {
public void onSubmit() {
onSave(gotoNextUnAnswered);
}
};
nextUnanswered = new Button("nextUnanswered") {
public void onSubmit() {
gotoNextUnAnswered = true;
}
};
form.add(nextUnanswered);
ArrayList<AnswerFormFieldPanel> answerFields = Lists.newArrayList();
multipleQuestionsPerPage = getQuestionsForOnePage ( subject.question, subject );
if ( subject.secondAlters.size()==1 && multipleQuestionsPerPage ) {
// ArrayList<Alter> alters = Lists.newArrayList(subject.secondAlters.get(0));
ArrayList<Alter> alters = Lists.newArrayList(subject.firstAlter,subject.secondAlters.get(0));
for ( Question quest : subject.questionList ) {
Answer answer =
Answers.getAnswerForInterviewQuestionAlters(Interviews.getInterview(subject.interviewId),
quest, alters);
if(answer == null) {
answerFields.add(AnswerFormFieldPanel.getInstance("question", quest, alters, subject.interviewId));
} else {
answerFields.add(AnswerFormFieldPanel.getInstance("question",
quest, answer.getValue(), answer.getOtherSpecifyText(), answer.getSkipReason(), alters, subject.interviewId));
}
}
interviewingPanel = new InterviewingPanel("interviewingPanel",answerFields,subject.interviewId);
} else {
for(Alter secondAlter : subject.secondAlters) {
ArrayList<Alter> alters = Lists.newArrayList(subject.firstAlter,secondAlter);
Answer answer =
Answers.getAnswerForInterviewQuestionAlters(
Interviews.getInterview(subject.interviewId),
subject.question, alters);
if(answer == null) {
answerFields.add(
AnswerFormFieldPanel.getInstance("question",
subject.question, alters, subject.interviewId));
} else {
answerFields.add(
AnswerFormFieldPanel.getInstance("question",
subject.question, answer.getValue(), answer.getOtherSpecifyText(),
answer.getSkipReason(), alters, subject.interviewId));
}
if(! answerFields.isEmpty()) {
answerFields.get(0).setAutoFocus();
}
}
interviewingPanel =
new InterviewingPanel("interviewingPanel",subject.question,answerFields,subject.interviewId);
}
form.add(interviewingPanel);
add(form);
add(new Link("backwardLink") {
public void onClick() {
EgonetPage page =
askPrevious(subject.interviewId,subject,new InterviewingAlterPairPage(subject));
if(page != null) {
setResponsePage(page);
}
}
});
Link forwardLink = new Link("forwardLink") {
public void onClick() {
EgonetPage page =
askNext(subject.interviewId,subject,false,new InterviewingAlterPairPage(subject));
if(page != null) {
setResponsePage(page);
}
}
};
add(forwardLink);
if(! AnswerFormFieldPanel.okayToContinue(answerFields,interviewingPanel.pageFlags())) {
forwardLink.setVisible(false);
nextUnanswered.setVisible(false);
}
}
/**
* both the "Next Question" and "Next UnAnswered Question" buttons call this
* to save the current data and advance
* @param gotoNextUnAnswered if true proceed to next UNANSWERED question
* if false proceed to next questions
*/
public void onSave(boolean gotoNextUnAnswered) {
List<String> pageFlags = interviewingPanel.pageFlags();
ArrayList<AnswerFormFieldPanel> answerFields = interviewingPanel.getAnswerFields();
boolean okayToContinue =
AnswerFormFieldPanel.okayToContinue(answerFields, pageFlags);
boolean consistent =
AnswerFormFieldPanel.allConsistent(answerFields, pageFlags);
boolean multipleSelectionsOkay =
AnswerFormFieldPanel.allRangeChecksOkay(answerFields);
for(AnswerFormFieldPanel answerField : answerFields) {
if ( !multipleSelectionsOkay ) {
answerField.setNotification(answerField.getRangeCheckNotification());
} else if(okayToContinue) {
Answers.setAnswerForInterviewQuestionAlters(
subject.interviewId, /*subject.question*/ answerField.getQuestion(), answerField.getAlters(),
answerField.getAnswer(), answerField.getOtherText(),
answerField.getSkipReason(pageFlags));
} else if(consistent) {
answerField.setNotification(
answerField.answeredOrRefused(pageFlags) ?
"" : "Unanswered");
} else {
answerField.setNotification(
answerField.consistent(pageFlags) ?
"" : answerField.inconsistencyReason(pageFlags));
}
}
if(okayToContinue) {
if (gotoNextUnAnswered) {
setResponsePage(
askNext(subject.interviewId,subject,true,new InterviewingAlterPairPage(subject)));
} else {
EgonetPage page =
askNext(subject.interviewId,subject,false,new InterviewingAlterPairPage(subject));
if(page != null) {
setResponsePage(page);
}
}
}
}
public String toString() {
return subject.toString();
}
public static EgonetPage askNext(
Long interviewId, Subject currentPage, boolean unansweredOnly, EgonetPage comeFrom)
{
// to move forward we need to start searching on the last question
if ( currentPage!=null && currentPage.questionList != null )
currentPage.question = currentPage.lastQuestionInList();
Subject nextSubject =
Interviewing.nextAlterPairPageForInterview(interviewId, currentPage, true, unansweredOnly);
if(nextSubject != null) {
EgonetPage nextPage = new InterviewingAlterPairPage(nextSubject);
return possiblyReplaceNextQuestionPageWithPreface(
interviewId,nextPage,
currentPage == null ? null : currentPage.question,
nextSubject.question,
comeFrom,nextPage);
}
return InterviewingNetworkPage.askNext(interviewId, null, comeFrom);
}
public static EgonetPage askPrevious(Long interviewId, Subject currentSubject, EgonetPage comeFrom) {
// to move backward we need to start searching on the first question
if ( currentSubject!=null && currentSubject.questionList != null )
currentSubject.question = currentSubject.firstQuestionInList();
Subject previousSubject =
Interviewing.nextAlterPairPageForInterview(interviewId, currentSubject, false, false);
EgonetPage previousPage =
previousSubject != null ?
new InterviewingAlterPairPage(previousSubject) :
InterviewingAlterPage.askPrevious(interviewId, null, comeFrom);
return possiblyReplaceNextQuestionPageWithPreface(
interviewId,previousPage,
previousSubject == null ? null : previousSubject.question,
currentSubject == null ? null : currentSubject.question,
previousPage,comeFrom);
}
/**
* the subject has a treeSet sectionQuestions, which is the group of questions this
* question (firstQuestion) belongs to. The end of the group is the last question within
* this treeset. Some questions might have a 'keepOnSamePage' flag set, and we will want to
* group all of those together into an array of answerPanels.
* @param firstQuestion - just what is says, first question on this 'page'
* @param subject - an object with a question and an alter and the listOfQuestions
* @return true if we will need to display more than one question
*/
private boolean getQuestionsForOnePage ( Question firstQuestion, Subject subject ) {
Iterator<Question> iter;
Question question;
boolean moreThanOne = false;
boolean hit = false;
boolean done = false;
subject.questionList = new ArrayList<Question>();
// If we don't allow multipe questions per page,
// just return a list with one Question and a false value
if ( !Question.ALLOW_MULTIPLE_QUESTIONS_PER_PAGE ) {
subject.questionList.add(firstQuestion);
return(false);
}
iter = subject.sectionQuestions.iterator();
while ( iter.hasNext() && !done ) {
question = iter.next();
if ( question.equals(firstQuestion)) {
subject.questionList.add(question);
hit = true;
} else if (hit) {
if ( question.getKeepOnSamePage()) {
subject.questionList.add(question);
moreThanOne = true;
} else {
done = true;
}
}
}
// in a similar manner, if we are going backwards and are on
// a question that needs to stay on the same page as the previous one,
// we will need to go back
if ( firstQuestion.getKeepOnSamePage()) {
iter = subject.sectionQuestions.descendingIterator();
hit = done = false;
while ( iter.hasNext() && !done ) {
question = iter.next();
if ( question.equals(firstQuestion)) {
hit = true;
} else if (hit) {
if ( question.getKeepOnSamePage()) {
subject.questionList.add(0,question);
moreThanOne = true;
} else {
subject.questionList.add(0,question);
moreThanOne = true;
done = true;
}
}
}
}
// System.out.println ( "Exitting InterviewingAlterPage.getQuestionsForOnePage");
// for ( Question q : subject.questionList) {
// System.out.println ( "Contains " + q.getTitle());
// }
return(moreThanOne);
}
}