/**
* Copyright (c) 2014 Matthias Jaenicke <matthias.jaenicke@student.kit.edu>,
* Matthias Plappert <undkc@student.kit.edu>,
* Julien Duman <uncyc@student.kit.edu>,
* Christian Dreher <uaeef@student.kit.edu>,
* Wasilij Beskorovajnov <uajkm@student.kit.edu> and
* Aydin Tekin <aydin.tekin@student.kit.edu>
*
* Released under the MIT license (refer to LICENSE.md)
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package edu.kit.iks.Cryptographics.Caesar.Demonstration;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.BorderFactory;
import javax.swing.JTextField;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.xnap.commons.i18n.I18n;
import edu.kit.iks.Cryptographics.VisualizationContainerController;
import edu.kit.iks.Cryptographics.Caesar.Experiment.CryptoModel;
import edu.kit.iks.CryptographicsLib.AbstractVisualizationController;
import edu.kit.iks.CryptographicsLib.AbstractVisualizationInfo;
import edu.kit.iks.CryptographicsLib.AlphabetStripView;
import edu.kit.iks.CryptographicsLib.Configuration;
import edu.kit.iks.CryptographicsLib.ImageView;
import edu.kit.iks.CryptographicsLib.KeyboardView;
import edu.kit.iks.CryptographicsLib.Logger;
import edu.kit.iks.CryptographicsLib.MouseClickListener;
/**
* Controller for the last step of demonstration phase. Controls the needed elements from
* {@link CryptoDemonstrationView}
*
* @author Wasilij Beskorovajnov.
*
*/
public class CryptoDemonstrationController extends
AbstractVisualizationController {
/**
* localization.
*/
private static I18n i18n = Configuration.getInstance().getI18n(
CryptoDemonstrationController.class);
/**
* Identicates the step of the demonstration.
*/
private int demonstrationStep;
/**
* Indicates how much fields left to edit.
*/
private int editableFields;
/**
* The model of this controller.
*/
private CryptoModel model;
private Element cryptoResources;
/**
* Constructor.
*
* @param visualizationInfo
*/
public CryptoDemonstrationController(
AbstractVisualizationInfo visualizationInfo) {
super(visualizationInfo);
SAXBuilder saxBuilder = new SAXBuilder();
// obtain file object
InputStream is = this.getClass().getResourceAsStream(
"/caesar/CaesarResources.xml");
try {
// converted file to document object
Document document = saxBuilder.build(is);
// get root node from xml
this.cryptoResources = document.getRootElement();
} catch (JDOMException | IOException e) {
Logger.error(e);
}
}
@Override
public void loadView() {
this.view = new CryptoDemonstrationView();
this.model = CryptoModel.getInstance();
// set the initial first step.
this.demonstrationStep = 1;
// generate ActionListener for the navigationButtons.
this.generateNavigationListener();
// generate ActionListener for the forwarding button proceed.
this.generateProceedListener();
for (int i = 1; i < this.getView().getUserOutput().length; i++) {
// Needed for delegating to the inner type ActionListener, when the actionEvent from the
// Button "ENTER" on the Keyboard is fired.
final JTextField userOutput = this.getView().getUserOutput()[i];
// FocusListener for the textfields.
this.generateUserOutputFocusListener(i, userOutput);
// actionListener for the textfields.
this.generateUserOutputActionListener(i, userOutput);
}
this.getView().validate();
}
/**
* Gets the view
*
* @return The view of this controller
*/
@Override
public CryptoDemonstrationView getView() {
return (CryptoDemonstrationView) this.view;
}
// ---------------------------------------------------------//
// -----------------private methods-------------------------//
/**
* Function for performing the needed demonstration. After each step the demonstration stops and
* continues when user wishes.
*
* @param step
* {@link demonstrationStep}
*/
private void demonstrate(int step) {
switch (step) {
case 1:
this.step1();
break;
case 2:
this.step2();
break;
case 3:
this.step3();
break;
default:
}
}
private void generateUserOutputActionListener(int i,
final JTextField userOutput) {
this.getView().getUserOutput()[i]
.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (userOutput.isEditable()) {
if (CryptoDemonstrationController.this.getModel()
.enc(3, userOutput.getName())
.equals(userOutput.getText())) {
// user encrypted the given char successful.
CryptoDemonstrationController.this
.presentSuccessfullCharEncrypt(userOutput);
if (CryptoDemonstrationController.this
.getEditableFields() == 0
&& CryptoDemonstrationController.this
.getAnimationStep() == 4) {
// User encrypted all characters valid.
CryptoDemonstrationController.this
.getView()
.getExplanations()
.setText(
CryptoDemonstrationController.this
.wrapHtml(CryptoDemonstrationController.i18n
.tr("Great work oh mighty Caesar. May your enemies shutter over your intelligence."
+ " Now we can move on to the real experiment and test your skills.")));
// remove all unnecessary elements.
CryptoDemonstrationController.this
.presentFinish();
CryptoDemonstrationController.this
.getView().removeKeyboard();
} else if (CryptoDemonstrationController.this
.getEditableFields() == 0
&& CryptoDemonstrationController.this
.getAnimationStep() == 3) {
// User has to encrypt the last 3 fields.
CryptoDemonstrationController.this
.prepareNextToLastStep(userOutput);
CryptoDemonstrationController.this
.getView()
.getExplanations()
.setText(
CryptoDemonstrationController.this
.wrapHtml(CryptoDemonstrationController.i18n
.tr("Very nice! Let's encrypt the rest of your name. Touch proceed.")));
CryptoDemonstrationController.this.setFeedbackImage("CaesarPositive");
} else {
// User encrypted correctly the given char.
CryptoDemonstrationController.this
.getView()
.getExplanations()
.setText(
CryptoDemonstrationController.this
.getModel()
.genRandomGrats()
+ " "
+ CryptoDemonstrationController.i18n
.trn("Only {0} left.",
"Only {0} left.",
CryptoDemonstrationController.this
.getEditableFields(),
CryptoDemonstrationController.this
.getEditableFields()));
CryptoDemonstrationController.this.setFeedbackImage("CaesarPositive");
// The next textfield to the right requests now the focus.
CryptoDemonstrationController.this
.getView().getUserOutput()[CryptoDemonstrationController.this
.getView().getUserOutput().length
- CryptoDemonstrationController.this
.getEditableFields()]
.requestFocus();
}
} else {
// User didn't encrypt correctly.
CryptoDemonstrationController.this
.getView()
.getExplanations()
.setText(
CryptoDemonstrationController.this
.getModel()
.genRandomBlamings());
userOutput.setText("");
CryptoDemonstrationController.this.setFeedbackImage("CaesarNegative");
userOutput.requestFocus();
}
}
}
});
}
private void setFeedbackImage(String resourceID) {
this.getView().getFeedback().removeAll();
String path = "";
try {
path = CryptoDemonstrationController.this.getCryptoResource()
.getChild("CryptoResources").getChild(resourceID)
.getAttributeValue("path");
} catch (NullPointerException nullException) {
//Element not found.
System.out.println("[NullPointerException] Ressource not found.");
nullException.printStackTrace();
}
GridBagConstraints imgConstraint = new GridBagConstraints();
imgConstraint.gridx = this.getView().getUserInput().length + 1;
imgConstraint.gridy = 0;
ImageView imageToSet = new ImageView(path);
this.getView().getFeedback().add(imageToSet, imgConstraint);
this.getView().validate();
this.getView().repaint();
}
private void generateUserOutputFocusListener(int i,
final JTextField userOutput) {
this.getView().getUserOutput()[i].addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
JTextField output = (JTextField) e.getSource();
// resets the highlighting.
CryptoDemonstrationController.this.resetStateOfIOFields();
if (CryptoDemonstrationController.this.getView().getKeyboard() != null) {
// remove the keyboard.
CryptoDemonstrationController.this.getView()
.removeKeyboard();
}
if (output.isEditable()) {
// highlights the character in the alphabet.
CryptoDemonstrationController.this
.highlightInputField(userOutput);
}
}
@Override
public void focusLost(FocusEvent e) {
// Nothing to do here.
}
});
}
private void generateProceedListener() {
this.getView().getProceed().addMouseListener(new MouseClickListener() {
@Override
public void clicked(MouseEvent e) {
CryptoDemonstrationController.this
.demonstrate(CryptoDemonstrationController.this
.getAnimationStep());
}
});
}
private void generateNavigationListener() {
this.getView().getBackButton().addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
VisualizationContainerController containerController = (VisualizationContainerController) CryptoDemonstrationController.this
.getParentController();
containerController.presentPreviousVisualizationController();
}
});
this.getView().getNextButton().addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
VisualizationContainerController containerController = (VisualizationContainerController) CryptoDemonstrationController.this
.getParentController();
containerController.presentNextVisualizationController();
}
});
}
private void prepareNextToLastStep(JTextField userOutput) {
this.getView().requestFocus();
this.getView().removeKeyboard();
this.getView().getProceed().setVisible(true);
this.getView()
.getAlphabet()
.unHighlight(
userOutput.getName().charAt(0)
- this.getModel().ASCII_UC_A);
}
private void presentSuccessfullCharEncrypt(JTextField userOutput) {
userOutput.setBorder(BorderFactory.createLineBorder(Color.green));
this.setEditableFields(this.getEditableFields() - 1);
userOutput.setEditable(false);
}
private void presentFinish() {
this.getView().removeAlphabet();
this.getView().getNavigationPanel()
.remove(this.getView().getNextButton());
GridBagConstraints nextConst = new GridBagConstraints();
nextConst.anchor = GridBagConstraints.CENTER;
nextConst.weightx = 1.0;
nextConst.weighty = 0.1;
nextConst.gridx = 1;
nextConst.gridy = 1;
nextConst.gridwidth = 26;
nextConst.gridheight = 2;
this.getView().add(this.getView().getNextButton(), nextConst);
this.getView().requestFocus();
}
private void highlightInputField(JTextField output) {
int charToEncryptAscii = output.getName().charAt(0);
AlphabetStripView viewAlphabet = this.getView().getAlphabet();
viewAlphabet.highlight(charToEncryptAscii - this.getModel().ASCII_UC_A);
output.setBorder(BorderFactory.createLineBorder(Color.blue, 5));
this.getView().createKeyboard(output, KeyboardView.CHAR_MODE);
}
private void resetStateOfIOFields() {
for (JTextField outputIterator : this.getView().getUserOutput()) {
if (outputIterator.getText() != null
&& CryptoDemonstrationController.this.getView()
.getAlphabet() != null) {
int charToEncryptAscii = outputIterator.getName().charAt(0);
AlphabetStripView viewAlphabet = CryptoDemonstrationController.this
.getView().getAlphabet();
viewAlphabet
.unHighlight(charToEncryptAscii
- CryptoDemonstrationController.this.getModel().ASCII_UC_A);
if (outputIterator.isEditable()) {
outputIterator.setBorder(BorderFactory
.createLineBorder(Color.darkGray));
}
}
}
}
/**
* Explain the elements on the screen. Only explanations are shown.
*/
private void step1() {
this.demonstrationStep++;
this.getView()
.getExplanations()
.setText(
this.wrapHtml(CryptoDemonstrationController.i18n
.tr("Because of your inferior intelligence you look at the first letter of your name: C."
+ " Then you look at the 3rd letter after C and take F. Great! Now you encrypted the"
+ " first letter of your name. Touch proceed.")));
// setup the alphabet.
this.getView().setupAlphabet();
this.getView().getUserInput()[0].setBorder(BorderFactory
.createLineBorder(Color.green));
this.getView().getUserOutput()[0].setBorder(BorderFactory
.createLineBorder(Color.green));
this.getView().getUserOutput()[0].setText("F");
this.getView().validate();
}
/**
* Describe how each character is encrypted.
*/
private void step2() {
this.demonstrationStep++;
this.editableFields = 1;
this.getView().getProceed().setVisible(false);
this.getView().getUserInput()[0].setBorder(null);
this.getView().getUserOutput()[0].setBorder(null);
this.getView()
.getExplanations()
.setText(
this.wrapHtml(CryptoDemonstrationController.i18n
.tr("Now try to encrypt the next letter yourself."
+ " If you need help, you can always use the help button.")));
this.getView().getUserInput()[1].setBorder(BorderFactory
.createLineBorder(Color.green));
this.getView().getUserOutput()[1].setEditable(true);
this.getView().getUserOutput()[1].requestFocus();
this.getView().validate();
}
/**
* Describe the general Caesar cipher. (The key can vary from 1-26.)
*/
private void step3() {
this.demonstrationStep++;
this.editableFields = (this.getView().getUserInput().length - 2);
this.getView().getForwardingViewContainer().remove(this.getView().getProceed());
this.getView().setProceed(null);
this.getView().getUserInput()[1].setBorder(null);
this.getView().getUserOutput()[1].setBorder(null);
for (int i = 2; i < this.getView().getUserInput().length; i++) {
this.getView().getUserOutput()[i].setEditable(true);
}
this.getView()
.getExplanations()
.setText(
this.wrapHtml(CryptoDemonstrationController.i18n
.tr("Oh mighty Caesar. No one will ever be able to destroy you! Because of that fact lets end"
+ " this childish games and finish the rest of the fields fast. Then we can send the courier again"
+ " but this time your enemies will have no idea who wrote it and you will conquer the world.")));
this.getView().getUserOutput()[2].requestFocus();
this.getView().validate();
}
// -------------------------------------------------------//
// -------------------Getter/Setter-----------------------//
/**
* @return the animationStep
*/
public int getAnimationStep() {
return this.demonstrationStep;
}
/**
* @return the editableFields
*/
public int getEditableFields() {
return this.editableFields;
}
@Override
public String getHelp() {
String help = CryptoDemonstrationController.i18n
.tr("Remember: Position of C in the alphabet is 3 and the key is also 3. C + key = C + 3 = 3 + 3 = 6."
+ " And 6 is the position of letter F in the alphabet. Et voila you encrypted C with the key of 3.");
return help;
}
/**
* @return the model
*/
public CryptoModel getModel() {
return this.model;
}
/**
* @param animationStep
* the animationStep to set
*/
public void setAnimationStep(int animationStep) {
this.demonstrationStep = animationStep;
}
/**
* @param editableFields
* the editableFields to set
*/
public void setEditableFields(int editableFields) {
this.editableFields = editableFields;
}
/**
* @param model
* the model to set
*/
public void setModel(CryptoModel model) {
this.model = model;
}
@Override
public void unloadView() {
this.view = null;
}
private String wrapHtml(String text) {
return "<html><body><div width=700px>" + text + "</div></body></html>";
}
/**
* @return the cryptoResource
*/
public Element getCryptoResource() {
return cryptoResources;
}
/**
* @param cryptoResource the cryptoResource to set
*/
public void setCryptoResource(Element cryptoResource) {
this.cryptoResources = cryptoResource;
}
}