import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.math.*;

public class DSApplet extends JApplet implements ActionListener {

  JPanel inputPanel;
  JPanel signingPanel;
  JPanel verifyPanel;

  JLabel dKeyLabel;
  JLabel nKeyLabel;
  JLabel eKeyLabel;

  //Info zu den einzelnen Schritten
  JLabel infoLabel1;
  JLabel infoLabel2;

  //Message Input
  JTextField input;
  JLabel inputLabel;

  //Buttons
  JButton nextStep;
  JButton restart;
  JPanel buttonInfoPanel ;

  //erster Berechnungsschritt (hash Wert der Message)
  JPanel hashPanel;
  JLabel hashLabel;
  JTextField hashField;

  //zweiter Berechnungsschritt (Hash Wert Konkatenieren)
  JPanel concatPanel;
  JLabel concatLabel;
  JTextField concatField;

  //dritter Berechnungsschritt (Signatur berechnen)
  JPanel calcPanel;
  JLabel calcLabel;
  JTextField calcField;

  //Signatur anzeigen
  JPanel signaturePanel ;
  JLabel signatureLabel;
  JTextField signatureField;

  //erster Entschlüsselungsschritt (m' berechnen)
  JPanel recalcPanel ;
  JLabel recalcLabel ;
  JTextField recalcField;

  //Zweiter Entschlüsselungsschritt (m' Element RM?)
  JPanel elementPanel;
  JLabel elementLabel;
  JTextField elementField;

  //Dritter Entschlüsselungsschritt (Halbieren)
  JPanel halfPanel ;
  JLabel halfLabel;
  JTextField halfField;

  //Vierter Entschlüsselungsschritt (Rehash)
  JPanel rehashPanel ;
  JLabel rehashLabel;
  JTextField rehashField;

  //Farben
  private Color background = Color.white;
  private Color foreground = Color.blue;
  private Color disabledColorBackground = Color.lightGray;

  //Counter der den aktuellen Berechnungsschritt anzeigt
  private int counter;

  public DSApplet() {
    super();
    this.setSize(new Dimension(600, 500));
  }


  public void init() {

    counter=0;

    //Layout setzen
    this.getContentPane().setLayout(null);
    this.getContentPane().setBackground(this.background);

    //Input Border
    Border defaultBorder = BorderFactory.createLineBorder(this.foreground);
    Border inputBorder = BorderFactory.createTitledBorder(defaultBorder, "Input");
    ((TitledBorder)inputBorder).setTitleColor(this.foreground);

    //Input Panel
    this.inputPanel = new JPanel();
    this.inputPanel.setBorder(inputBorder);
    this.inputPanel.setBackground(this.background);
    this.inputPanel.setLayout(new FlowLayout());
    this.inputPanel.setBounds(0,0,600,100);

    //Input Feld und Text
    this.inputLabel = new JLabel("Please insert up to 5 Characters: ");
    this.inputLabel.setForeground(this.foreground);
    this.input = new JTextField("0");
    input.setMinimumSize(new Dimension(100, 25));
    input.setPreferredSize(new Dimension(100, 25));

    //leeres Feld für Zwischenraum
    JLabel empty = new JLabel();
    empty.setMinimumSize(new Dimension(160, 10));
    empty.setPreferredSize(new Dimension(160, 10));

    this.inputPanel.add(this.inputLabel);
    this.inputPanel.add(this.input);
    this.inputPanel.add(empty);

    //Panel + Text für Keys
    JPanel keyPanel = new JPanel();
    keyPanel.setBackground(this.background);
    keyPanel.setLayout(new BoxLayout(keyPanel, BoxLayout.Y_AXIS));
    keyPanel.setPreferredSize(new Dimension(120, 55));
    keyPanel.setMaximumSize(new Dimension(120, 55));
    this.dKeyLabel = new JLabel("Private key d: 5");
    this.dKeyLabel.setForeground(this.foreground);
    this.nKeyLabel = new JLabel("Public key n: 299");
    this.nKeyLabel.setForeground(this.foreground);
    this.eKeyLabel = new JLabel("Public key e: 53");
    this.eKeyLabel.setForeground(this.foreground);
    keyPanel.add(this.dKeyLabel);
    keyPanel.add(this.nKeyLabel);
    keyPanel.add(this.eKeyLabel);
    this.inputPanel.add(keyPanel);
    this.getContentPane().add(this.inputPanel);

    //Dimensionen
    Dimension panelDim = new Dimension(350, 40);
    Dimension labelDim = new Dimension(120, 25);
    Dimension fieldDim = new Dimension(200, 25);

    //Verschluesselung
    Border signingBorder = BorderFactory.createTitledBorder(defaultBorder, "Signing Process");
    ((TitledBorder)signingBorder).setTitleColor(this.foreground);

    this.signingPanel = new JPanel();
    this.signingPanel.setLayout(new BoxLayout(signingPanel, BoxLayout.Y_AXIS));
    this.signingPanel.setBorder(signingBorder);
    this.signingPanel.setBackground(this.background);
    this.signingPanel.setBounds(0,100,600,150);

    //Feld erster Berechnungsschritt
    hashPanel = new JPanel();
    hashPanel.setBackground(this.background);
    hashPanel.setPreferredSize(panelDim);
    hashPanel.setMaximumSize(panelDim);
    hashPanel.setLayout(new FlowLayout());
    hashPanel.setVisible(false);

    hashLabel = new JLabel("hashValue: ");
    hashLabel.setForeground(this.foreground);
    hashLabel.setPreferredSize(labelDim);
    hashLabel.setVisible(false);

    hashField = new JTextField();
    hashField.setPreferredSize(fieldDim);
    hashField.setEditable(false);
    hashField.setBackground(this.disabledColorBackground);
    hashField.setVisible(false);

    hashPanel.add(hashLabel);
    hashPanel.add(hashField);
    hashPanel.setAlignmentX(Component.LEFT_ALIGNMENT);

    //zweiter Berechnungsschritt
    concatPanel = new JPanel();
    concatPanel.setBackground(this.background);
    concatPanel.setPreferredSize(panelDim);
    concatPanel.setMaximumSize(panelDim);
    concatPanel.setLayout(new FlowLayout());
    concatPanel.setVisible(false);

    concatLabel = new JLabel("R(m) = m' : ");
    concatLabel.setForeground(this.foreground);
    concatLabel.setVisible(false);
    concatLabel.setPreferredSize(labelDim);

    concatField = new JTextField();
    concatField.setPreferredSize(fieldDim);
    concatField.setEditable(false);
    concatField.setBackground(this.disabledColorBackground);
    concatField.setVisible(false);

    concatPanel.add(concatLabel);
    concatPanel.add(concatField);
    concatPanel.setAlignmentX(Component.LEFT_ALIGNMENT);

    //dritter Berechnungsschritt
    calcPanel = new JPanel();
    calcPanel.setBackground(this.background);
    calcPanel.setPreferredSize(panelDim);
    calcPanel.setMaximumSize(panelDim);
    calcPanel.setLayout(new FlowLayout());
    calcPanel.setVisible(false);

    calcLabel = new JLabel("(m')^ d (mod n) = s : ");
    calcLabel.setForeground(this.foreground);
    calcLabel.setPreferredSize(labelDim);
    calcLabel.setVisible(false);

    calcField = new JTextField();
    calcField.setPreferredSize(fieldDim);
    calcField.setEditable(false);
    calcField.setBackground(this.disabledColorBackground);
    calcField.setVisible(false);

    calcPanel.add(calcLabel);
    calcPanel.add(calcField);
    calcPanel.setAlignmentX(Component.LEFT_ALIGNMENT);

    this.signingPanel.add(hashPanel);
    this.signingPanel.add(concatPanel);
    this.signingPanel.add(calcPanel);

    this.getContentPane().add(this.signingPanel);

    //Entschlüsselung
     Border verifyBorder = BorderFactory.createTitledBorder(defaultBorder, "Verifying Process");
    ((TitledBorder)verifyBorder).setTitleColor(this.foreground);

    this.verifyPanel = new JPanel();
    this.verifyPanel.setLayout(new BoxLayout(verifyPanel, BoxLayout.Y_AXIS));
    this.verifyPanel.setBorder(verifyBorder);
    this.verifyPanel.setBackground(this.background);
    this.verifyPanel.setBounds(0,250,600,230);

    //Signatur darstellen
    signaturePanel = new JPanel();
    signaturePanel.setBackground(this.background);
    signaturePanel.setPreferredSize(panelDim);
    signaturePanel.setMaximumSize(panelDim);
    signaturePanel.setLayout(new FlowLayout());
    signaturePanel.setVisible(false);

    signatureLabel = new JLabel("Signed Message s: ");
    signatureLabel.setForeground(this.foreground);
    signatureLabel.setPreferredSize(labelDim);
    signatureLabel.setVisible(false);

    signatureField = new JTextField();
    signatureField.setPreferredSize(fieldDim);
    signatureField.setEditable(false);
    signatureField.setBackground(this.disabledColorBackground);
    signatureField.setVisible(false);

    signaturePanel.add(signatureLabel);
    signaturePanel.add(signatureField);
    signaturePanel.setAlignmentX(Component.LEFT_ALIGNMENT);

    //erster Entschlüsselungsschritt
    recalcPanel = new JPanel();
    recalcPanel.setBackground(this.background);
    recalcPanel.setPreferredSize(panelDim);
    recalcPanel.setMaximumSize(panelDim);
    recalcPanel.setLayout(new FlowLayout());
    recalcPanel.setVisible(false);

    recalcLabel = new JLabel("s^e(mod n)=m' : ");
    recalcLabel.setForeground(this.foreground);
    recalcLabel.setPreferredSize(labelDim);
    recalcLabel.setVisible(false);

    recalcField = new JTextField();
    recalcField.setPreferredSize(fieldDim);
    recalcField.setEditable(false);
    recalcField.setBackground(this.disabledColorBackground);
    recalcField.setVisible(false);

    recalcPanel.add(recalcLabel);
    recalcPanel.add(recalcField);
    recalcPanel.setAlignmentX(Component.LEFT_ALIGNMENT);

    //Zweiter Entschlüsselungsschritt
    elementPanel = new JPanel();
    elementPanel.setBackground(this.background);
    elementPanel.setPreferredSize(panelDim);
    elementPanel.setMaximumSize(panelDim);
    elementPanel.setLayout(new FlowLayout());
    elementPanel.setVisible(false);

    elementLabel = new JLabel("m' Element MR? : ");
    elementLabel.setForeground(this.foreground);
    elementLabel.setPreferredSize(labelDim);
    elementLabel.setVisible(false);

    elementField = new JTextField();
    elementField.setPreferredSize(fieldDim);
    elementField.setEditable(false);
    elementField.setBackground(this.disabledColorBackground);
    elementField.setVisible(false);

    elementPanel.add(elementLabel);
    elementPanel.add(elementField);
    elementPanel.setAlignmentX(Component.LEFT_ALIGNMENT);

    //Dritter Entschlüsselungsschritt
    halfPanel = new JPanel();
    halfPanel.setBackground(this.background);
    halfPanel.setPreferredSize(panelDim);
    halfPanel.setMaximumSize(panelDim);
    halfPanel.setLayout(new FlowLayout());
    halfPanel.setVisible(false);

    halfLabel = new JLabel("R-1(m')=m : ");
    halfLabel.setForeground(this.foreground);
    halfLabel.setPreferredSize(labelDim);
    halfLabel.setVisible(false);

    halfField = new JTextField();
    halfField.setPreferredSize(fieldDim);
    halfField.setEditable(false);
    halfField.setBackground(this.disabledColorBackground);
    halfField.setVisible(false);

    halfPanel.add(halfLabel);
    halfPanel.add(halfField);
    halfPanel.setAlignmentX(Component.LEFT_ALIGNMENT);

    //Vierter Entschlüsselungsschritt
    rehashPanel = new JPanel();
    rehashPanel.setBackground(this.background);
    rehashPanel.setPreferredSize(panelDim);
    rehashPanel.setMaximumSize(panelDim);
    rehashPanel.setLayout(new FlowLayout());
    rehashPanel.setVisible(false);

    rehashLabel = new JLabel("message");
    rehashLabel.setForeground(this.foreground);
    rehashLabel.setPreferredSize(labelDim);
    rehashLabel.setVisible(false);

    rehashField = new JTextField();
    rehashField.setPreferredSize(fieldDim);
    rehashField.setEditable(false);
    rehashField.setBackground(this.disabledColorBackground);
    rehashField.setVisible(false);

    rehashPanel.add(rehashLabel);
    rehashPanel.add(rehashField);
    rehashPanel.setAlignmentX(Component.LEFT_ALIGNMENT);

    this.verifyPanel.add(signaturePanel);
    this.verifyPanel.add(recalcPanel);
    this.verifyPanel.add(elementPanel);
    this.verifyPanel.add(halfPanel);
    this.verifyPanel.add(rehashPanel);

    this.getContentPane().add(this.verifyPanel);

    //Calculate Button
    buttonInfoPanel = new JPanel();
    buttonInfoPanel.setBackground(this.background);
    buttonInfoPanel.setLayout(null);
    this.buttonInfoPanel.setBounds(0,480,600,80);

    this.nextStep = new JButton("calculate");
    this.nextStep.setBackground(this.background);
    this.nextStep.setForeground(this.foreground);
    this.nextStep.addActionListener(this);
    this.nextStep.setBounds(170,50,100,30);

    buttonInfoPanel.add(this.nextStep);

    //restart Button
    this.restart=new JButton("start again");
    this.restart.setBackground(this.background);
    this.restart.setForeground(this.foreground);
    this.restart.addActionListener(this);
    this.restart.setBounds(290,50,100,30);

    buttonInfoPanel.add(this.restart);

    //infoLabel1
    infoLabel1 =new JLabel("Insert up to 5 characters.");
    infoLabel1.setForeground(this.foreground);
    infoLabel1.setBounds(10,0,500,30);

    buttonInfoPanel.add(this.infoLabel1);

    //infoLabel2
    this.infoLabel2 =new JLabel("");
    this.infoLabel2.setForeground(this.foreground);
    this.infoLabel2.setBounds(10,15,500,30);

    this.buttonInfoPanel.add(infoLabel2);

    buttonInfoPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
    this.getContentPane().add(buttonInfoPanel);
  }

  private void startAgain(){
    this.input.setText("");
    this.nextStep.setEnabled(true);
    this.nextStep.setVisible(true);

    hashPanel.setVisible(false);
    hashLabel.setVisible(false);
    hashField.setVisible(false);
    hashField.setText("");

    concatPanel.setVisible(false);
    concatLabel.setVisible(false);
    concatField.setVisible(false);
    concatField.setText("");

    calcPanel.setVisible(false);
    calcLabel.setVisible(false);
    calcField.setVisible(false);
    calcField.setText("");

    signaturePanel.setVisible(false);
    signatureLabel.setVisible(false);
    signatureField.setVisible(false);
    signatureField.setText("");

    recalcPanel.setVisible(false);
    recalcLabel.setVisible(false);
    recalcField.setVisible(false);
    recalcField.setText("");

    elementPanel.setVisible(false);
    elementLabel.setVisible(false);
    elementField.setVisible(false);
    elementField.setText("");

    halfPanel.setVisible(false);
    halfLabel.setVisible(false);
    halfField.setVisible(false);
    halfField.setText("");

    rehashPanel.setVisible(false);
    rehashLabel.setVisible(false);
    rehashField.setVisible(false);
    rehashField.setText("");

    this.infoLabel2.setVisible(false);
    this.nextStep.setText("calculate");
    this.input.setEnabled(true);
    this.infoLabel1.setText("Insert up to 5 characters.");
    counter=0;
  }

  public void actionPerformed(ActionEvent e) {
    if(e.getSource() == nextStep) {
      if(this.input.getText().length() > 0 &&  this.input.getText().length()<6) {
          switch(counter){
            case(0):
              this.nextStep.setText("next step");
              this.hashPanel.setVisible(true);
              this.hashLabel.setVisible(true);
              this.hashField.setVisible(true);
              this.hashField.setText(new Integer(this.input.getText().hashCode()).toString());
              this.input.setEnabled(false);
              this.infoLabel1.setText("To calculate the digital signature we need to convert the message into numbers.");
              this.infoLabel2.setText("Here we choosed a hash function.");
              this.infoLabel2.setVisible(true);
              counter++;
              break;
            case(1):
                this.concatField.setText(this.hashField.getText()+this.hashField.getText());
                this.concatField.setVisible(true);
                this.concatLabel.setVisible(true);
                this.concatPanel.setVisible(true);
                this.infoLabel1.setText("Now the function R(m) concatenates the number." );
                this.infoLabel2.setVisible(false);
                counter++;
                break;
            case(2):
              this.calcField.setText(this.calculate(this.concatField.getText()));
              this.calcField.setVisible(true);
              this.calcLabel.setVisible(true);
              this.calcPanel.setVisible(true);
              this.infoLabel1.setText("Encrypt the signature with the private key d and the public key n.");
              this.nextStep.setText("send");
              counter++;
              break;
            case(3):
              this.nextStep.setText("next step");
              this.signatureField.setVisible(true);
              this.signatureLabel.setVisible(true);
              this.signaturePanel.setVisible(true);
              this.signatureField.setText(this.calcField.getText());
              this.infoLabel1.setText("Send the message.");
              counter++;
              break;
            case(4):
              this.recalcField.setVisible(true);
              this.recalcLabel.setVisible(true);
              this.recalcPanel.setVisible(true);
              this.infoLabel1.setText("Decrypt the signature with the public key n and the public key e.");
              this.recalcField.setText(this.concatField.getText());
              counter++;
              break;
            case(5):
              this.elementField.setVisible(true);
              this.elementLabel.setVisible(true);
              this.elementPanel.setVisible(true);
              this.elementField.setText("true");
              this.infoLabel1.setText("Is the decrypted signature a element of RM, that means, is the number concatenated?");
              counter++;
              break;
            case(6):
              this.halfField.setVisible(true);
              this.halfLabel.setVisible(true);
              this.halfPanel.setVisible(true);
              this.halfField.setText(this.hashField.getText());
              this.infoLabel1.setText("If the decrypted signature is a element of RM, then half it.");
              counter++;
              break;
            case(7):
              this.nextStep.setVisible(false);
              this.nextStep.setEnabled(false);
              this.rehashField.setVisible(true);
              this.rehashLabel.setVisible(true);
              this.rehashPanel.setVisible(true);
              this.rehashField.setText(this.input.getText());
              this.infoLabel1.setText("Rehash the number to read the original message.");
              break;
            default:
              this.startAgain();
          }//switch

      }else if(this.input.getText().length() <= 0){
        infoLabel1.setText("You have to insert a message.");
        infoLabel2.setText("Please insert up to 5 characters.");
        infoLabel2.setVisible(true);

      }else if(this.input.getText().length()>=6){
        infoLabel1.setText("The message is to long.");
        infoLabel2.setText("Please insert up to 5 characters.");
        infoLabel2.setVisible(true);

      }//if
    }//if
    else if(e.getSource() == restart){
      this.startAgain();
    }//else
  }//actionPerformed


  private String calculate(String arg) {
    BigInteger keyD = new BigInteger("5");
    BigInteger keyN = new BigInteger("299");
    BigInteger result=new BigInteger(arg);
    result=result.modPow(keyD,keyN);
    return result.toString();
  }

}