cl.uai.client.MarkingInterface.java Source code

Java tutorial

Introduction

Here is the source code for cl.uai.client.MarkingInterface.java

Source

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * @package   eMarking
 * @copyright 2013 Jorge Villaln <villalon@gmail.com>
 *                Hans C. Jeria <hansj@live.cl>
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
package cl.uai.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import cl.uai.client.buttons.BubbleButton;
import cl.uai.client.buttons.ShowChatButton;
import cl.uai.client.buttons.ShowHelpButton;
import cl.uai.client.buttons.ShowRubricButton;
import cl.uai.client.buttons.ShowWallButton;
import cl.uai.client.chat.ChatInterface;
import cl.uai.client.chat.NodeChat;
import cl.uai.client.chat.SendSosDialog;
import cl.uai.client.chat.HelpInterface;
import cl.uai.client.chat.WallInterface;
import cl.uai.client.data.AjaxData;
import cl.uai.client.data.AjaxRequest;
import cl.uai.client.data.Criterion;
import cl.uai.client.data.SubmissionGradeData;
import cl.uai.client.marks.CustomMark;
import cl.uai.client.marks.HighlightMark;
import cl.uai.client.marks.Mark;
import cl.uai.client.marks.PathMark;
import cl.uai.client.marks.RubricMark;
import cl.uai.client.page.EditMarkDialog;
import cl.uai.client.page.MarkingPage;
import cl.uai.client.page.MarkingPagesInterface;
import cl.uai.client.resources.EmarkingMessages;
import cl.uai.client.resources.Resources;
import cl.uai.client.rubric.RubricInterface;
import cl.uai.client.toolbar.MarkingToolBar;

import com.allen_sauer.gwt.dnd.client.PickupDragController;
import com.github.gwtbootstrap.client.ui.ProgressBar;
import com.github.gwtbootstrap.client.ui.base.ProgressBarBase;
import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.ScriptInjector;
import com.google.gwt.dom.client.Style.Cursor;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.datepicker.client.CalendarUtil;

/**
 * Marking interface is the main interface which holds all interactions
 * for eMarking
 * 
 * @author Jorge Villalon <villalon@gmail.com>
 *
 */
public class MarkingInterface extends EMarkingComposite {

    /** For logging purposes */
    private static Logger logger = Logger.getLogger(MarkingInterface.class.getName());

    /** Event bus for e-marking **/
    public static EventBus EVENT_BUS = GWT.create(SimpleEventBus.class);

    /** Static resource for i18n messages **/
    public static EmarkingMessages messages = GWT.create(EmarkingMessages.class);

    /** Id of the draft to visualize **/
    private static int draftId = -1;

    /** Wait dialog to make sure some things occur linearly **/
    private static DialogBox waitDialog = null;

    /** Counter for how many interfaces are currently loading simultaneously **/
    private int loading = 0;

    /** Submission data (student, course, grade, marker) **/
    public static SubmissionGradeData submissionData = null;

    /** Show buttons **/
    private List<BubbleButton> bubbleButtons = null;

    /** Chat intefaces **/
    public ChatInterface chat = null;
    public WallInterface wall = null;
    public SendSosDialog sos = null;
    public HelpInterface help = null;

    /**
     * The id of the submission the interface is working with
     * @return
     */
    public static int getDraftId() {
        return draftId;
    }

    public static void setDraftId(int draftid) {
        draftId = draftid;
    }

    /** Main panels for layout **/
    private VerticalPanel mainPanel = null;

    private AbsolutePanel markingPanel = null;
    private SplitLayoutPanel interfacePanel = null;

    private FocusPanel focusPanel = null;
    private HTML loadingMessage = null;

    /** Main eMarking interfaces **/
    private MarkingToolBar toolbar = null;
    private MarkingPagesInterface markingPagesInterface = null;

    private int rubricMinSize = 100;
    private RubricInterface rubricInterface = null;

    /** Drag and Drop controler for marking interface **/
    public PickupDragController dragController = null;
    /** Timer related variables **/
    private Timer timer = null;
    private int timerWaitingTurns = 1;

    private Timer resizeTimer = null;
    private Date resizeTime = new Date();
    private boolean resizeTimeout = false;

    private Timer heartBeatTimer = null;

    private int ticksUntilTrying = 0;

    /** Suggester for previous comments **/
    public MultiWordSuggestOracle previousCommentsOracle = new MultiWordSuggestOracle();

    /**
    /**
     * 
     */
    public MarkingInterface() {

        // The timer will check if no other resize events have been called in the last 200 ms
        resizeTimer = new Timer() {
            @Override
            public void run() {
                Date now = new Date();
                long diff = now.getTime() - resizeTime.getTime();
                // The last resize was in less than 200 ms
                if (diff < 200) {
                    resizeTimer.schedule(200);
                } else {
                    // More than 200 ms, we accept no more resize is being done
                    resizeTimeout = false;

                    Date oneyear = new Date();
                    CalendarUtil.addMonthsToDate(oneyear, 12);

                    Cookies.setCookie("emarking_width", Integer.toString(Window.getClientWidth()), oneyear);
                    EMarkingWeb.markingInterface.loadSubmissionData();
                }
            }
        };

        // Focus panel to catch key events
        focusPanel = new FocusPanel();

        // Main panel has two rows: Toolbar and Marking panel
        mainPanel = new VerticalPanel();
        mainPanel.addStyleName(Resources.INSTANCE.css().interfaceMainPanel());

        focusPanel.setWidget(mainPanel);

        // Toolbar goes up
        toolbar = new MarkingToolBar();
        mainPanel.add(toolbar);

        focusPanel.addKeyDownHandler(new MarkingInterfaceKeyDownHandler(toolbar));

        // Marking panel containing the marking interface
        interfacePanel = new SplitLayoutPanel() {
            @Override
            public void onResize() {
                super.onResize();
                markingPagesInterface.resizePage(this.getCenterWidth());
            };
        };
        interfacePanel.animate(180);
        interfacePanel.addStyleName(Resources.INSTANCE.css().interfacepanel());

        loadingMessage = new HTML(messages.Loading() + " " + EMarkingConfiguration.getMoodleUrl());

        bubbleButtons = new ArrayList<BubbleButton>();

        bubbleButtons.add(new ShowRubricButton(Window.getClientWidth() - 40, 0, 0));
        bubbleButtons.add(new ShowChatButton(Window.getClientWidth() - 40, 45, NodeChat.SOURCE_CHAT));
        bubbleButtons.add(new ShowWallButton(Window.getClientWidth() - 40, 90, NodeChat.SOURCE_WALL));
        bubbleButtons.add(new ShowHelpButton(Window.getClientWidth() - 40, 135, NodeChat.SOURCE_SOS));

        interfacePanel.add(loadingMessage);
        // interfacePanel.setCellHorizontalAlignment(loadingMessage, HasAlignment.ALIGN_CENTER);      

        markingPanel = new AbsolutePanel();
        markingPanel.add(interfacePanel);

        for (BubbleButton b : bubbleButtons) {
            markingPanel.add(b);
        }

        mainPanel.add(markingPanel);

        // Timer for pinging system
        timer = new Timer() {
            @Override
            public void run() {
                // If there are ticks to wait before trying again, update message and update ticks
                if (ticksUntilTrying > 0) {
                    loadingMessage.setHTML(messages.CantReachServerRetrying(ticksUntilTrying));
                    ticksUntilTrying--;
                } else {
                    // Updating next trial for one more second and trying onLoad again
                    timerWaitingTurns++;
                    ticksUntilTrying = Math.min(timerWaitingTurns, 60);
                    loadingMessage.setHTML(messages.Loading() + " " + EMarkingConfiguration.getMoodleUrl());
                    onLoad();
                }
            }
        };

        heartBeatTimer = new Timer() {
            @Override
            public void run() {
                String extradata = "";
                if (submissionData != null)
                    extradata = "&marker=" + submissionData.getMarkerid() + "&draft=" + submissionData.getId();
                final String requestUrl = extradata;
                AjaxRequest.ajaxRequest("action=heartbeat" + extradata, new AsyncCallback<AjaxData>() {
                    @Override
                    public void onSuccess(AjaxData result) {
                        logger.info("Heartbeat! " + requestUrl);
                    }

                    @Override
                    public void onFailure(Throwable caught) {
                        logger.warning("Failure on heartbeat");
                    }
                });
            }
        };
        // Drag and Drop controller attached to marking panel
        dragController = new PickupDragController(markingPanel, false);

        waitDialog = new DialogBox(false, true);
        waitDialog.setGlassEnabled(true);
        waitDialog.addStyleName(Resources.INSTANCE.css().commentdialog());
        waitDialog.setHTML(MarkingInterface.messages.Loading());
        ProgressBar pbar = new ProgressBar(ProgressBarBase.Style.STRIPED);
        pbar.setActive(true);
        pbar.setPercent(100);
        waitDialog.setWidget(pbar);

        this.initWidget(focusPanel);
    }

    public void addLoading(boolean saving) {
        this.loading++;

        if (this.loading > 0) {
            if (saving) {
                waitDialog.setHTML(MarkingInterface.messages.Saving());
            } else {
                waitDialog.setHTML(MarkingInterface.messages.Loading());
            }
            waitDialog.center();
        }
    }

    public void updateGeneralFeedback(final String generalFeedback) {
        addLoading(true);
        // Invokes the ajax Moodle interface to save the mark
        AjaxRequest.ajaxRequest("action=updgeneralfeedback" + "&feedback=" + URL.encode(generalFeedback),
                new AsyncCallback<AjaxData>() {
                    @Override
                    public void onSuccess(AjaxData result) {
                        // Parse json results and check if there was an error
                        if (!result.getError().equals("")) {
                            logger.severe(result.getError());
                            Window.alert(result.getError());
                            return;
                        }

                        finishLoading();
                    }

                    @Override
                    public void onFailure(Throwable caught) {
                        if (EMarkingConfiguration.isDebugging()) {
                            caught.printStackTrace();
                            logger.severe(caught.getMessage());
                        }
                        finishLoading();
                    }
                });
    }

    /**
     * Add a mark to both the page and update the rubric interface
     * 
     * @param mark the mark to add
     */
    public void addMark(final Mark mark, final MarkingPage page) {

        RootPanel.get().getElement().getStyle().setCursor(Cursor.WAIT);

        Mark.loadingIcon.removeFromParent();
        page.getAbsolutePanel().add(Mark.loadingIcon, mark.getPosx(), mark.getPosy());
        Mark.loadingIcon.setVisible(true);

        //por defecto el criterionid = 0 y la clase para el color es criterion0
        int cid = 0;
        if (EMarkingConfiguration.isColoredRubric()) {
            Criterion c = EMarkingWeb.markingInterface.getToolbar().getMarkingButtons().getSelectedCriterion();
            if (c != null) {
                cid = c.getId();
            }
        }

        int markposx = mark.getPosx();
        int markposy = mark.getPosy();

        String path = "";
        if (mark instanceof HighlightMark) {
            HighlightMark hmark = (HighlightMark) mark;
            path = "&path=" + URL.encode(hmark.getEnd().getX() + "," + hmark.getEnd().getY());
            logger.fine("sending " + markposx + "," + markposy + " -> " + hmark.getEnd().getX() + ","
                    + hmark.getEnd().getY() + " path:" + path);
        } else if (mark instanceof PathMark) {
            path = "&path=" + URL.encode(((PathMark) mark).getPath());
        }
        // Invokes the ajax Moodle interface to save the mark
        AjaxRequest.ajaxRequest("action=addcomment" + "&comment=" + URL.encode(mark.getRawtext()) + "&posx="
                + markposx + "&posy=" + markposy + "&width=" + page.getWidth() + "&height=" + page.getHeight()
                + "&format=" + mark.getFormat() + "&pageno=" + mark.getPageno() + "&criterionid=" + cid + path
                + "&colour=" + mark.getCriterionId() + "&windowswidth=" + page.getWidth() + "&windowsheight="
                + page.getHeight(), new AsyncCallback<AjaxData>() {

                    @Override
                    public void onFailure(Throwable caught) {
                        Mark.loadingIcon.setVisible(false);
                        logger.severe("Exception adding mark.");
                        logger.severe(caught.getMessage());
                        Window.alert(caught.getMessage());
                        RootPanel.get().getElement().getStyle().setCursor(Cursor.AUTO);
                    }

                    @Override
                    public void onSuccess(AjaxData result) {
                        Mark.loadingIcon.setVisible(false);

                        Map<String, String> values = AjaxRequest.getValueFromResult(result);

                        // Parse json results and check if there was an error
                        if (!result.getError().equals("")) {
                            Window.alert(messages.ErrorAddingMark());
                            RootPanel.get().getElement().getStyle().setCursor(Cursor.AUTO);
                            return;
                        }

                        // Parses important values from result
                        int id = Integer.parseInt(values.get("id"));
                        long timemodified = Long.parseLong(values.get("timemodified"));
                        int markerid = Integer.parseInt(values.get("markerid"));
                        String markername = values.get("markername");
                        float newgrade = 0;
                        if (mark instanceof RubricMark) {
                            newgrade = Float.parseFloat(values.get("grade"));
                        } else {
                            newgrade = MarkingInterface.submissionData.getFinalgrade();
                        }

                        // Sets the values for the new mark
                        mark.setId(id);
                        mark.setMarkerid(markerid);
                        mark.setMarkername(markername);
                        mark.setTimeCreated(timemodified);

                        // Adds the mark to the marking interface
                        markingPagesInterface.addMarkWidget(mark, -1, page);

                        // If it is a comment And to the rubric interface
                        toolbar.getMarkingButtons().updateStats();

                        if (!(mark instanceof CustomMark) && mark.getFormat() != 5) {
                            EMarkingWeb.markingInterface.getRubricInterface().getToolsPanel().getPreviousComments()
                                    .addMarkAsCommentToInterface(mark, true);
                        }

                        // Updates toolbar
                        setTimemodified(timemodified);

                        // Update the marking interface with the final grade and time
                        EMarkingWeb.markingInterface.setFinalgrade(newgrade, timemodified);

                        RootPanel.get().getElement().getStyle().setCursor(Cursor.AUTO);
                    }
                });

    }

    /**
     * Adds a mark to current submission.
     * 
     * @param level the mark to assign
     * @param posx X coordinate where to draw mark in page
     * @param posy Y coordinate where to draw mark in page
     */
    public void addRubricMark(final int level, final int posx, final int posy, final MarkingPage page) {

        // Shows comment dialog
        // 0 for regradeid as we are creating a mark
        final EditMarkDialog dialog = new EditMarkDialog(posx, posy, level, 0);
        if (this.setBonus >= 0) {
            dialog.setBonus(this.setBonus);
            this.setBonus = -1;
        }
        dialog.addCloseHandler(new CloseHandler<PopupPanel>() {
            @Override
            public void onClose(CloseEvent<PopupPanel> event) {

                // If dialog was not cancelled and contains a comment, try to add the mark
                if (!dialog.isCancelled()) {

                    // Calculate parameters for adding mark
                    final String comment = dialog.getTxtComment(); // Comment from dialog
                    final float bonus = dialog.getBonus();
                    final int levelid = dialog.getLevelId();
                    final String feedbackToAjax;
                    if (dialog.haveFeedback()) {
                        feedbackToAjax = dialog.getFeedback();
                    } else {
                        feedbackToAjax = "";
                    }
                    // Ajax URL for adding mark
                    String url = "action=addmark" + "&level=" + levelid + "&posx=" + posx + "&posy=" + posy
                            + "&pageno=" + (page.getPageNumber()) + "&sesskey=" + EMarkingConfiguration.getSessKey()
                            + "&bonus=" + bonus + "&comment=" + URL.encode(comment) + "&windowswidth="
                            + page.getWidth() + "&windowsheight=" + page.getHeight() + "&feedback="
                            + feedbackToAjax;

                    // Add loading icon
                    Mark.loadingIcon.removeFromParent();
                    page.getAbsolutePanel().add(Mark.loadingIcon, posx, posy);
                    Mark.loadingIcon.setVisible(true);

                    rubricInterface.getRubricPanel().loadingRubricCriterion(levelid);

                    // Make Ajax request 
                    AjaxRequest.ajaxRequest(url, new AsyncCallback<AjaxData>() {

                        @Override
                        public void onFailure(Throwable caught) {
                            Mark.loadingIcon.setVisible(false);
                            rubricInterface.getRubricPanel().finishloadingRubricCriterion(levelid);

                            logger.severe("Error adding mark to Moodle!");
                            logger.severe(caught.getMessage());
                            Window.alert(caught.getMessage());
                        }

                        @Override
                        public void onSuccess(AjaxData result) {
                            Mark.loadingIcon.setVisible(false);
                            rubricInterface.getRubricPanel().finishloadingRubricCriterion(levelid);
                            Mark.hideIcons();

                            // Parse Json values
                            Map<String, String> values = AjaxRequest.getValueFromResult(result);

                            if (!values.get("error").equals("")) {
                                Mark.loadingIcon.setVisible(false);
                                rubricInterface.getRubricPanel().finishloadingRubricCriterion(levelid);

                                logger.severe("Error adding mark to Moodle!");
                                Window.alert(MarkingInterface.messages.ErrorAddingMark());
                                return;
                            }

                            // Get main values
                            int previd = Integer.parseInt(values.get("replaceid"));
                            int newid = Integer.parseInt(values.get("id"));
                            float newgrade = Float.parseFloat(values.get("grade"));
                            long timemodified = Long.parseLong(values.get("timemodified"));
                            String markername = values.get("markername");
                            int pageno = page.getPageNumber();
                            int regradeid = Integer.parseInt(values.get("regradeid"));
                            int regradeaccepted = Integer.parseInt(values.get("regradeaccepted"));
                            int regrademotive = Integer.parseInt(values.get("regrademotive"));
                            String regradecomment = values.get("regradecomment");
                            String regrademarkercomment = values.get("regrademarkercomment");
                            int criterionId = Integer.parseInt(values.get("criterionid"));

                            // If there was a previous mark with the same level, remove it
                            if (previd > 0) {
                                page.deleteMarkWidget(previd);
                            }

                            long unixtime = System.currentTimeMillis() / 1000L;

                            // Add mark to marking pages interface
                            RubricMark mark = new RubricMark(newid, posx, posy, pageno,
                                    EMarkingConfiguration.getMarkerId(), dialog.getLevelId(), unixtime, criterionId,
                                    markername, comment);

                            if (dialog.haveFeedback()) {
                                mark.setFeedback(dialog.getFeedbackArray());
                            }
                            mark.setRegradeid(regradeid);
                            mark.setRegradeaccepted(regradeaccepted);
                            mark.setRegradecomment(regradecomment);
                            mark.setRegrademarkercomment(regrademarkercomment);
                            mark.setRegrademotive(regrademotive);

                            Criterion criterion = MarkingInterface.submissionData.getLevelById(mark.getLevelId())
                                    .getCriterion();
                            criterion.setSelectedLevel(mark.getLevelId());
                            criterion.setBonus(bonus);
                            markingPagesInterface.addMarkWidget(mark, previd, page);
                            rubricInterface.getRubricPanel().addMarkToRubric(mark);
                            toolbar.getMarkingButtons().updateStats();
                            toolbar.getMarkingButtons().changeColor(criterion.getId());

                            EMarkingWeb.markingInterface.getRubricInterface().getToolsPanel().getPreviousComments()
                                    .addMarkAsCommentToInterface(mark, true);

                            setFinalgrade(newgrade, timemodified);
                        }
                    });
                }
            }
        });
        dialog.center();
    }

    /**
     * Deletes a mark from the interface
     * 
     * @param mark The Mark to be deleted
     */
    public void deleteMark(final Mark mark) {
        // Check if the mark is a rubric mark
        final RubricMark rubricMark = mark instanceof RubricMark ? (RubricMark) mark : null;

        logger.fine("Deleting comment " + mark.getId());

        // Delete from view for user
        mark.setVisible(false);

        // Set cursor waiting
        RootPanel.get().getElement().getStyle().setCursor(Cursor.WAIT);

        String url = null;

        if (rubricMark == null) {
            // Ajax URL for deleting comment
            url = "action=deletecomment" + "&id=" + mark.getId() + "&sesskey=" + EMarkingConfiguration.getSessKey();
        } else {
            // Ajax URL for deleting mark
            url = "action=deletemark" + "&level=" + rubricMark.getLevelId() + "&sesskey="
                    + EMarkingConfiguration.getSessKey();

            rubricInterface.getRubricPanel().loadingRubricCriterion(rubricMark.getLevelId());
        }

        // Make Ajax request 
        AjaxRequest.ajaxRequest(url, new AsyncCallback<AjaxData>() {

            @Override
            public void onFailure(Throwable caught) {
                logger.severe("Exception deleting mark.");
                logger.severe(caught.getMessage());
                if (rubricMark != null)
                    rubricInterface.getRubricPanel().finishloadingRubricCriterion(rubricMark.getLevelId());
                Window.alert(caught.getMessage());
                mark.setVisible(true);
                RootPanel.get().getElement().getStyle().setCursor(Cursor.AUTO);
            }

            @Override
            public void onSuccess(AjaxData result) {
                // Parse Json values
                Map<String, String> values = AjaxRequest.getValueFromResult(result);

                if (rubricMark != null)
                    rubricInterface.getRubricPanel().finishloadingRubricCriterion(rubricMark.getLevelId());

                // Get main values
                float newgrade = 0;
                if (rubricMark != null)
                    newgrade = Float.parseFloat(values.get("grade"));

                // Get main values
                long timemodified = Long.parseLong(values.get("timemodified"));

                if (rubricMark != null) {
                    // Then add resulting mark it to the rubric interface
                    rubricMark.getLevel().getCriterion().setSelectedLevel(0);
                    rubricInterface.getRubricPanel().deleteMarkFromRubric(rubricMark);
                    if (EMarkingConfiguration
                            .getMarkingType() == EMarkingConfiguration.EMARKING_TYPE_MARKER_TRAINING) {
                        rubricMark.removeCollaborativeButtons();
                    }
                    rubricInterface.getToolsPanel().getPreviousComments()
                            .deletePreviousComment(rubricMark.getRawtext());
                    setFinalgrade(newgrade, timemodified);
                    Mark.markPopup.setVisible(false);
                } else {
                    markingPagesInterface.deleteMarkWidget(mark.getId());
                    setTimemodified(timemodified);
                }

                toolbar.getMarkingButtons().updateStats();

                EMarkingWeb.markingInterface.getRubricInterface().getToolsPanel().loadSumissionData();

                RootPanel.get().getElement().getStyle().setCursor(Cursor.AUTO);
            }
        });

    }

    public void finishLoading() {
        this.loading--;
        if (this.loading <= 0)
            waitDialog.hide();
    }

    /**
     * Gets the drag controller for main interface
     * @return
     */
    public PickupDragController getDragController() {
        return dragController;
    }

    public MarkingPagesInterface getMarkingPagesInterface() {
        return markingPagesInterface;
    }

    public RubricInterface getRubricInterface() {
        return rubricInterface;
    }

    /**
     * @return the toolbar
     */
    public MarkingToolBar getToolbar() {
        return toolbar;
    }

    public void setColoredRubric(boolean colored) {

        Date oneyear = new Date();
        CalendarUtil.addMonthsToDate(oneyear, 12);

        Cookies.setCookie("emarking_showcolors", colored ? "1" : "0", oneyear);
        EMarkingConfiguration.setColoredRubric(colored);

        EMarkingWeb.markingInterface.loadInterface();
    }

    /**
     * Loads marking interface according to current submission
     */
    public void loadInterface() {

        toolbar.loadSubmissionData();

        dragController.unregisterDropControllers();
        interfacePanel.clear();

        markingPagesInterface = new MarkingPagesInterface();
        rubricInterface = new RubricInterface();

        for (BubbleButton b : bubbleButtons) {
            b.setLeft(Window.getClientWidth() - 40);
            b.updatePosition(markingPanel);
            if (b instanceof ShowRubricButton) {
                b.setVisible(!EMarkingConfiguration.isShowRubricOnLoad());
            } else {
                b.setVisible(EMarkingConfiguration.isChatEnabled());
            }

            b.setVisible(false);
        }

        int rubricWidth = (int) (Window.getClientWidth() - (Window.getClientWidth() / 1.61803));
        rubricMinSize = (int) Math.max(rubricWidth, 300);
        if (EMarkingConfiguration.getMarkingType() == EMarkingConfiguration.EMARKING_TYPE_PRINT_SCAN) {
            rubricWidth = rubricMinSize - 10;
        }
        interfacePanel.addEast(rubricInterface, rubricWidth);
        interfacePanel.setWidgetMinSize(rubricInterface, 10);
        interfacePanel.add(markingPagesInterface);
        interfacePanel.setWidgetMinSize(markingPagesInterface, rubricMinSize);
        interfacePanel.setHeight((Window.getClientHeight() - toolbar.getOffsetHeight()) + "px");

        // When we set the rubric visibility we call the loadinterface in the markinginterface object
        rubricInterface.setVisible(EMarkingConfiguration.isShowRubricOnLoad()
                && EMarkingConfiguration.getMarkingType() != EMarkingConfiguration.EMARKING_TYPE_PRINT_SCAN);
    }

    public void setShowRubricButtonVisible(boolean visible) {
        bubbleButtons.get(0).setVisible(false);
    }

    /**
     * Loads submission data using global submission id
     */
    public void loadSubmissionData() {

        // Checks that global submission id is valid
        if (MarkingInterface.draftId <= 0)
            return;

        addLoading(false);

        // Ajax requesto to submission data
        AjaxRequest.ajaxRequest("action=getsubmission", new AsyncCallback<AjaxData>() {

            @Override
            public void onFailure(Throwable caught) {
                logger.severe("Error getting submission from Moodle!");
                logger.severe(caught.getMessage());
                Window.alert(caught.getMessage());
                finishLoading();
            }

            @Override
            public void onSuccess(AjaxData result) {
                // Parse Json values
                Map<String, String> values = AjaxRequest.getValueFromResult(result);

                // Reset submission data
                submissionData = SubmissionGradeData.createFromConfiguration(values);

                if (submissionData != null) {
                    EMarkingWeb.markingInterface.loadInterface();
                } else {
                    Window.alert(MarkingInterface.messages.InvalidSubmissionData());
                }

                Window.setTitle(
                        "Emarking " + submissionData.getCoursename() + " " + submissionData.getActivityname());

                if (EMarkingConfiguration.isChatEnabled()) {
                    activateChat();
                }

                finishLoading();

                Window.addResizeHandler(new ResizeHandler() {
                    @Override
                    public void onResize(ResizeEvent event) {
                        resizeTime = new Date();
                        if (!resizeTimeout) {
                            resizeTimeout = true;
                            resizeTimer.schedule(200);
                        }
                    }
                });
            }
        });
    }

    @Override
    protected void onLoad() {

        // Ajax request to load submission data
        AjaxRequest.ajaxRequest("action=ping", new AsyncCallback<AjaxData>() {

            @Override
            public void onFailure(Throwable caught) {
                // Keep trying if something fails every few seconds
                timer.scheduleRepeating(1000);
            }

            @Override
            public void onSuccess(AjaxData result) {
                //Check if values are ok
                if (result.getError().equals("")) {

                    // Parse Json values
                    Map<String, String> value = AjaxRequest.getValueFromResult(result);

                    try {
                        EMarkingConfiguration.loadConfiguration(value);
                    } catch (Exception e) {
                        e.printStackTrace();
                        Window.alert(MarkingInterface.messages.ErrorLoadingSubmission());
                        return;
                    }

                    // Clear interface (submission and rubric interfaces)
                    interfacePanel.clear();

                    // Cancel timer, we don't need to ping again
                    timer.cancel();

                    // Load submission data
                    loadSubmissionData();

                    focusPanel.getElement().focus();

                    // Schedule heartbeat if configured as
                    if ((value.get("heartbeat") != null && value.get("heartbeat").equals("1"))) {
                        // Every two minutes
                        heartBeatTimer.scheduleRepeating(2 * 60 * 1000);
                    }
                } else {
                    // Keep trying if something fails every few seconds
                    timer.scheduleRepeating(1000);
                }
            }
        });
    }

    private void activateChat() {

        final String nodepath = EMarkingConfiguration.getNodejspath() + "/socket.io/socket.io.js";

        ScriptInjector.fromUrl(nodepath).setCallback(new Callback<Void, Exception>() {

            @Override
            public void onFailure(Exception reason) {
                logger.severe("Could not find node server " + nodepath);
                EMarkingConfiguration.setChatServerError(true);
                disableCollaboration();
            }

            @Override
            public void onSuccess(Void result) {
                try {

                    if (EMarkingWeb.chatServer != null)
                        return;

                    chat = new ChatInterface();
                    wall = new WallInterface();
                    sos = new SendSosDialog();
                    help = new HelpInterface();

                    EMarkingWeb.chatServer = new NodeChat();

                } catch (Exception e) {
                    e.printStackTrace();
                    logger.severe("Fatal error trying to load NodeJS. Disabling collaborative features.");
                    EMarkingConfiguration.setChatServerError(true);
                    disableCollaboration();
                }
            }
        }).inject();
    }

    public void regradeMark(final RubricMark mark, final String comment, final int motive) {

        RootPanel.get().getElement().getStyle().setCursor(Cursor.WAIT);
        final MarkingPage page = markingPagesInterface.getPageByIndex(mark.getPageno() - 1);
        if (page == null) {
            logger.severe("Page is null for page index " + mark.getPageno());
            return;
        }
        Mark.loadingIcon.removeFromParent();
        page.getAbsolutePanel().add(Mark.loadingIcon, mark.getPosx(), mark.getPosy());
        Mark.loadingIcon.setVisible(true);

        // Invokes the ajax Moodle interface to save the mark
        AjaxRequest.ajaxRequest("action=addregrade" + "&comment=" + URL.encode(comment) + "&motive=" + motive
                + "&level=" + mark.getLevelId(), new AsyncCallback<AjaxData>() {

                    @Override
                    public void onFailure(Throwable caught) {
                        Mark.loadingIcon.setVisible(false);
                        logger.severe("Exception regrading mark.");
                        logger.severe(caught.getMessage());
                        Window.alert(caught.getMessage());
                        RootPanel.get().getElement().getStyle().setCursor(Cursor.AUTO);
                    }

                    @Override
                    public void onSuccess(AjaxData result) {
                        Mark.loadingIcon.setVisible(false);

                        Map<String, String> values = AjaxRequest.getValueFromResult(result);

                        // Parse json results and check if there was an error
                        if (!result.getError().equals("")) {
                            Window.alert(messages.ErrorAddingMark());
                            RootPanel.get().getElement().getStyle().setCursor(Cursor.AUTO);
                            return;
                        }

                        // Parses important values from result
                        int regradeid = Integer.parseInt(values.get("regradeid"));
                        long timemodified = Long.parseLong(values.get("timemodified"));

                        // Sets the values for the new mark
                        mark.setRegradeid(regradeid);
                        mark.setRegradecomment(comment);
                        mark.setRegrademotive(motive);

                        // Add the mark to the rubric so it updates the information in the rubric panel
                        EMarkingWeb.markingInterface.getRubricInterface().getRubricPanel().addMarkToRubric(mark);
                        mark.setMarkHTML();

                        // Updates toolbar
                        setTimemodified(timemodified);

                        RootPanel.get().getElement().getStyle().setCursor(Cursor.AUTO);
                    }
                });
    }

    /**
     * Reloads main interface for a new submission
     * 
     * @param newSubmissionId the new submission id
     */
    public void reload(int newSubmissionId) {

        // Validate new submission id value
        if (newSubmissionId < 0) {
            Window.alert("Invalid submission id value " + draftId);
            return;
        }

        draftId = newSubmissionId;

        reloadPage();
    }

    public void reloadPage() {
        String madeURL = Window.Location.getProtocol() + "//" + Window.Location.getHost()
                + Window.Location.getPath() + "?";
        for (String key : Window.Location.getParameterMap().keySet()) {
            String value = Window.Location.getParameterMap().get(key).get(0);
            if (key.equals("ids")) {
                value = draftId + "";
            }
            madeURL += key + "=";
            madeURL += value;
            madeURL += "&";
        }
        Window.Location.replace(madeURL);
    }

    /**
     * A new grade was assigned through marking
     * 
     * @param newgrade new final grade
     * @param timemodified when was modified
     */
    public void setFinalgrade(float newgrade, long timemodified) {
        submissionData.setFinalgrade(newgrade);
        this.setTimemodified(timemodified);
        toolbar.getGrade().loadSubmissionData();
        focusPanel.getElement().focus();
    }

    /**
     * A new grade was assigned through marking
     * 
     * @param newgrade new final grade
     * @param timemodified when was modified
     */
    public void setTimemodified(long timemodified) {
        submissionData.setDatemodified(timemodified);
    }

    private float setBonus = -1;

    //Sets a preset bonus for the next time the addrubric dialog is opened (used in delphi)
    public void setDialogNewBonus(float bonus) {
        this.setBonus = bonus;
    }

    public void addNotificationToBubbleButton(int source) {
        for (BubbleButton btn : this.bubbleButtons) {
            if (btn.getSource() == source) {
                btn.addNotification();
            }
        }
        getToolbar().getChatButtons().addNotification(source);
    }

    public void removeNotificationToBubbleButton(int source) {
        for (BubbleButton btn : this.bubbleButtons) {
            if (btn.getSource() == source) {
                btn.removeNotification();
            }
        }
        getToolbar().getChatButtons().removeNotification(source);
    }

    public void disableCollaboration() {
        for (BubbleButton b : bubbleButtons) {
            if (!(b instanceof ShowRubricButton)) {
                b.setVisible(false);
            }
        }
        this.toolbar.getChatButtons().loadSubmissionData();
    }

    public void hideRubric() {
        Mark.hideIcons();
        Mark.markPopup.setVisible(false);
        if (interfacePanel.getWidgetSize(rubricInterface) < 10) {
            interfacePanel.setWidgetSize(rubricInterface, rubricMinSize);
            markingPagesInterface.resizePage(interfacePanel.getOffsetWidth() - rubricMinSize);
        } else {
            interfacePanel.setWidgetSize(rubricInterface, 0);
            markingPagesInterface.resizePage(interfacePanel.getOffsetWidth());
        }
    }

    public AbsolutePanel getMarkingPanel() {
        return this.markingPanel;
    }

    /**
     * 
     * @param html
     * @param b
     */
    public void addPreviousComment(String html, boolean b) {

    }
}