package fi.utu.ville.exercises.layout;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import fi.utu.ville.exercises.helpers.StandardSubmissionType;
import fi.utu.ville.exercises.model.SubmissionType;
import fi.utu.ville.standardutils.Localizer;
import fi.utu.ville.standardutils.StandardIcon.Icon;
import fi.utu.ville.standardutils.StandardUIFactory;
import fi.utu.ville.standardutils.UIConstants;
public class PhasedAssignmentController {
private final PhasedExecutor exec;
private int currentStep;
private final Step[] steps;
private boolean navigable;
private boolean retriable;
private final AssignmentProgressBar bar;
private final PhasedAssignmentNavigation navigator;
private final LayoutClickListener barListener;
private final Localizer localizer;
public PhasedAssignmentController(PhasedExecutor exec,
int numberOfSteps, boolean showCorrect,
boolean showPrev, Localizer localizer) {
this.exec = exec;
this.localizer = localizer;
steps = new Step[numberOfSteps];
for (int i = 0; i < steps.length; i++) {
steps[i] = new Step();
}
bar = new AssignmentProgressBar(steps, showCorrect);
navigator = new PhasedAssignmentNavigation(localizer, showPrev);
currentStep = 0;
bar.setCurrent(currentStep);
barListener = e -> stepTo(bar.getClickedIndex(e));
navigator.setNextButtonEnabled(false);
addNavigatorLogic();
}
//***** Public API *****//
public void setNavigable(boolean enabled) {
navigable = enabled;
navigator.setPrevButtonEnabled(navigable && currentStep > 0);
navigator.setPrevButtonVisible(navigable);
navigator.setNextButtonEnabled(navigable && currentStep < steps.length - 1);
}
public void setRetriable(boolean enabled) {
retriable = enabled;
navigator.setCheckButtonEnabled(retriable || !steps[currentStep].answered);
}
public void setClickNavigable(boolean enabled) {
if (enabled) {
bar.addLayoutClickListener(barListener);
bar.addStyleName("clickable");
} else {
bar.removeLayoutClickListener(barListener);
bar.removeStyleName("clickable");
}
}
public void showNumbers(boolean enabled) {
bar.setNumbersVisible(enabled);
}
public void reset() {
for (int i = 0; i < steps.length; i++) {
steps[i].answered = false;
steps[i].correct = false;
}
stepTo(0);
}
public Component getProgressBar() {
return bar;
}
public Component getNavigator() {
return navigator;
}
public void prev() {
stepTo(currentStep - 1);
}
public int getCurrentStep() {
return currentStep;
}
public boolean isAnswered(int index) {
return index >= 0
&& index < steps.length
&& steps[index].answered;
}
public void check() {
steps[currentStep].answered = true;
steps[currentStep].correct = exec.isCorrect(currentStep);
navigator.setCheckButtonEnabled(retriable);
if (currentStep < steps.length - 1) {
navigator.setNextButtonEnabled(true);
navigator.focusNext();
} else {
final Window confirm = new Window(localizer
.getUIText(UIConstants.SUBMIT_QUESTION));
confirm.setModal(true);
confirm.setWidth("600px");
confirm.setHeight("330px");
confirm.setCaption("");
confirm.setStyleName("opaque");
confirm.addStyleName("unclosable-window");
confirm.setClosable(false);
confirm.addStyleName("submit-window");
VerticalLayout content = new VerticalLayout();
content.setSizeFull();
content.setMargin(true);
Label question = new Label(localizer
.getUIText(UIConstants.SUBMIT_QUESTION));
question.setContentMode(ContentMode.HTML);
question.addStyleName("big-text-white");
question.setSizeUndefined();
content.addComponent(question);
content.setComponentAlignment(question,
Alignment.TOP_CENTER);
confirm.setContent(content);
// Button holder (back to round, replay, next)
HorizontalLayout buttons = new HorizontalLayout();
buttons.addStyleName("submit-buttons-container");
buttons.setWidth("100%");
buttons.setSpacing(true);
content.addComponent(buttons);
content.setComponentAlignment(buttons,
Alignment.TOP_CENTER);
Button submit = StandardUIFactory
.getRoundButton(Icon.SUBMIT);
submit.setDescription(
localizer.getUIText(UIConstants.SUBMIT));
Button cancel = StandardUIFactory
.getRoundButton(Icon.CLOSE);
cancel.setDescription(
localizer.getUIText(UIConstants.CLOSE));
buttons.addComponents(submit, cancel);
buttons.setComponentAlignment(submit,
Alignment.MIDDLE_CENTER);
buttons.setComponentAlignment(cancel,
Alignment.MIDDLE_CENTER);
submit.addClickListener(e -> {
exec.askSubmit(StandardSubmissionType.NORMAL);
confirm.close();
});
cancel.addClickListener(e -> confirm.close());
UI.getCurrent().addWindow(confirm);
}
}
public void next() {
if (steps[currentStep].answered == false && !navigable) {
steps[currentStep].answered = true;
steps[currentStep].correct = exec.isCorrect(currentStep);
}
stepTo(currentStep + 1);
}
public void setCheckButtonVisible(boolean visible) {
navigator.setCheckButtonVisible(visible);
}
public void removeClickShortcuts() {
navigator.removeClickShortcuts();
}
/***** Private implementations *****/
private void addNavigatorLogic() {
navigator.addPrevButtonListener(e -> prev());
navigator.addCheckButtonListener(e -> {
check();
});
navigator.addNextButtonListener(e -> next());
}
private void stepTo(int step) {
if (step >= 0 && step < steps.length) {
currentStep = step;
bar.setCurrent(currentStep);
navigator.setNextButtonEnabled((currentStep < steps.length - 1)
&& (navigable || steps[currentStep].answered));
navigator.setPrevButtonEnabled(currentStep > 0);
navigator.setCheckButtonEnabled(retriable || !steps[currentStep].answered);
exec.drawProblem(currentStep);
}
}
public static class Step {
public boolean answered;
public boolean correct;
}
public interface PhasedExecutor {
public void drawProblem(int index);
public boolean isCorrect(int index);
public abstract void askSubmit(SubmissionType type);
}
}