1
2
3
4 package org.telscenter.pas.steps;
5
6 import java.awt.BorderLayout;
7 import java.awt.Color;
8 import java.awt.Component;
9 import java.io.IOException;
10 import java.io.StringReader;
11 import java.util.ArrayList;
12 import java.util.Date;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.logging.Level;
18 import java.util.logging.Logger;
19
20 import javax.swing.BorderFactory;
21 import javax.swing.JComponent;
22 import javax.swing.JLabel;
23 import javax.swing.JPanel;
24 import javax.swing.JTextArea;
25 import javax.swing.border.CompoundBorder;
26
27 import net.sf.sail.core.entity.ISock;
28 import net.sf.sail.core.entity.ISockEntry;
29
30 import org.telscenter.pas.beans.IWorkReporter;
31 import org.telscenter.pas.beans.PasProject;
32 import org.telscenter.pas.beans.PasStep;
33 import org.telscenter.pas.service.INavigationService;
34 import org.telscenter.pas.steps.actions.ChallengeQuestionCheckAction;
35 import org.telscenter.pas.steps.domain.BlockInteraction;
36 import org.telscenter.pas.steps.domain.ChoiceInteraction;
37 import org.telscenter.pas.steps.domain.ResponseDeclaration;
38 import org.telscenter.pas.steps.domain.SimpleChoice;
39 import org.telscenter.pas.ui.pdf.PDFUtil;
40 import org.telscenter.pas.ui.util.PasColors;
41
42 import com.lowagie.text.Element;
43 import com.lowagie.text.Font;
44 import com.lowagie.text.Paragraph;
45 import com.lowagie.text.html.simpleparser.HTMLWorker;
46 import com.lowagie.text.html.simpleparser.StyleSheet;
47 import com.lowagie.text.pdf.PdfPCell;
48 import com.lowagie.text.pdf.PdfPTable;
49
50 /***
51 * Implement of the Pas step type, <i>ChallengeQuestion</i>.
52 *
53 * @author Jerry Cheung
54 * @author Hiroki Terashima
55 * @author turadg
56 */
57 public class ChallengeQuestion extends Assessment {
58 /***
59 * Logger for this class
60 */
61 private static final Logger logger = Logger
62 .getLogger(ChallengeQuestion.class.getName());
63
64
65 private int gotoStepIndex;
66
67
68 private PasStep gotoStep;
69
70
71
72
73
74
75 private List<Integer> scores = new ArrayList<Integer>();
76
77
78
79 private String scoringMode;
80
81
82
83 private int maxAttempts;
84
85
86 private List<JPanel> stepParts = new ArrayList<JPanel>();
87
88
89
90 public static final String indexes[] = { "1st", "2nd", "3rd", "4th", "5th",
91 "6th", "7th", "8th", "9th", "10th" };
92
93
94 private ChallengeQuestionUI cqUI;
95
96
97
98 private INavigationService navigationService;
99
100
101
102 private PasProject pasProject;
103
104
105
106 private String choiceOrdering;
107
108
109 public ChallengeQuestion() {
110 }
111
112
113 @Override
114 public String getType() {
115 return "Challenge Question";
116 }
117
118 /***
119 * The entry method to CQ. This method gets called when the step is visited
120 * If the evidence step has not been visited before visiting this CQ step,
121 * display a message to go back to the step
122 *
123 * @return visual representation of the Challenge Question
124 */
125 @Override
126 public Component getComponent() {
127 if (cqUI == null)
128 cqUI = new ChallengeQuestionUI(this);
129
130 cqUI.getGotoStepButton().setVisible(false);
131
132
133
134
135
136
137
138
139
140 ISock<String> lastAnswerSock = getLastAnswerSock();
141 if (lastAnswerSock != null && !lastAnswerSock.isEmpty()) {
142 if (isStudentAnswerCorrect(lastAnswerSock)
143 || (numStudentAttempts() >= scores.size())) {
144 ChallengeQuestionCheckAction cqAction = cqUI.getCQCheckAction();
145 cqAction.doCheckAndUpdate();
146 return cqUI;
147 }
148 }
149
150
151
152
153
154
155 JPanel panel = panelToReviewEvidencePage();
156 if (panel != null)
157 return panel;
158
159
160
161
162 cqUI.updateCqUI_Interactions();
163 return cqUI;
164 }
165
166 /***
167 * This method determines whether the goto step (i.e. evidence step) for
168 * this challenge question has been visited at all, or has been visited
169 * since the last visit to that CQ step. If either of these has not
170 * occurred, a message will be displayed in the VLE asking the user to
171 * review the evidence step again before seeing the CQ again.
172 *
173 * @return panel
174 */
175 private JPanel panelToReviewEvidencePage() {
176 JPanel panel = null;
177
178
179 if (!isGotoStepEverVisited()) {
180 panel = new JPanel();
181 panel
182 .add(new JLabel(
183 "Please review earlier evidence steps in this project before starting this Challenge Question."));
184 return panel;
185 }
186
187
188
189
190 ISock<String> lastAnswerSock = getLastAnswerSock();
191 if (lastAnswerSock != null && !lastAnswerSock.isEmpty()
192 && !isStudentAnswerCorrect(lastAnswerSock)) {
193 if (!isGotoStepVisitedSinceLastWrongAnswer()) {
194
195
196 panel = new JPanel();
197 panel
198 .add(new JLabel(
199 "Please review the evidence page before trying this Challenge Question."));
200 return panel;
201 }
202 }
203 return null;
204
205 }
206
207
208
209
210
211 /***
212 * Returns a PDF-version of the report
213 *
214 * @see org.telscenter.pas.steps.ChallengeQuestion#getReportForLearnerPDF()
215 */
216 public PdfPCell getReportForLearnerPDF(boolean withAnnotations) {
217 if (logger.isLoggable(Level.CONFIG)) {
218 logger.config("start");
219 }
220
221 int defaultFont = Font.TIMES_ROMAN;
222 PdfPTable table = PDFUtil.createStepTitle(this.getTitle());
223 PdfPTable questionAnswerTable = new PdfPTable(1);
224
225 List<ResponseDeclaration> reponseDeclarations = assessmentItem
226 .getResponseDeclarations();
227
228 if (reponseDeclarations.isEmpty()) {
229 PdfPCell noNoteTaken = new PdfPCell(new Paragraph(Messages
230 .getString("Note.NOTE_NOT_TAKEN")));
231
232 } else {
233 PdfPCell questionAnswerTableCell = null;
234 Font font = new Font(defaultFont, 14, Font.NORMAL);
235 font.setColor(PasColors.showAllWorkTextColor);
236 for (ResponseDeclaration rd : reponseDeclarations) {
237 BlockInteraction bi = getInteractionByResponseDeclaration(rd);
238 String prompt = null;
239 String answer = null;
240
241 if (bi == null) {
242 prompt = null;
243 } else {
244 prompt = bi.getPrompt();
245 }
246
247 PdfPCell noteQuestionCell = null;
248 if (prompt == null) {
249 prompt = Messages.getString("Note.ERROR_PROMPT_NOT_FOUND");
250
251 noteQuestionCell = new PdfPCell(new Paragraph(prompt, font));
252 noteQuestionCell.setBorderWidthBottom(0.0f);
253 noteQuestionCell.setGrayFill(0.8f);
254 } else {
255
256 StringReader stringReader = new StringReader(prompt);
257 List<Element> p = null;
258 try {
259 StyleSheet st = new StyleSheet();
260 st.loadTagStyle("body", "face", "Times New Roman");
261
262 st.loadTagStyle("body", "font-size", "6,0");
263
264 p = HTMLWorker.parseToList(stringReader, st);
265
266 } catch (IOException e) {
267 e.printStackTrace();
268 }
269
270 stringReader.close();
271
272 noteQuestionCell = new PdfPCell();
273 for (Element e : p) {
274 noteQuestionCell.addElement(e);
275 }
276
277 noteQuestionCell.setBorderWidthBottom(0.0f);
278 noteQuestionCell.setGrayFill(0.8f);
279
280
281
282
283
284
285
286
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315 if (bi == null) {
316 answer = null;
317 } else {
318 answer = lastAnswer(this.getResponseDeclarationToSocks(),
319 rd);
320 }
321
322 if (answer == null) {
323 answer = Messages.getString("Note.NOT_ANSWERED");
324 } else if (bi instanceof ChoiceInteraction) {
325 ChoiceInteraction<String> ci = (ChoiceInteraction<String>) bi;
326
327 List<SimpleChoice<String>> simpleChoices = ci.getSimpleChoices();
328 for (SimpleChoice<String> choice : simpleChoices) {
329 if (choice.getIdentifier().equals(answer)) {
330 answer = choice.getContent();
331 }
332 }
333 }
334
335 PdfPCell noteAnswerCell = new PdfPCell(new Paragraph(answer,
336 font));
337 noteAnswerCell.setBorderWidthTop(0.0f);
338
339 questionAnswerTable.addCell(noteQuestionCell);
340 questionAnswerTable.addCell(noteAnswerCell);
341
342 questionAnswerTableCell = new PdfPCell(questionAnswerTable);
343 questionAnswerTableCell.setPaddingLeft(9.0f);
344 questionAnswerTableCell.setBorderWidth(0.0f);
345
346 }
347 table.addCell(questionAnswerTableCell);
348 }
349 PdfPCell mainCell = new PdfPCell(table);
350
351 mainCell.setBorder(0);
352
353 if (logger.isLoggable(Level.CONFIG)) {
354 logger.config("end");
355 }
356
357
358 return mainCell;
359
360
361
362 }
363
364 /*** *********************************************************************************** */
365 /***
366 * ******************************* GOTO EVIDENCE STEP
367 * **********************************************************
368 */
369 /***
370 * Checks if gotoStep has ever been visited
371 *
372 * @return true iff the gotoStep has ever been visited (at least once)
373 * before visiting this Challenge Question step
374 */
375 public boolean isGotoStepEverVisited() {
376 if (getLastGotoStepVisitedSockEntry() == null) {
377 return false;
378 }
379 return true;
380 }
381
382 /***
383 * Checks if gotoStep has ever been visited
384 *
385 * @return true iff the gotoStep has ever been visited (at least once)
386 * before visiting this Challenge Question step
387 */
388 public ISockEntry<String> getLastGotoStepVisitedSockEntry() {
389 ISock<String> navigationLogSock = getPasProject()
390 .getNavigationLogSock();
391 ISockEntry<String> lastGotoStepVisitSockEntry = null;
392
393 if (navigationLogSock != null) {
394 Object gotoStepElement = getPasProject().getItemLog("step_open",
395 getGotoStep());
396 Iterator<ISockEntry<String>> iter = navigationLogSock
397 .entryIterator();
398 while (iter.hasNext()) {
399
400 ISockEntry<String> logElement = iter.next();
401 if (logElement.getValue().equals(gotoStepElement)) {
402 lastGotoStepVisitSockEntry = logElement;
403 }
404 }
405 }
406 return lastGotoStepVisitSockEntry;
407 }
408
409 /***
410 * Checks if gotoStep has been visited between the last time this step was
411 * visited and now This must only be called if the last answer was wrong
412 *
413 * @return true iff the gotoStep has been visited (at least once) between
414 * the last time this ChallengeQuestion step was visited until now
415 */
416 public boolean isGotoStepVisitedSinceLastWrongAnswer() {
417
418 ISock<String> lastWrongAnswerSock = getLastAnswerSock();
419 Iterator<ISockEntry<String>> entryIterator = lastWrongAnswerSock.entryIterator();
420 ISockEntry<String> lastSockEntry = null;
421 while (entryIterator.hasNext()) {
422 lastSockEntry = entryIterator.next();
423 }
424 Date lastWrongAnswerEntryDate = lastSockEntry.getDate();
425
426 ISockEntry<String> lastGotoStepVisitSockEntry = getLastGotoStepVisitedSockEntry();
427 if (lastGotoStepVisitSockEntry == null) {
428 return false;
429 }
430
431 Date lastGotoStepVisitDate = lastGotoStepVisitSockEntry.getDate();
432
433 return lastWrongAnswerEntryDate.before(lastGotoStepVisitDate);
434 }
435
436 /***
437 * ******************************* END GOTO EVIDENCE STEP
438 * ******************************************************
439 */
440
441 /***
442 * ************************************** ANSWER
443 * ******************************************
444 */
445
446 /***
447 * @return number of attempts that the student has made
448 */
449 public int numStudentAttempts() {
450
451 ResponseDeclaration rd = assessmentItem.getResponseDeclarations()
452 .get(0);
453 ISock<String> studentSock = this.getResponseDeclarationToSocks().get(rd);
454 if (studentSock == null) {
455 logger.severe("no sock available for rim declaration " + rd
456 + "\n so defaulting to ZERO for numStudentAttempts()");
457 return 0;
458 }
459 return studentSock.size();
460 }
461
462 /***
463 * @param rd
464 * @param bi
465 * @return answer - either stored in socks or whatever is retrieved from
466 * choice interaction
467 */
468 protected String getAnswer(ResponseDeclaration rd, BlockInteraction bi) {
469 String answer = lastAnswer(this.getResponseDeclarationToSocks(), rd);
470 if (answer == null) {
471 answer = Messages.getString("Note.NOT_ANSWERED");
472
473 } else if (bi instanceof ChoiceInteraction) {
474 ChoiceInteraction<String> ci = (ChoiceInteraction<String>) bi;
475 String scoreReport = this.getScoreReport();
476 if (scoreReport != null) {
477 answer = scoreReport;
478 } else {
479 List<SimpleChoice<String>> simpleChoices = ci.getSimpleChoices();
480 for (SimpleChoice<String> sc : simpleChoices) {
481 if (sc.getIdentifier().equals(answer)) {
482 answer = sc.getContent();
483 }
484 }
485 }
486 }
487 return answer;
488 }
489
490 /***
491 * TODO: refactor into utils along w/ lastAnswer
492 *
493 * retrieves correct answer based on the inline feedback
494 *
495 * @return corrAnswer
496 */
497 public String correctAnswer() {
498 ResponseDeclaration rd = assessmentItem.getResponseDeclarations()
499 .get(0);
500 return rd.getCorrectResponses().get(0);
501 }
502
503 /***
504 * retrieves last answer based on the data from student sock
505 *
506 */
507 public String lastAnswer() {
508 ResponseDeclaration rd = assessmentItem.getResponseDeclarations()
509 .get(0);
510 ISock<String> sock = this.getResponseDeclarationToSocks().get(rd);
511
512 if (sock == null) {
513 String errMsg = "no sock available for rim declaration " + rd
514 + "\n so returning null for lastAnswer()";
515 logger.severe(errMsg);
516 return null;
517 }
518
519 if (sock.isEmpty())
520 return null;
521
522 return sock.peek();
523 }
524
525 /***
526 * @param rd
527 * @return sock last answer from sock
528 */
529 public ISock<String> getLastAnswerSock() {
530 ResponseDeclaration rd = getAssessmentItem().getResponseDeclarations()
531 .get(0);
532 ISock<String> sock = getResponseDeclarationToSocks().get(rd);
533
534 if (sock == null) {
535 String errMsg = "no sock available for rim declaration " + rd
536 + "\n so returning null for lastAnswer()";
537 logger.severe(errMsg);
538 return null;
539 }
540
541 if (sock.isEmpty())
542 return null;
543
544 return sock;
545 }
546
547 /***
548 * Checks if student's answer in the provided sock is correct
549 *
550 * @param studentAnswerSock
551 * the Sock containing the student's answer
552 * @return true iff the first item in the sock contains a correct answer
553 * response
554 */
555 public boolean isStudentAnswerCorrect(ISock<String> studentAnswerSock) {
556 String studentAnswer = studentAnswerSock.peek();
557 Object correctAnswer = correctAnswer();
558 return correctAnswer.equals(studentAnswer);
559 }
560
561 /***
562 * ************************** ENDS ANSWER SECTION
563 * ************************************************
564 */
565 /*** *********************************************************************************************** */
566
567 /****************************************************************************
568 * SETTERS AND GETTERS - ACCESSOR METHODS ********************
569 *
570 * Methods: - getInteractionByResponseDeclaration - setCurrentStepPart,
571 * getStepParts - setScoringMode, getScoringMode - setScores, getScores -
572 * setGotoStepIndex, getGotoStepIndex - setGotoStep, getGotoStep -
573 * setScoreReport, getScoreReport - setMaxAttempts, getMaxAttempts -
574 * setCqUI, getCqUI - setNavigationService, getNavigationService -
575 * getPasProject, setPasProject - getChoiceOrdering, setChoiceOrdering -
576 * getCorrectFeedbackInline - getFeedbackContentFromChoices -
577 * getLastFeedbackInline
578 **************************************************************************/
579
580 /***
581 * @param rd
582 * @return
583 */
584 protected BlockInteraction getInteractionByResponseDeclaration(
585 ResponseDeclaration rd) {
586 BlockInteraction bi = Assessment.getInteractionByResponseDeclaration(
587 getAssessmentItem().getItemBody().getInteractions(), rd);
588 return bi;
589 }
590
591 /***
592 * @return stepParts
593 */
594 public List<JPanel> getStepParts() {
595 return this.stepParts;
596 }
597
598 /***
599 * @param currentPart
600 * adds the current step part to the list of steps' parts
601 */
602 private void setCurrentStepPart(JPanel currentPart) {
603 List<JPanel> stepParts = this.stepParts;
604 stepParts.add(currentPart);
605 this.stepParts = stepParts;
606 }
607
608 /***
609 * @return scoringMode
610 */
611 public String getScoringMode() {
612 return scoringMode;
613 }
614
615 /***
616 * @param scoringMode
617 * how the scoring is done - quantitative, qualitative, or off
618 */
619 public void setScoringMode(String scoringMode) {
620 this.scoringMode = scoringMode;
621 }
622
623 /***
624 * @return the scores
625 */
626 public List<Integer> getScores() {
627 return scores;
628 }
629
630 /***
631 * @param scores
632 * the scores to set
633 */
634 public void setScores(List<Integer> scores) {
635 logger.info("setScores");
636 if (scores == null)
637 throw new NullPointerException("null 'scores' argument'");
638 this.scores = scores;
639 }
640
641 /***
642 * @return the gotoStepIndex
643 */
644 public int getGotoStepIndex() {
645 return gotoStepIndex;
646 }
647
648 /***
649 * @param gotoStepIndex
650 * the gotoStepIndex to set
651 */
652 public void setGotoStepIndex(int gotoStepIndex) {
653 this.gotoStepIndex = gotoStepIndex;
654 }
655
656 /***
657 * @return the gotoStep
658 */
659 public PasStep getGotoStep() {
660 return gotoStep;
661 }
662
663 /***
664 * @param gotoStep
665 * the step to go to when reviewing evidence
666 */
667 public void setGotoStep(PasStep gotoStep) {
668 if (gotoStep == null)
669 throw new NullPointerException("null 'gotoStep' argument'");
670 this.gotoStep = gotoStep;
671 }
672
673 /***
674 * @return scoreReport
675 */
676 public String getScoreReport() {
677 Object correctAnswer = correctAnswer();
678 String reportText = null;
679 String lastAnswer = lastAnswer();
680 int sNumAttempts = numStudentAttempts();
681
682 if (correctAnswer.equals(lastAnswer)) {
683 reportText = getCorrectAnswerReport(sNumAttempts, scores, indexes);
684 } else if (sNumAttempts >= scores.size()) {
685 reportText = "Out of tries. 0 points.";
686 } else {
687 reportText = getWrongAnswerReport(sNumAttempts, scores, indexes);
688 }
689
690 if (reportText == null) {
691 String errMsg = "no score report available "
692 + "\n so returning null";
693 logger.severe(errMsg);
694 return null;
695 }
696
697 return reportText;
698 }
699
700 /***
701 * provides scorereport to be shown for correct answer by stating how many
702 * attempts (tries) have been made and how many points have been earned
703 *
704 *
705 * @param sNumAttempts
706 * @param scores
707 * @param initHtml
708 * @return reportText
709 */
710 protected String getCorrectAnswerReport(int sNumAttempts,
711 List<Integer> scores, String[] indexes) {
712 String reportText = null;
713 int index = sNumAttempts - 1;
714 String corrFeedback = indexes[index] + " try";
715
716 if (scores.get(index) > 0) {
717 reportText = corrFeedback + " earned you " + scores.get(index)
718 + " points.";
719 } else {
720 reportText = "Correct on " + corrFeedback + ".";
721 }
722 return reportText;
723 }
724
725 /***
726 * provides scorereport to be shown for wrong answer by stating how many
727 * attempts (tries) have been made and how many possible points are
728 * attainable (0 if that score attempt has a score of 0)
729 *
730 * @param sNumAttempts
731 * @param scores
732 * @param initHtml
733 * @param attmptFeedback
734 * @return reportText
735 */
736 private String getWrongAnswerReport(int sNumAttempts, List<Integer> scores,
737 String[] indexes) {
738 String reportText = null;
739 if (scores.get(sNumAttempts) > 0) {
740
741 reportText = indexes[sNumAttempts] + " try for "
742 + scores.get(sNumAttempts) + " points.";
743 } else {
744 reportText = indexes[sNumAttempts] + " try.";
745 }
746 return reportText;
747 }
748
749 /***
750 * @return the indexes of the attempts
751 */
752 public String[] getAttemptIndexes() {
753 return indexes;
754 }
755
756 /***
757 * @return the maxAttempts
758 */
759 public int getMaxAttempts() {
760 return maxAttempts;
761 }
762
763 /***
764 * @param maxAttempts
765 * the maxAttempts to set
766 */
767 public void setMaxAttempts(int maxAttempts) {
768 this.maxAttempts = maxAttempts;
769 }
770
771 /***
772 * @return the cqUI
773 */
774 public ChallengeQuestionUI getCqUI() {
775 return this.cqUI;
776 }
777
778 /***
779 * @param cqUI
780 * the cqUI to set
781 */
782 public void setCqUI(ChallengeQuestionUI cqUI) {
783 this.cqUI = cqUI;
784 }
785
786 /***
787 * @param navigationService
788 * navigation service for being able to retrieve, visit, and
789 * update steps in the navigation task panel
790 */
791 public void setNavigationService(INavigationService navigationService) {
792 this.navigationService = navigationService;
793
794 }
795
796 /***
797 * @return the navigationService
798 */
799 public INavigationService getNavigationService() {
800 return this.navigationService;
801 }
802
803 /***
804 * @return the pasProject
805 */
806 public PasProject getPasProject() {
807 return this.pasProject;
808 }
809
810 /***
811 * @param pasProject
812 * the pasProject to set
813 */
814 public void setPasProject(PasProject pasProject) {
815 this.pasProject = pasProject;
816 }
817
818 /***
819 * @param choiceOrdering -
820 * sets the variable for whether to reorder choices or not
821 */
822 public void setChoiceOrdering(String choiceOrdering) {
823 this.choiceOrdering = choiceOrdering;
824 }
825
826 /***
827 * @return choiceOrdering
828 */
829 public String getChoiceOrdering() {
830 return this.choiceOrdering;
831 }
832
833 /***
834 * returns the inline feedback if the chosen answer is the correct one
835 *
836 * @return newFeedbackInline
837 */
838 public String getCorrectFeedbackInline() {
839 List<BlockInteraction> theInteractions = assessmentItem.getItemBody()
840 .getInteractions();
841 ChoiceInteraction<String> interaction = (ChoiceInteraction<String>) theInteractions
842 .get(0);
843 List<SimpleChoice<String>> choices = interaction.getSimpleChoices();
844 String newFeedbackInline = getFeedbackContentFromChoices(choices);
845
846 return newFeedbackInline;
847 }
848
849 /***
850 * returns the inline feedback from the choices, choosing the one for the
851 * correct answer if the number of points for this attempt is greater than
852 * 0, the feedback would include saying that "you answered on the nth try
853 * for x points" where n is the number of attempts the user has made, and x
854 * is the number of points allotted for that attempt on a particular
855 * question, otherwise the part about the points is not included.
856 *
857 * @return newFeedbackInline
858 */
859 protected String getFeedbackContentFromChoices(List<SimpleChoice<String>> choices) {
860 String newFeedbackInline = "";
861
862 for (int i = 0; i < choices.size(); i++) {
863 String followupMessage = "You answered on the ";
864 int numTry = numStudentAttempts();
865 if (numTry == 0)
866 break;
867 List<Integer> scores = getScores();
868 String correctAnswer = correctAnswer();
869 if ((choices.get(i).getIdentifier()).equals(correctAnswer)) {
870 String origFeedbackInline = extractBody(choices.get(i)
871 .getFeedbackInline().getContent().toString());
872 if (scores.get(numTry - 1) > 0) {
873 newFeedbackInline = "<html><body>" + origFeedbackInline
874 + followupMessage + indexes[numTry - 1]
875 + " try for " + scores.get(numTry - 1) + " points."
876 + "</body></html>";
877 } else {
878 newFeedbackInline = "<html><body>" + origFeedbackInline
879 + followupMessage + indexes[numTry - 1]
880 + " try.</body></html>";
881 }
882 }
883
884 }
885 return newFeedbackInline;
886 }
887
888 /***
889 * returns the inline feedback for the last answer chosen
890 *
891 * @return newFeedbackInline
892 */
893 public String getLastFeedbackInline(Assessment assessment) {
894
895
896 ResponseDeclaration rd = assessmentItem.getResponseDeclarations()
897 .get(0);
898 String lastAnswer = Assessment.lastAnswer(assessment
899 .getResponseDeclarationToSocks(), rd);
900 List<BlockInteraction> theInteractions = assessmentItem.getItemBody()
901 .getInteractions();
902 ChoiceInteraction<String> interaction = (ChoiceInteraction<String>) theInteractions
903 .get(0);
904 List<SimpleChoice<String>> choices = interaction.getSimpleChoices();
905 String newFeedbackInline = "";
906
907 if (lastAnswer == null) {
908 throw new IllegalStateException(
909 "displayLastFeedbackInline() called while no lastAnswer() available");
910 }
911 for (int i = 0; i < choices.size(); i++) {
912 String followupMessage = "Click the evidence button below and review the earlier evidence. Then return to this Challenge Question for a ";
913 String finalFollowupMessage = "Sorry, you're out of tries. Move on to the next step.";
914 int numTry = numStudentAttempts();
915
916 if ((choices.get(i).getIdentifier()).equals(lastAnswer)) {
917 String origFeedbackInline = extractBody(choices.get(i)
918 .getFeedbackInline().getContent().toString());
919 if (numTry >= getMaxAttempts()) {
920 newFeedbackInline = "<html><body>" + origFeedbackInline
921 + finalFollowupMessage + "</body></html>";
922 } else {
923 newFeedbackInline = "<html><body>" + origFeedbackInline
924 + followupMessage + indexes[numTry] + " try."
925 + "</body></html>";
926 }
927 }
928 }
929 return newFeedbackInline;
930 }
931
932 /***
933 * @param responseDeclarations
934 * @param iterator
935 * @param filteredPrompt
936 * @param bi
937 */
938 private void setBiPrompt(List<ResponseDeclaration> responseDeclarations,
939 int iterator, BlockInteraction bi) {
940 String oldPrompt = bi.getPrompt();
941 int index = oldPrompt.indexOf("Part");
942 int index2 = oldPrompt.indexOf("Partner");
943 String filteredPrompt = extractBody(oldPrompt);
944
945 if (responseDeclarations.size() > 1) {
946 if ((index < 0) || (index == index2)) {
947 bi.setPrompt("<html><body> Part " + iterator + " : "
948 + filteredPrompt + "</body></html>");
949 } else {
950 bi
951 .setPrompt("<html><body>" + filteredPrompt
952 + "</body></html>");
953 }
954 } else {
955 bi.setPrompt("<html><body>" + filteredPrompt + "</body></html>");
956 }
957 }
958
959 /***
960 * Extracts the text in between the <body>...</body>
961 */
962 @Override
963 protected String extractBody(String prompt) {
964 int start = prompt.indexOf("<body>");
965 int end = prompt.indexOf("</body>");
966
967 String extractedBody = "";
968
969 if (start != -1 && end != -1) {
970 extractedBody = prompt.substring(start + 6, end);
971 return extractedBody;
972 }
973 return prompt;
974 }
975
976 /***
977 * @see org.telscenter.pas.beans.IWorkReporter#getEntityToPromptMap()
978 */
979 public Map<String, String> getEntityToPromptMap() {
980 Map<String, String> rimToPromptMap = new HashMap<String, String>();
981 List<ResponseDeclaration> responseDeclarations = assessmentItem
982 .getResponseDeclarations();
983 for (ResponseDeclaration responseDeclaration : responseDeclarations) {
984 String rimname = responseDeclaration.getRim().getName();
985 BlockInteraction bi = getInteractionByResponseDeclaration(responseDeclaration);
986 String prompt = bi.getPrompt();
987
988 rimToPromptMap.put(rimname, prompt);
989 }
990 return rimToPromptMap;
991 }
992
993
994 }