// CryptKey.java, version 1.06, file created, November 15, 2004.
//
// Applet for generating XOR encryption keys.
//
// This file last updated June 7, 2007, by Rick Wagner.
// Copyright 2004-2006 by Rick Wagner, all rights reserved.
//
// Use of this source code is authorized for educational purposes only. No use without
// proper attribution to Rick Wagner (http://iris.usc.edu/home/iris/rwagner/
// e-mail: Richard.J.Wagner@gmail.com).
//
// The prefix naming convention used here is a modified Hungarian notation.
// "s" is string, "sf" is single precision floating point, "i" is integer, "b" is boolean,
// and "d" is dimension.

import java.applet.*;
import java.awt.*;

public class CryptKey extends Applet
{
  // Applet instance variables:
  private final String sVerNum = "1.06";                    // Only constructors can run here ("" is a constructor).
  private final String sCompiledDate = "June 7, 2007";      // Compiled date.

  private Dimension dApplet = null;                         // The applet panel size (set in calling html).
  private Image imOffScreen = null;                         // Offscreen image for double buffering.
  private Graphics grOffScreen = null;                      // Offscreen graphics for double buffering.

  private Button btnComputeKey = null;

  private TextArea taCryptText = null;
  private TextArea taPlainText = null;
  private TextArea taKeyText = null;

  private Label lblOne = null;                              // First label.
  private Label lblTwo = null;                              // Second label.
  private Label lblThree = null;                            // Third label.
  private Label lblMessage = null;                          // Message label.

  // To allow browsers to get information about the applet (not yet implemented in Netscape nor in MSIE):
  public String getAppletInfo()
  {
    return "XOR encryption key applet, version " + sVerNum +
           ", by Rick Wagner, copyright 2004-2007,\nall rights reserved.\n\n" +
           "Compiled " + sCompiledDate + ". Source code use authorized for\n" +
           "educational purposes only. No use without attribution.\n";
  }

  // Initialize the applet
  public void init()
  {
    int i = 0;
    GridBagLayout gbl = null;                               // GridBagLayout is used for the applet GUI layout.
    GridBagConstraints gbc = null;

    this.setBackground(Color.lightGray);
    dApplet = this.size();

    gbl = new GridBagLayout();
    this.setLayout(gbl);

    gbc = new GridBagConstraints();
    gbc.insets = new Insets(5, 10, 5, 10);                  // top, left, bottom, right.
    gbc.weightx = 0.0;
    gbc.weighty = 0.0;
    gbc.gridx = 0;


    // First Label
    lblOne = new Label("Encrypted Text", Label.CENTER);
    gbc.gridy = 0;
    gbl.setConstraints(lblOne, gbc);
    this.add(lblOne);

    // Add the crypt text box:
    taCryptText = new TextArea("", 6, 80);                  // 6 rows and 80 columns.
    taCryptText.setEditable(true);
    gbc.gridy = 1;
    gbl.setConstraints(taCryptText, gbc);
    this.add(taCryptText);

    // Second Label
    lblTwo = new Label("Plain (decrypted) Text", Label.CENTER);
    gbc.gridy = 2;
    gbl.setConstraints(lblTwo, gbc);
    this.add(lblTwo);

    // Add the plain text box:
    taPlainText = new TextArea("", 6, 80);                   // 6 rows and 80 columns.
    taPlainText.setEditable(true);
    gbc.gridy = 3;
    gbl.setConstraints(taPlainText, gbc);
    this.add(taPlainText);

    // Message Label
    lblMessage = new Label("          Welcome to the XOR encryption key applet." +
                           "Type or paste text into the upper two text boxes.          ", Label.CENTER);
    gbc.gridy = 4;
    gbl.setConstraints(lblMessage, gbc);
    this.add(lblMessage);

    // Add the Compute Key button:
    btnComputeKey = new Button("Compute Key");               // The compute button.
    btnComputeKey.setForeground(Color.black);
    btnComputeKey.setBackground(Color.lightGray);
    gbc.gridy = 5;
    gbl.setConstraints(btnComputeKey, gbc);
    this.add(btnComputeKey);

    // Third Label
    lblThree = new Label("Key Text", Label.CENTER);
    gbc.gridy = 6;
    gbl.setConstraints(lblThree, gbc);
    this.add(lblThree);

    // Add the key text box:
    taKeyText = new TextArea("", 6, 80);                     // 6 rows and 80 columns.
    taKeyText.setEditable(true);
    gbc.gridy = 7;
    gbl.setConstraints(taKeyText, gbc);
    this.add(taKeyText);

  } // End of init()

  // Execute this code after initialization
  public void start()
  {
    System.out.println("\n" + this.getAppletInfo());         // Identify self to the Java console-aware user
    taCryptText.requestFocus();
  }                                                          // End of start()

  // Implements double buffering 
  public void update(Graphics g)
  {
    if (imOffScreen == null)
    {
      // Make sure the offscreen and graphics exist:
      imOffScreen = this.createImage(dApplet.width, dApplet.height);
      grOffScreen = imOffScreen.getGraphics();
      grOffScreen.clearRect(0, 0, dApplet.width, dApplet.height);
    }
    this.paint(grOffScreen);
    g.drawImage(imOffScreen, 0, 0, null);
  }

  // The applet frame painting function
  public void paint(Graphics g)
  {
    // Code for displaying images or drawing in the applet frame (called by the OS).
    g.clearRect(0, 0, dApplet.width, dApplet.height);        // Needed for double buffering.
    this.setBackground(Color.lightGray);                     // Ditto.
  
    drawFrame(g);                                            // Draw the frame abound the applet.
  }                                                          // End of paint()

  private void drawFrame(Graphics g)
  {
    // Draw a recessed frame around the applet border. Designed for gray-on-gray browser background.
    g.setColor(Color.black);
    g.drawLine(0, 0, dApplet.width - 1, 0);
    g.drawLine(0, 0, 0, dApplet.height - 1);
    g.setColor(Color.white);
    g.drawLine(0, dApplet.height - 1, dApplet.width - 1, dApplet.height - 1);
    g.drawLine(dApplet.width - 1, 1, dApplet.width - 1, dApplet.height - 1);
  }

  public boolean action(Event e, Object o)
  {
    if (e.target == btnComputeKey)
    {
      btnComputeKey.disable();
      if (taCryptText.getText().length() == 0)
      {
        System.out.println("Cryptext Empty");
      }
      else
      {
        System.out.println("Cryptext Not Empty");
        if (taPlainText.getText().length() == 0)
        {
          System.out.println("Plaintext Empty");
        }
        else
        {
          // We can do the key computation
          System.out.println("Plaintext Not Empty");
          computeKey();
        }
      }
      btnComputeKey.enable();
    }
    return true;                                              // Absorb the event;
  }                                                           // End of action().

  private void computeKey()
  {
    int i = 0;
    int iCryptLength = 0;
    int iPlainLength = 0;
    int iTemp = 0;
    String sCryptText = null;
    String sPlainText = null;
    String sKeyText = null;
    StringBuffer sbTemp = null;

    sCryptText = taCryptText.getText();
    sPlainText = taPlainText.getText();

    iCryptLength = sCryptText.length();
    iPlainLength = sPlainText.length();
    System.out.println("\n");

    if (iCryptLength < iPlainLength)
    {
      // Pad out the crypttext.
      System.out.println("Padding the crypttext with spaces.");
      lblMessage.setText("Padding the crypttext with spaces.");
      sbTemp = new StringBuffer();
      for (i = iCryptLength; i < iPlainLength; i++)
      {
        sbTemp.append(" ");
      }
      sCryptText = sCryptText + sbTemp.toString();
      taCryptText.setText(sCryptText);
      iCryptLength = sCryptText.length();
    }
    else
    {
      if (iPlainLength < iCryptLength)
      {
        // Pad out the plaintext.
        System.out.println("Padding the plaintext with spaces.");
        lblMessage.setText("Padding the plaintext with spaces.");
        sbTemp = new StringBuffer();
        for (i = iPlainLength; i < iCryptLength; i++)
        {
          sbTemp.append(" ");
        }
        sPlainText = sPlainText + sbTemp.toString();
        taPlainText.setText(sPlainText);
        iPlainLength = sPlainText.length();
      }
      else
      {
        // They are equal in length, do nothing.
      }
    }

    // Begin the key computation.
    sbTemp = new StringBuffer();
    System.out.println("Writing encrypted text as numeric code.");
    lblMessage.setText("Writing encrypted text as numeric code.");

    for (i = 0; i < iCryptLength; i++)
    {
      iTemp = sCryptText.charAt(i) ^ sPlainText.charAt(i);

      if (i == iCryptLength - 1)
      {
        sbTemp.append(iTemp);
      }
      else
      {
        sbTemp.append(iTemp + " ");
      }
    }
    taKeyText.setText(sbTemp.toString());
  }                                                                       // End of computeKey().

} // End of Applet class CryptKey
