es.deusto.weblab.client.experiments.logic.ui.MobileLogicExperiment.java Source code

Java tutorial

Introduction

Here is the source code for es.deusto.weblab.client.experiments.logic.ui.MobileLogicExperiment.java

Source

/*
* Copyright (C) 2005 onwards University of Deusto
* All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution.
*
* This software consists of contributions made by many individuals, 
* listed below:
*
* Author: Pablo Ordua <pablo@ordunya.com>
*
*/
package es.deusto.weblab.client.experiments.logic.ui;

import java.util.HashMap;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

import es.deusto.weblab.client.WebLabClient;
import es.deusto.weblab.client.comm.exceptions.CommException;
import es.deusto.weblab.client.configuration.IConfigurationRetriever;
import es.deusto.weblab.client.dto.experiments.Command;
import es.deusto.weblab.client.dto.experiments.ResponseCommand;
import es.deusto.weblab.client.experiments.gpib.ui.GpibExperiment;
import es.deusto.weblab.client.experiments.logic.circuit.Circuit;
import es.deusto.weblab.client.experiments.logic.circuit.CircuitParser;
import es.deusto.weblab.client.experiments.logic.circuit.Gate;
import es.deusto.weblab.client.experiments.logic.circuit.InvalidCircuitException;
import es.deusto.weblab.client.experiments.logic.circuit.Operation;
import es.deusto.weblab.client.experiments.logic.circuit.Switch;
import es.deusto.weblab.client.experiments.logic.commands.GetCircuitCommand;
import es.deusto.weblab.client.experiments.logic.commands.SolveCircuitCommand;
import es.deusto.weblab.client.lab.comm.callbacks.IResponseCommandCallback;
import es.deusto.weblab.client.lab.experiments.ExperimentBase;
import es.deusto.weblab.client.lab.experiments.IBoardBaseController;
import es.deusto.weblab.client.ui.widgets.WlTimer;
import es.deusto.weblab.client.ui.widgets.WlWaitingLabel;
import es.deusto.weblab.client.ui.widgets.WlWebcam;
import es.deusto.weblab.client.ui.widgets.WlTimer.IWlTimerFinishedCallback;

public class MobileLogicExperiment extends ExperimentBase {

    public static final String LOGIC_WEBCAM_IMAGE_URL_PROPERTY = "es.deusto.weblab.logic.webcam.image.url";
    public static final String DEFAULT_LOGIC_WEBCAM_IMAGE_URL = "https://cams.weblab.deusto.es/webcam/proxied.py/pld1";

    private static final String LOGIC_WEBCAM_REFRESH_TIME_PROPERTY = "es.deusto.weblab.logic.webcam.refresh.millis";
    private static final int DEFAULT_LOGIC_WEBCAM_REFRESH_TIME = 400;

    private static final String LOGIC_USE_WEBCAM_PROPERTY = "logic.use.webcam";
    private static final boolean DEFAULT_LOGIC_USE_WEBCAM = false;

    public static class Style {
        public static final String TIME_REMAINING = "wl-time_remaining";
        public static final String CLOCK_ACTIVATION_PANEL = "wl-clock_activation_panel";
        public static final String LOGIC_INPUT_VALUE_LABEL = "logic-small-input-value-label";
        public static final String LOGIC_MOUSE_POINTER_HAND = "logic-mouse-pointer-hand";
    }

    private final Map<Operation, ImageResource> operation2url = new HashMap<Operation, ImageResource>();

    private final String zeroString = "0";
    private final String oneString = "1";

    // Widgets
    private final VerticalPanel widget;
    private final VerticalPanel removableWidgetsPanel;
    private HorizontalPanel circuitPanel;
    private WlWebcam webcam;
    private WlTimer timer;
    private WlWaitingLabel messages;
    private Grid circuitGrid;
    private HTML input1Label; // Input values
    private HTML input2Label;
    private HTML input3Label;
    private HTML input4Label;
    private Image gateA1Image; // 1st level (A) of gates
    private Image gateA2Image;
    private Image gateA3Image;
    private Image gateB1Image; // 2nd level (B) of gates
    private Image gateB2Image;
    private Image gateC1Image; // 3rd level (C) of gates
    private Image unknownGateImage;
    private DialogBox changeUnknownGateDialogBox;
    private Button sendSolutionButton;
    private final Label referenceToShowBoxesLabel = new Label("");
    private Image light;

    // DTOs
    private final boolean useWebcam;
    private Command lastCommand;
    private Circuit circuit;
    private boolean solving = true;
    private int points = 0;
    private final ClickHandler unkownGateHandler;
    private final MobileResources resources = GWT.create(MobileResources.class);

    private final IResponseCommandCallback commandCallback = new IResponseCommandCallback() {

        @Override
        public void onSuccess(ResponseCommand responseCommand) {
            MobileLogicExperiment.this.processCommandSent(responseCommand);
        }

        @Override
        public void onFailure(CommException e) {
            MobileLogicExperiment.this.messages.setText("Error: " + e.getMessage()
                    + ". Please, notify the WebLab-Deusto administrators at weblab@deusto.es about this error.");
        }
    };

    public MobileLogicExperiment(IConfigurationRetriever configurationRetriever,
            IBoardBaseController commandSender) {
        super(configurationRetriever, commandSender);

        this.useWebcam = this.configurationRetriever.getBoolProperty(LOGIC_USE_WEBCAM_PROPERTY,
                DEFAULT_LOGIC_USE_WEBCAM);

        this.fillMaps();

        this.widget = new VerticalPanel();
        this.widget.setWidth("100%");
        this.widget.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);

        this.removableWidgetsPanel = new VerticalPanel();
        this.removableWidgetsPanel.setWidth("100%");
        this.removableWidgetsPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
        this.removableWidgetsPanel.setSpacing(20);

        this.unkownGateHandler = new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                if (MobileLogicExperiment.this.solving)
                    MobileLogicExperiment.this.changeUnknownGateDialogBox.show();
                MobileLogicExperiment.this.changeUnknownGateDialogBox
                        .showRelativeTo(MobileLogicExperiment.this.referenceToShowBoxesLabel);

            }
        };
    }

    private void fillMaps() {
        this.operation2url.put(Operation.AND, this.resources.smallAND());
        this.operation2url.put(Operation.NAND, this.resources.smallNAND());
        this.operation2url.put(Operation.OR, this.resources.smallOR());
        this.operation2url.put(Operation.NOR, this.resources.smallNOR());
        this.operation2url.put(Operation.XOR, this.resources.smallXOR());
    }

    public ImageResource getURL(Operation operation) {
        return this.operation2url.get(operation);
    }

    void changeUnknownGate(Operation operation) {
        this.setUnknownGate(this.getURL(operation));
        this.sendSolutionButton.setEnabled(true);
        this.circuit.setUnknownOperation(0, operation);
    }

    private void setUnknownGate(ImageResource resource) {
        final Image image = new Image(resource);
        this.circuitGrid.setWidget(2, 2, image);
        image.addClickHandler(this.unkownGateHandler);
    }

    @Override
    public void initialize() {
        this.removableWidgetsPanel.add(new Label(i18n.welcomeToWebLabDeustoLogic()));
        this.removableWidgetsPanel.add(new Label(i18n.replaceTheUnknownGate()));
        this.removableWidgetsPanel.add(new Label(i18n.solveAsManyCircuitsAsPossible()));
        this.removableWidgetsPanel.add(new HTML(i18n.youCanCheckYourScoreAt()));

        this.widget.add(this.removableWidgetsPanel);
    }

    @Override
    public void initializeReserved() {

    }

    @Override
    public void queued() {
        this.widget.setVisible(false);
    }

    @Override
    public void start(int time, String initialConfiguration) {
        final JSONValue parsedInitialConfiguration = JSONParser.parseStrict(initialConfiguration);
        final String webcamUrl = parsedInitialConfiguration.isObject().get("webcam").isString().stringValue();

        this.points = 0;
        this.widget.setVisible(true);

        while (this.removableWidgetsPanel.getWidgetCount() > 0)
            this.removableWidgetsPanel.remove(0);

        // Timer
        this.timer = new WlTimer();
        this.timer.setStyleName(GpibExperiment.Style.TIME_REMAINING);
        this.timer.getWidget().setWidth("30%");
        this.timer.setTimerFinishedCallback(new IWlTimerFinishedCallback() {
            @Override
            public void onFinished() {
                MobileLogicExperiment.this.boardController.clean();
            }
        });
        this.removableWidgetsPanel.add(this.timer.getWidget());

        // Webcam
        this.webcam = new WlWebcam(this.getWebcamRefreshingTime(), webcamUrl);

        final Widget webcamWidget;
        if (this.useWebcam) {
            webcamWidget = this.webcam.getWidget();
            this.webcam.start();
        } else {
            this.light = new Image();
            webcamWidget = this.light;
            turnOffLight();
        }
        this.removableWidgetsPanel.add(webcamWidget);

        // Horizontal Panel
        this.circuitPanel = new HorizontalPanel();
        this.circuitPanel.setWidth("100%");
        this.circuitPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);

        this.circuitPanel.add(this.referenceToShowBoxesLabel);

        // Circuit
        this.circuitGrid = new Grid(5, 8);
        this.circuitGrid.setBorderWidth(0);
        this.circuitPanel.add(this.circuitGrid);

        // Inputs
        this.input1Label = new HTML(this.getFormatedInputLabel(this.zeroString, 1));
        this.input1Label.setStyleName(Style.LOGIC_INPUT_VALUE_LABEL);
        this.circuitGrid.setWidget(0, 0, this.input1Label);
        this.input2Label = new HTML(this.getFormatedInputLabel(this.zeroString, 2));
        this.input2Label.setStyleName(Style.LOGIC_INPUT_VALUE_LABEL);
        this.circuitGrid.setWidget(1, 0, this.input2Label);
        this.input3Label = new HTML(this.getFormatedInputLabel(this.zeroString, 3));
        this.input3Label.setStyleName(Style.LOGIC_INPUT_VALUE_LABEL);
        this.circuitGrid.setWidget(3, 0, this.input3Label);
        this.input4Label = new HTML(this.getFormatedInputLabel(this.zeroString, 4));
        this.input4Label.setStyleName(Style.LOGIC_INPUT_VALUE_LABEL);
        this.circuitGrid.setWidget(4, 0, this.input4Label);

        // Gates (level A)
        this.gateA1Image = new Image(this.resources.smallUNKNOWN());
        this.circuitGrid.setWidget(0, 2, this.gateA1Image);
        this.gateA2Image = new Image(this.resources.smallUNKNOWN());
        this.circuitGrid.setWidget(2, 2, this.gateA2Image);
        this.gateA3Image = new Image(this.resources.smallUNKNOWN());
        this.circuitGrid.setWidget(4, 2, this.gateA3Image);

        // Gates (level B)
        this.gateB1Image = new Image(this.resources.smallUNKNOWN());
        this.circuitGrid.setWidget(1, 4, this.gateB1Image);
        this.gateB2Image = new Image(this.resources.smallUNKNOWN());
        this.circuitGrid.setWidget(3, 4, this.gateB2Image);

        // Gates (level C)
        this.gateC1Image = new Image(this.resources.smallUNKNOWN());
        this.circuitGrid.setWidget(2, 6, this.gateC1Image);

        // Connections
        for (final RowColumnPair pair : RowColumnPair.getRowsColumnPairs()) {
            final Image pairImage = new Image(pair.getImageResourceMobile(this.resources));
            this.circuitGrid.setWidget(pair.getRow(), pair.getColumn() + 1, pairImage);
        }

        // Setting the Unknown Gate
        this.unknownGateImage = this.gateA2Image;
        this.unknownGateImage.addStyleName(Style.LOGIC_MOUSE_POINTER_HAND);
        this.changeUnknownGateDialogBox = new MobileChangeUnknownGateDialogBox(this);

        this.circuitPanel.setCellHorizontalAlignment(this.circuitGrid, HasHorizontalAlignment.ALIGN_RIGHT);
        this.circuitPanel.setCellVerticalAlignment(webcamWidget, HasVerticalAlignment.ALIGN_MIDDLE);
        this.circuitPanel.setCellHorizontalAlignment(webcamWidget, HasHorizontalAlignment.ALIGN_LEFT);
        this.removableWidgetsPanel.add(this.circuitPanel);

        // Messages
        this.messages = new WlWaitingLabel("Receiving the circuit");
        this.messages.start();
        this.removableWidgetsPanel.add(this.messages.getWidget());

        // Send Solution button
        this.sendSolutionButton = new Button(i18n.sendSolution());
        this.sendSolutionButton.setEnabled(false);
        this.sendSolutionButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                MobileLogicExperiment.this.sendCommand(new SolveCircuitCommand(MobileLogicExperiment.this.circuit));
                MobileLogicExperiment.this.messages.setText("Sending solution");
                MobileLogicExperiment.this.messages.start();
            }
        });
        this.removableWidgetsPanel.add(this.sendSolutionButton);

        this.sendCommand(new GetCircuitCommand());
    }

    @Override
    public void setTime(int time) {
        this.timer.updateTime(time);
    }

    @Override
    public Widget getWidget() {
        return this.widget;
    }

    @Override
    public void end() {
        if (this.webcam != null) {
            this.webcam.setVisible(false);
            this.webcam.dispose();
            this.webcam = null;
        }
        if (this.timer != null) {
            this.timer.dispose();
            this.timer = null;
        }
        if (this.messages != null) {
            this.messages.dispose();
        }

        if (this.sendSolutionButton != null) {
            this.sendSolutionButton.setVisible(false);
        }
    }

    @Override
    public boolean expectsPostEnd() {
        return true;
    }

    @Override
    public void postEnd(String initialData, String endData) {
        if (endData == null) {
            this.messages.setText("Finished. Waiting for your punctuation...");
        } else {
            this.messages.setText("Finished. Your punctuation: " + endData);
            this.widget.add(new HTML("Check the ranking <a href=\"" + WebLabClient.baseLocation
                    + "/weblab/admin/winners.py\">here</a>"));
        }
    }

    private int getWebcamRefreshingTime() {
        return this.configurationRetriever.getIntProperty(MobileLogicExperiment.LOGIC_WEBCAM_REFRESH_TIME_PROPERTY,
                MobileLogicExperiment.DEFAULT_LOGIC_WEBCAM_REFRESH_TIME);
    }

    private void sendCommand(Command command) {
        this.lastCommand = command;
        this.boardController.sendCommand(command, this.commandCallback);
    }

    private void processCommandSent(ResponseCommand responseCommand) {
        if (this.lastCommand instanceof GetCircuitCommand) {
            this.messages.stop();
            this.messages.setText("");
            final CircuitParser circuitParser = new CircuitParser();
            try {
                this.circuit = circuitParser.parseCircuit(responseCommand.getCommandString());
            } catch (final InvalidCircuitException e) {
                this.messages.setText("Invalid Circuit received: " + e.getMessage());
                return;
            }
            this.sendSolutionButton.setEnabled(false);
            this.updateCircuitGrid();
        } else if (this.lastCommand instanceof SolveCircuitCommand) {
            this.messages.stop();

            if (responseCommand.getCommandString().startsWith("FAIL")) {
                this.solving = false;
                this.messages.setText(i18n.wrongOneGameOver(this.points));
                this.sendSolutionButton.setEnabled(false);
            } else if (responseCommand.getCommandString().startsWith("OK")) {
                this.points++;
                this.messages.setText(i18n.wellDone1point());
                turnOnLight();
                final Timer sleepTimer = new Timer() {

                    @Override
                    public void run() {
                        MobileLogicExperiment.this.sendCommand(new GetCircuitCommand());
                        turnOffLight();
                    }
                };
                sleepTimer.schedule(2000);
            }
        } else {
            // TODO: Unknown command!
        }
    }

    void turnOffLight() {
        this.light.setUrl(GWT.getModuleBaseURL() + "/img/bulb_off.png");
    }

    void turnOnLight() {
        this.light.setUrl(GWT.getModuleBaseURL() + "/img/bulb_on.png");
    }

    private void updateCircuitGrid() {
        final Gate gateC1 = this.circuit.getRoot();
        final Gate gateB1 = (Gate) gateC1.getRight();
        final Gate gateB2 = (Gate) gateC1.getLeft();
        final Gate gateA1 = (Gate) gateB1.getRight();
        final Gate gateA2 = (Gate) gateB1.getLeft();
        final Gate gateA3 = (Gate) gateB2.getLeft();
        final Switch switch1 = (Switch) gateA1.getRight();
        final Switch switch2 = (Switch) gateA1.getLeft();
        final Switch switch3 = (Switch) gateA2.getLeft();
        final Switch switch4 = (Switch) gateA3.getLeft();

        this.circuitGrid.setWidget(2, 6, new Image(this.getURL(gateC1.getOperation())));
        this.circuitGrid.setWidget(1, 4, new Image(this.getURL(gateB1.getOperation())));
        this.circuitGrid.setWidget(3, 4, new Image(this.getURL(gateB2.getOperation())));
        this.circuitGrid.setWidget(0, 2, new Image(this.getURL(gateA1.getOperation())));
        this.circuitGrid.setWidget(2, 2, new Image(this.getURL(gateA2.getOperation())));
        this.circuitGrid.setWidget(4, 2, new Image(this.getURL(gateA3.getOperation())));

        this.input1Label.setHTML(this.getFormatedInputLabel(switch1.turned ? this.oneString : this.zeroString, 1));
        this.input2Label.setHTML(this.getFormatedInputLabel(switch2.turned ? this.oneString : this.zeroString, 2));
        this.input3Label.setHTML(this.getFormatedInputLabel(switch3.turned ? this.oneString : this.zeroString, 3));
        this.input4Label.setHTML(this.getFormatedInputLabel(switch4.turned ? this.oneString : this.zeroString, 4));

        this.setUnknownGate(this.resources.smallUNKNOWN());
    }

    private String getFormatedInputLabel(String labelText, int inputNumber) {
        switch (inputNumber) {
        case 1:
            return labelText + "<br /><br />";
        case 4:
            return "<br />" + labelText;
        default:
            return labelText;
        }
    }
}