// "Permutations and Combinations"
// Version 2.2
// Written by Patrick R. McAtee
// For CSCE235, Fall 2001, Instructor Chuck Cusack
// ****************************************************************************
// This is a simple applet that calculates permutations and combinations.
// This program was created to be a part of a website in development called
// "TACSE," Tutorials and Applets for Computer Science Education.  TACSE is the
// brainchild of Dr. Charles Cusack, computer science professor at University
// of Nebraska-Lincoln.  In the future, the TACSE site will be a one-stop shop
// to learn about computer science and its surrounding topics.
// ****************************************************************************
// Do I need to document the code well enough that someone who doesn't know
// JAVA could use it?  Will other people be able to use this code or just view
// it?  Are you planning on linking to our page
// or inserting our stuff onto the TACSE page itself?  Will we need to include
// instructions on how to change the JAVA runtime environment of the various
// possible browsers and OS's?  Is the grading scale going to be changed?

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


public class PermComb extends JApplet implements ActionListener{
  JButton jPermButton = new JButton();
  JButton jCombButton = new JButton();
  JButton jClearButton = new JButton();
  JButton jHelpButton = new JButton();
  JTextField npField = new JTextField();
  JTextField rpField = new JTextField();
  JTextField ncField = new JTextField();
  JTextField rcField = new JTextField();
  JTextField pAnswerField = new JTextField();
  JTextField cAnswerField = new JTextField();

  //Construct the applet
  public void init() {
    this.setVisible(true);
    this.getContentPane().setLayout(null);
    this.getContentPane().setBackground(Color.yellow);


  // This code is documented out because I like the default look and feel
  // but I left it in so that it could be easily changed in the future.
  /*try {
    UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
    SwingUtilities.updateComponentTreeUI(this);
    }
    catch (Exception e) {}*/

    Setup();
  }

  public void Setup() {
  //Label, always more labels...
    JLabel PermLabel = new JLabel("Permutation:");
    PermLabel.setBounds(10,20,100,20);
    PermLabel.setForeground(Color.black);
    this.getContentPane().add(PermLabel);
    JLabel CombLabel = new JLabel("Combination:");
    CombLabel.setBounds(215,20,75,20);
    CombLabel.setForeground(Color.black);
    this.getContentPane().add(CombLabel);
  //Creating the Permutation Button
    JLabel PnrLabel = new JLabel("P (n , r)");
    PnrLabel.setForeground(Color.black);
    jPermButton.setBounds(10,115,100,25);
    this.getContentPane().add(jPermButton);
    jPermButton.add(PnrLabel);
    jPermButton.addActionListener(this);
    jPermButton.setActionCommand("perm");
  //Creating the Combination Button
    JLabel CnrLabel = new JLabel("C (n , r)");
    CnrLabel.setForeground(Color.black);
    jCombButton.setBounds(190,115,100,25);
    this.getContentPane().add(jCombButton);
    jCombButton.add(CnrLabel);
    jCombButton.addActionListener(this);
    jCombButton.setActionCommand("comb");
  //Creating the text fields where the n and r values can be input
    npField.setBounds(23,50,60,20);
    this.getContentPane().add(npField);
    ncField.setBounds(230,50,60,20);
    this.getContentPane().add(ncField);
    rpField.setBounds(23,80,60,20);
    this.getContentPane().add(rpField);
    rcField.setBounds(230,80,60,20);
    this.getContentPane().add(rcField);
  //Labeling the input fields
    JLabel npLabel = new JLabel ("n:");
    npLabel.setForeground(Color.black);
    npLabel.setBounds(10,55,10,10);
    this.getContentPane().add(npLabel);
    JLabel ncLabel = new JLabel ("n:");
    ncLabel.setForeground(Color.black);
    ncLabel.setBounds(217,55,10,10);
    this.getContentPane().add(ncLabel);
    JLabel rpLabel = new JLabel ("r:");
    rpLabel.setForeground(Color.black);
    rpLabel.setBounds(10,85,10,10);
    this.getContentPane().add(rpLabel);
    JLabel rcLabel = new JLabel ("r:");
    rcLabel.setForeground(Color.black);
    rcLabel.setBounds(217,85,10,10);
    this.getContentPane().add(rcLabel);
  //Creating the fields where the answer will appear, I've decided to make
  //separate fields for permutations and combinations because you might
  //have a need to compare the two simultaneously.
    JLabel pAnswerLabel = new JLabel("< Answers >");
    pAnswerLabel.setForeground(Color.black);
    pAnswerLabel.setBounds(115,155,74,10);
    this.getContentPane().add(pAnswerLabel);
    pAnswerField.setBounds(10,150,100,20);
    this.getContentPane().add(pAnswerField);
    //JLabel cAnswerLabel = new JLabel("Answer:");
    //cAnswerLabel.setForeground(Color.black);
    //cAnswerLabel.setBounds(140,175,60,10);
    //this.getContentPane().add(cAnswerLabel);
    cAnswerField.setBounds(190,150,100,20);
    this.getContentPane().add(cAnswerField);
  //creating buttons that allow user to clear the fields
    jClearButton.setBounds(10,210,110,25);
    this.getContentPane().add(jClearButton);
    JLabel ClearLabel = new JLabel("Clear Fields");
    ClearLabel.setForeground(Color.black);
    jClearButton.add(ClearLabel);
    jClearButton.addActionListener(this);
    jClearButton.setActionCommand("Clear");
  //creating a button that could be used to make a help window pop up in the future.
    jHelpButton.setBounds(185,210,105,25);
    this.getContentPane().add(jHelpButton);
    JLabel HelpLabel = new JLabel("How To Use");
    HelpLabel.setForeground(Color.black);
    jHelpButton.add(HelpLabel);
    jHelpButton.addActionListener(this);
    jHelpButton.setActionCommand("Help");
  //draw a line...
    //g.drawLine(5,175,290,175);
  //draw a happy face...
  }

  public void actionPerformed(ActionEvent e) {
    Container contentPane = getContentPane();
    if (e.getActionCommand().equals("perm")) {
      //contentPane.setBackground(Color.red);
      long Pnr = Permutation();
      if (Pnr != 0) {
        pAnswerField.setText(Pnr+"");
      }
    }
    else if (e.getActionCommand().equals("comb")) {
      //contentPane.setBackground(Color.black);
      long Cnr = Combination();
      if (Cnr != 0) {
        cAnswerField.setText(Cnr+"");

      }
    }
    else if (e.getActionCommand().equals("Clear")) {
      //contentPane.setBackground(Color.lightGray);
      npField.setText(null);
      rpField.setText(null);
      pAnswerField.setText(null);
      ncField.setText(null);
      rcField.setText(null);
      cAnswerField.setText(null);
    }
    else if (e.getActionCommand().equals("Help")) {
      //contentPane.setBackground(Color.lightGray);
      JOptionPane.showMessageDialog(this, "To use this applet: \n Type the"+
      " values that you would like to use in your Permutation or \n Combination"+
      " into the fields marked 'n' and 'r,' then push the \n appropriate"+
      " button.  The result will be displayed in the corresponding \n answer"+
      " field.  To clear all fields, click the 'Clear Fields' button.");
    }
  }

  public long Permutation() {
    String npString = npField.getText();
    String rpString = rpField.getText();
    int npint = 0;
    int rpint = 0;

  //This method checks for errors in the data type of n and r by first attempting
  //to convert them from string type to int type.  If it recognizes that data
  //will be lost due to the type conversion, then it knows the string is not of
  //type int and is invalid.  This causes the warning to be displayed.  Next, it
  //makes sure that both numbers are positive, and finally, that the r value is
  //less than or equal to the n value, which is required for calculating the
  //permutation/combination.
    try {
      npint = Integer.parseInt(npString);
      rpint = Integer.parseInt(rpString);
    }
    catch (NumberFormatException e) {
      JOptionPane.showMessageDialog(this, "ERROR! The values for 'n' and 'r' \n must be positive integers");
      return 0;
    }
    if (npint <= 0 || rpint <= 0) {
      JOptionPane.showMessageDialog(this, "ERROR! The values for 'n' and 'r' \n must be positive integers");
      return 0;
    }
    if (npint < rpint) {
      JOptionPane.showMessageDialog(this, "ERROR! The value of 'r' must be less than \n or equal to the value of 'n.'");
      return 0;
    }

  //Here the method is making the calculation of the permutation value itself.
  //The formula is P(n,r) = n!/(n-r)!.  Initially I tried to calculate the
  //numerator and denominator separately, and then divide them, but in the
  //process of debugging the code, I created this shorter algorithm, so I used it.
    long Pnr = 1;
    int mult = npint;
    int nmr = (npint - rpint);
    while (mult>nmr) {
      Pnr = Pnr * mult;
      mult--;
    }

    return Pnr;
  }

  public long Combination() {
    String ncString = ncField.getText();
    String rcString = rcField.getText();
    int ncint = 0;
    int rcint = 0;

  //The following four statements are designed to catch errors in data placed
  //in the 'n' and 'r' fields.  For more info see the Permutation method.
    try {
      ncint = Integer.parseInt(ncString);
      rcint = Integer.parseInt(rcString);
    }
    catch (NumberFormatException e) {
      JOptionPane.showMessageDialog(this, "ERROR! The values for 'n' and 'r' \n must be positive integers");
      return 0;
    }
    if (ncint <= 0 || rcint <= 0) {
      JOptionPane.showMessageDialog(this, "ERROR! The values for 'n' and 'r' \n must be positive integers");
      return 0;
    }
    if (ncint < rcint) {
      JOptionPane.showMessageDialog(this, "ERROR! The value of 'r' must be less than \n or equal to the value of 'n.'");
      return 0;
    }

  //Here it is calculating the actual value of the combination.  The formula
  //is C(n,r) = n!/(r!(n-r)!).  I decided to implement factorial iteratively
  //rather than recursively because I didn't want to write a separate method.
    long nfact = 1;
    for (int i=2; i<=ncint; i++) {
      nfact = nfact * i;
    }
    long rfact = 1;
    for (int i=2; i<=rcint; i++) {
      rfact = rfact * i;
    }
    long nmr = ncint - rcint;
    int nmrfact = 1;
    for (int i=2; i<=nmr; i++) {
      nmrfact = nmrfact * i;
    }

    long Cnr = (nfact/(rfact * nmrfact));

    return Cnr;
  }
}

