package org.javarosa.form.api;

import org.javarosa.core.model.FormIndex;
import org.javarosa.core.model.data.AnswerDataFactory;
import org.javarosa.core.model.data.IAnswerData;
import org.javarosa.core.model.data.UncastData;

/**
 * Replay form entry session. Steps through form, applying answers from the
 * session to corresponding questions by matching form indices. Replay aborts
 * if form indices don't match and stops when the session is empty.
 *
 * @author Phillip Mates (pmates@dimagi.com).
 */
public class FormEntrySessionReplayer {
    private final FormEntrySession formEntrySession;
    private final FormEntryController formEntryController;

    private FormEntrySessionReplayer(FormEntryController formEntryController,
                                     FormEntrySession formEntrySession) {
        this.formEntryController = formEntryController;
        this.formEntrySession = formEntrySession;
    }

    public static void tryReplayingFormEntry(FormEntryController formEntryController,
                                             FormEntrySession formEntrySession) {
        FormEntrySessionReplayer replayer =
                new FormEntrySessionReplayer(formEntryController, formEntrySession);
        if (replayer.isRestoringFormSession()) {
            replayer.replayForm();
        }
    }

    private boolean isRestoringFormSession() {
        return formEntrySession != null && formEntrySession.size() > 0;
    }

    private void replayForm() {
        formEntryController.jumpToIndex(FormIndex.createBeginningOfFormIndex());
        int event = formEntryController.stepToNextEvent(FormEntryController.STEP_INTO_GROUP);
        while (event != FormEntryController.EVENT_END_OF_FORM && isRestoringFormSession()) {
            replayEvent(event);
            event = formEntryController.stepToNextEvent(FormEntryController.STEP_INTO_GROUP);
        }
    }

    private void replayEvent(int event) {
        if (event == FormEntryController.EVENT_QUESTION) {
            replayQuestion();
        } else if (event == FormEntryController.EVENT_PROMPT_NEW_REPEAT) {
            if (formEntrySession.peekAction().isNewRepeatAction()) {
                formEntryController.newRepeat();
                while (formEntrySession.peekAction().isNewRepeatAction()) {
                    formEntrySession.popAction();
                }
            }
            // TODO PLM: can't handle proceeding to end of form after "Don't add" action
        }
    }

    private void replayQuestion() {
        FormIndex questionIndex = formEntryController.getModel().getFormIndex();
        FormEntrySession.FormEntryAction action = formEntrySession.peekAction();

        if (!questionIndex.toString().equals(action.formIndexString)) {
            throw new ReplayError("Unable to replay form due to incorrect question index");
        }

        if (action.isSkipAction()) {
            formEntrySession.popAction();
            return;
        }
        while (questionIndex.toString().equals(formEntrySession.peekAction().formIndexString)) {
            action = formEntrySession.popAction();
            FormEntryPrompt entryPrompt =
                    formEntryController.getModel().getQuestionPrompt(questionIndex);
            IAnswerData answerData =
                    AnswerDataFactory.template(entryPrompt.getControlType(),
                            entryPrompt.getDataType()).cast(new UncastData(action.value));
            formEntryController.answerQuestion(questionIndex, answerData);
        }
    }

    public static class ReplayError extends RuntimeException {
        public ReplayError(String msg) {
            super(msg);
        }
    }
}

@@ -2224,21 +2224,18 @@
         
-while
+if
  (formEn
@@ -2680,17 +2680,16 @@
     if (
-!
 question
@@ -2747,107 +2747,8 @@
     
-        throw new ReplayError(%22Unable to replay form due to incorrect question index%22);%0A        %7D%0A%0A
     
@@ -2772,32 +2772,36 @@
 SkipAction()) %7B%0A
+    
             form
@@ -2842,123 +2842,21 @@
     
-return;%0A        %7D%0A        while (questionIndex.toString().equals(formEntrySession.peekAction().formIndexString)) %7B%0A
+%7D else %7B%0A    
     
@@ -2906,32 +2906,36 @@
 ();%0A            
+ 
+   
 FormEntryPrompt 
@@ -2948,16 +2948,20 @@
 rompt =%0A
+    
         
@@ -3037,16 +3037,20 @@
 Index);%0A
+    
         
@@ -3098,16 +3098,20 @@
         
+    
 AnswerDa
@@ -3159,16 +3159,20 @@
 Type(),%0A
+    
         
@@ -3250,24 +3250,28 @@
 on.value));%0A
+    
             
@@ -3333,16 +3333,139 @@
 rData);%0A
+            %7D%0A        %7D else %7B%0A            throw new ReplayError(%22Unable to replay form due to incorrect question index%22);%0A
         

Remove while loop from form entry replaying