package edu.vserver.math;
import java.text.DecimalFormat;
import java.util.ArrayList;
import com.vaadin.server.ThemeResource;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Layout;
import com.vaadin.ui.Table;
import com.vaadin.ui.Table.ColumnResizeEvent;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.themes.BaseTheme;
import com.vaadin.ui.themes.ChameleonTheme;
import edu.vserver.exercises.math.essentials.layout.MathExerciseView;
import edu.vserver.exercises.math.essentials.layout.Problem;
import edu.vserver.exercises.math.essentials.layout.TimeStamp;
import edu.vserver.exercises.math.essentials.layout.TimeStampHandler;
import edu.vserver.exercises.math.essentials.level.DiffLevel;
import edu.vserver.exercises.math.essentials.level.LevelMathSubmissionInfo;
import fi.utu.ville.exercises.model.ExerciseData;
import fi.utu.ville.exercises.model.ExerciseException;
import fi.utu.ville.exercises.model.SubmissionVisualizer;
import fi.utu.ville.standardutils.Localizer;
import fi.utu.ville.standardutils.StandardIcon.Icon;
import fi.utu.ville.standardutils.TempFilesManager;
import fi.utu.ville.standardutils.UIConstants;
public abstract class AbstractMathTableSubmissionViewer<E extends ExerciseData, F extends LevelMathSubmissionInfo<G>, G extends Problem>
extends VerticalLayout implements SubmissionVisualizer<E, F> {
private static final long serialVersionUID = -1228022609075470958L;
private Table table;
private E exercise;
private F submInfo;
private Localizer localizer;
private DecimalFormat format;
private final String assignmentName;
private final String exerciseName;
public AbstractMathTableSubmissionViewer(String assignmentName,String exerciseName) {
this.assignmentName = assignmentName;
this.exerciseName = exerciseName;
}
// Abstract method for getting executor for each type of exercise.
protected abstract MathExerciseView<G> getExerView(E exerData, F submInfo);
@Override
public void initialize(E exercise, F dataObject, Localizer localizer,
TempFilesManager tempFilesManager) throws ExerciseException {
this.exercise = exercise;
this.submInfo = dataObject;
this.localizer = localizer;
format = new DecimalFormat("#.#");
doLayout();
}
@Override
public Layout getView() {
return this;
}
@Override
public String exportSubmissionDataAsText() {
return AbstractMathSubmissionViewer.getSimpleTextExport(exercise,
submInfo, localizer, "");
}
protected Embedded getDiffLevel() {
ThemeResource pic = new ThemeResource(
"../vexer-math/icons/star-gold-64.png");
if (submInfo.getDiffLevel() == DiffLevel.EASY) {
pic = new ThemeResource("../vexer-math/icons/star-bronze-64.png");
} else if (submInfo.getDiffLevel() == DiffLevel.NORMAL) {
pic = new ThemeResource("../vexer-math/icons/star-silver-64.png");
}
Embedded diffLevel = new Embedded(submInfo.getDiffLevel().name(), pic);
return diffLevel;
}
protected void doLayout() {
setSpacing(true);
setMargin(true);
setWidth("100%");
table = new Table();
table.addColumnResizeListener(new Table.ColumnResizeListener() {
/**
*
*/
private static final long serialVersionUID = -3535283813634437776L;
@Override
public void columnResize(ColumnResizeEvent event) {
// Get the new width of the resized column
int width = event.getCurrentWidth();
// Get the property ID of the resized column
String column = (String) event.getPropertyId();
// Do something with the information
table.setColumnFooter(column, String.valueOf(width) + "px");
}
});
// Must be immediate to send the resize events immediately
table.setImmediate(true);
// Common knowledge to all math problems:
// - Question
// - isCorrect
// - Correct answer
// - User's anwer
// - Correctness
// - Time on task
// - Time on answer
table.addStyleName(ChameleonTheme.TABLE_STRIPED);
table.addContainerProperty("Question", String.class, null);
table.setColumnHeader("Question",localizer.getUIText(UIConstants.QUESTION));
table.addContainerProperty("Given answer", String.class, null);
table.setColumnHeader("Given answer",localizer.getUIText(UIConstants.GIVEN_ANSWER));
table.addContainerProperty("Correct answer", String.class, null);
table.setColumnHeader("Correct answer",localizer.getUIText(UIConstants.CORRECT_ANSWER));
table.addContainerProperty("Time", String.class, null);
table.setColumnHeader("Time",localizer.getUIText(UIConstants.TIME));
table.addContainerProperty("Correctness", Label.class, null);
table.setColumnHeader("Correctness",localizer.getUIText(UIConstants.CORRECT));
// table.addContainerProperty("Timeline", Button.class, null);
// table.addContainerProperty("Show exercise", Button.class, null);
table.setColumnAlignment("Correctness", Table.Align.CENTER);
table.setCellStyleGenerator(new Table.CellStyleGenerator() {
private static final long serialVersionUID = -2373086824079035962L;
@Override
public String getStyle(Table source, Object itemId, Object propertyId) {
if(submInfo.getProblems().get((int)itemId).isCorrect()) {
return null;
}
if(!"Correctness".equals(propertyId)) {
return null;
}
return "background-red";
}
});
table.setWidth("650px");
int correctAnswers = 0;
int amount = submInfo.getProblems().size();
// Divided handlers
final ArrayList<TimeStampHandler> handlers = divideTimeStamps(submInfo
.getTimeStamps());
//int i = 0;
Double[] timesPerTask = new Double[handlers.size()];
for (int i = 0; i < handlers.size() && i < submInfo.getProblems().size(); i++) {
final G problem = submInfo.getProblems().get(i);
String time = timePerTask(handlers, i);
double t = 0;
try {
t = Double.parseDouble(time);
} catch (Exception e) {
// e.printStackTrace();
}
timesPerTask[i] = t;
Button showExercise = new Button("Show exercise");
showExercise.addStyleName(BaseTheme.BUTTON_LINK);
showExercise.addClickListener(new Button.ClickListener() {
/**
*
*/
private static final long serialVersionUID = 524295315804770796L;
@Override
public void buttonClick(ClickEvent event) {
Window res = new Window("Show exercise");
VerticalLayout content = new VerticalLayout();
content.setSizeUndefined();
content.setSpacing(true);
MathExerciseView<G> view = getExerView(exercise, submInfo);
view.drawProblem(problem);
content.addComponent(view);
res.setContent(content);
UI.getCurrent().addWindow(res);
}
});
// ThemeResource icon = new ThemeResource(
// "../vexer-math/icons/false.png");
// Embedded correctness = new Embedded(null, icon);
//
// try {
// // The amount of correct answers
// if (problem.isCorrect()) {
// correctAnswers++;
//
// icon = new ThemeResource("../vexer-math/icons/correct.png");
// correctness = new Embedded(null, icon);
// }
// } catch (Exception e) {
//
// }
if(problem.isCorrect()) {
correctAnswers++;
}
Label correctnessIcon = new Label(problem.isCorrect() ? Icon.OK.getIcon().variant()
: Icon.CANCEL.getIcon().variant(),ContentMode.HTML);
correctnessIcon.setWidthUndefined();
table.addItem(new Object[] { problem.getQuestion(localizer),
problem.getUserAnswer(),
problem.getCorrectAnswer(),
format.format(t),
correctnessIcon},
new Integer(i));
}
HorizontalLayout horStats = new HorizontalLayout();
horStats.setSizeUndefined();
horStats.setSpacing(true);
Label stats = new Label("<span>" + correctAnswers + "</span>");
stats.setContentMode(ContentMode.HTML);
stats.addStyleName("lastSubmissionInfo");
VerticalLayout statsContainer = new VerticalLayout();
Label pointLabel = new Label(localizer.getUIText(UIConstants.CORRECT));
pointLabel.addStyleName("lastSubmissionInfo");
statsContainer.setSpacing(true);
statsContainer.addComponents(stats,pointLabel);
statsContainer.setComponentAlignment(stats, Alignment.MIDDLE_CENTER);
statsContainer.setComponentAlignment(pointLabel, Alignment.MIDDLE_CENTER);
horStats.addComponent(statsContainer);
Label doneExers = new Label("<span>" + amount + "</span>");
doneExers.setContentMode(ContentMode.HTML);
doneExers.addStyleName("lastSubmissionInfo");
VerticalLayout doneExersContainer = new VerticalLayout();
Label doneExersLabel = new Label(localizer.getUIText(UIConstants.QUESTIONS));
doneExersLabel.addStyleName("lastSubmissionInfo");
doneExersContainer.setSpacing(true);
doneExersContainer.addComponents(doneExers,doneExersLabel);
doneExersContainer.setComponentAlignment(doneExers, Alignment.MIDDLE_CENTER);
doneExersContainer.setComponentAlignment(doneExersLabel, Alignment.MIDDLE_CENTER);
horStats.addComponent(doneExersContainer);
//HorizontalLayout chartContainer = MathSubmissionUIFactory.getChartContainer(handlers, timesPerTask, correctAnswers, (handlers.size() - correctAnswers));//new HorizontalLayout();
//Embedded diffLevel = getDiffLevel();
//addComponent(diffLevel);
Label assignmentNameLabel = new Label("<div style='font-size:28px !important;text-align:center;color:#000'>"
+ assignmentName+"</div>",ContentMode.HTML);
assignmentNameLabel.setWidth("100%");
assignmentNameLabel.addStyleName("lastSubmissionInfo");
addComponent(assignmentNameLabel);
Label exerciseNameLabel = new Label("<div style='text-align:center;color:#000;padding-bottom:25px;'>"
+ exerciseName + "</div>", ContentMode.HTML);
exerciseNameLabel.setWidth("100%");
exerciseNameLabel.addStyleName("lastSubmissionInfo");
addComponent(exerciseNameLabel);
addComponent(horStats);
//addComponent(chartContainer);
addComponent(new Label("<div style='height:20px'></div>",ContentMode.HTML));
VerticalLayout tableContainer = new VerticalLayout();
tableContainer.setSizeUndefined();
tableContainer.addComponent(table);
addComponent(tableContainer);
//setComponentAlignment(diffLevel, Alignment.MIDDLE_CENTER);
//setComponentAlignment(chartContainer, Alignment.MIDDLE_CENTER);
setComponentAlignment(horStats, Alignment.MIDDLE_CENTER);
setComponentAlignment(tableContainer, Alignment.MIDDLE_CENTER);
}
/*
* divides Submission info Time stamp handler into sub exercise handlers.
*/
protected ArrayList<TimeStampHandler> divideTimeStamps(TimeStampHandler stamps) {
ArrayList<TimeStampHandler> handlers = new ArrayList<TimeStampHandler>();
int i = 3;
while (i < stamps.size()) {
TimeStampHandler handler = new TimeStampHandler();
int j = i - 3;
while (j <= i) {
handler.add(stamps.get(j));
j++;
}
handlers.add(handler);
i = i + 3;
}
return handlers;
}
protected String timePerTask(ArrayList<TimeStampHandler> stamp, int i) {
TimeStampHandler subProblem = stamp.get(i);
TimeStamp firstEvent = subProblem.get(0);
TimeStamp lastEvent = subProblem.get(subProblem.size() - 1);
if (firstEvent.getEventStr().equals("startExercise")
|| firstEvent.getEventStr().equals(
"NextButtonListener.buttonClick()")
|| lastEvent.getEventStr().equals("submitExercise")
|| lastEvent.getEventStr().equals(
"NextButtonListener.buttonClick()")) {
long start = firstEvent.getTime();
long end = lastEvent.getTime();
double time = (end - start) / (double) 1000;
return "" + time;
} else {
return "N/A";
}
}
protected Layout doAdditionalSubProbLayout(final G subProblem) {
return null;
}
protected Localizer getLocalizer() {
return localizer;
}
private Window getEditPointsWindow() {
Window result = new Window();
return result;
}
}