/**
 * calcbigint.java - 17/05/02 - 16/09/02
 * 
 * Auteur : Jean-Paul QUELEN
 * 
 * calculatrice "biginteger"
 * modification et ajout de main() le 06/01/18 et 31/08/22
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.math.BigInteger;

public class calcbigint extends JFrame implements ActionListener {
	static final long serialVersionUID = 220831L;
	JTextField tn1 = new JTextField (30);
	JTextField tn2 = new JTextField (30);
	JTextField tn3 = new JTextField (30);
	TextArea tanr = new TextArea ("", 5, 50, TextArea.SCROLLBARS_VERTICAL_ONLY);
	BigInteger n1, n2, n3, nr, zero, un, deux, trois, maxint;
	JButton raz = new JButton ("Raz");
	JButton plus = new JButton ("+");
	JButton moins = new JButton ("-");
	JButton fois = new JButton ("*");
	JButton divise = new JButton ("/");
	JButton reste = new JButton ("%");
	JButton puissance = new JButton ("^");
	JButton pgcd = new JButton ("pgcd");
	JButton ppcm = new JButton ("ppcm");
	JButton rn1 = new JButton ("r->n1");
	JButton rn2 = new JButton ("r->n2");
	JButton rn3 = new JButton ("r->n3");
	JButton pp = new JButton ("pp");
	JButton factorisation = new JButton ("factorisation");
	JButton factorielle = new JButton ("!");
	JButton n2parmin1 = new JButton ("n2 parmi n1");
	JButton pmod = new JButton ("^%");
	JButton divmod = new JButton ("/%");
	JButton invmod = new JButton ("inv%");
	String err0;

	public calcbigint (String titre) {
		super (titre);
		setBackground (Color.lightGray);
		setLayout (new GridLayout (7, 1));

		JPanel p = new JPanel();
		p.setBackground (Color.lightGray);
		add (p);
		p.add (new JLabel ("n1 :"));
		p.add (tn1);

		add (p = new JPanel());
		p.setBackground (Color.lightGray);
		p.add (new JLabel ("n2 :"));
		p.add (tn2);

		add (p = new JPanel());
		p.setBackground (Color.lightGray);
		p.add (new JLabel ("n3 :"));
		p.add (tn3);

		add (p = new JPanel());
		p.setBackground (Color.lightGray);
		p.add (new JLabel ("r ="));
		p.add (tanr);

		add (p = new JPanel());
		p.setBackground (Color.lightGray);
		p.add (raz);
		raz.addActionListener (this);
		p.add (plus);
		plus.addActionListener (this);
		p.add (moins);
		moins.addActionListener (this);
		p.add (fois);
		fois.addActionListener (this);
		p.add (divise);
		divise.addActionListener (this);
		p.add (reste);
		reste.addActionListener (this);
		p.add (puissance);
		puissance.addActionListener (this);

		add (p = new JPanel());
		p.setBackground (Color.lightGray);
		p.add (pgcd);
		pgcd.addActionListener (this);
		p.add (ppcm);
		ppcm.addActionListener (this);
		p.add (rn1);
		rn1.addActionListener (this);
		p.add (rn2);
		rn2.addActionListener (this);
		p.add (rn3);
		rn3.addActionListener (this);
		p.add (pp);
		pp.addActionListener (this);

		add (p = new JPanel());
		p.setBackground (Color.lightGray);
		p.add (factorisation);
		factorisation.addActionListener (this);
		p.add (factorielle);
		factorielle.addActionListener (this);
		p.add (n2parmin1);
		n2parmin1.addActionListener (this);
		p.add (pmod);
		pmod.addActionListener (this);
		p.add (divmod);
		divmod.addActionListener (this);
		p.add (invmod);
		invmod.addActionListener (this);

		zero = BigInteger.ZERO;
		un = BigInteger.ONE;
		deux = BigInteger.valueOf (2);
		trois = BigInteger.valueOf (3);
		maxint = BigInteger.valueOf ((long)Integer.MAX_VALUE);
		err0 = "erreur : n2 = 0";
}

	public void actionPerformed (ActionEvent evt) {
		boolean nonerreur = true;
		if (evt.getSource() == raz) {
			tn1.setText ("");
			tn2.setText ("");
			tn3.setText ("");
			tanr.setText ("");
		} else if (evt.getSource() == factorisation) {
			try {
				n1 = new BigInteger (tn1.getText());
			}
			catch (NumberFormatException nfe) {}
			tanr.setText ((n1.compareTo (zero) < 0) ? "-" : "");
			n1 = n1.abs();
			if (n1.compareTo (zero) == 0)
				tanr.append ("0");
			else {
				int exp = 0;
				for (int i = 0; (i < n1.bitLength()) && (!n1.testBit (i)); i++)
					exp ++;
				BigInteger n = n1.shiftRight (exp);
				if (exp > 0) {
					tanr.append ("2");
					if (exp > 1)
						tanr.append (" ^ " + Integer.toString (exp));
					if (n.compareTo(un) != 0)
						tanr.append (" x ");
					exp = 0;
				}
				BigInteger diviseur = trois;
				while (diviseur.multiply(diviseur).compareTo (n) <= 0) {
					BigInteger[] qr = n.divideAndRemainder (diviseur); 
					while (qr [1].compareTo (zero) == 0) {
						exp ++;
						n = qr [0];
						qr = n.divideAndRemainder(diviseur);
					}
					if (exp > 0) {
						tanr.append (diviseur.toString ());
						if (exp > 1)
							tanr.append (" ^ " + Integer.toString (exp));
						if (n.compareTo(un) != 0)
							tanr.append ("x");
						exp = 0;
					}
					diviseur = diviseur.add (deux);
				}
				if (n.compareTo (un) != 0)
					tanr.append (n.toString ());
			}
		} else if (evt.getSource() == rn1)
			tn1.setText (tanr.getText ());
		else if (evt.getSource() == rn2)
			tn2.setText (tanr.getText());
		else if (evt.getSource() == rn3)
			tn3.setText (tanr.getText ());
		else if (evt.getSource() == pp) {
			int n = 1;
			try {
				n1 = new BigInteger (tn1.getText());
			}
			catch (NumberFormatException nfe) {}
			try {
				n = Integer.parseInt (tn2.getText());
			}
			catch (NumberFormatException nfe) { }
			tanr.setText (n1 + ((n1.isProbablePrime (n)) ? " probablement": "non") + " premier");
		} else {
			try {
				n1 = new BigInteger (tn1.getText());
			}
			catch (NumberFormatException nfe) {}
			try {
				n2 = new BigInteger (tn2.getText());
			}
			catch (NumberFormatException nfe) {}
			try {
				n3 = new BigInteger (tn3.getText());
			}
			catch (NumberFormatException nfe) {}
			if (evt.getSource() == plus)
				nr = n1.add (n2);
			else if (evt.getSource() == moins)
				nr = n1.subtract (n2);
			else if (evt.getSource() == fois)
				nr = n1.multiply (n2);
			else if (evt.getSource() == divise) {
				try {
					nr = n1.divide (n2);
				}
				catch (ArithmeticException ae) {
					nonerreur = false;
					tanr.setText (err0);
				}
			} else if (evt.getSource() == reste) {
				try {
					nr = n1.remainder (n2);
				}
				catch (ArithmeticException ae) {
					nonerreur = false;
					tanr.setText (err0);
				}
			} else if (evt.getSource() == puissance)
				if (n2.compareTo (maxint) <= 0) {
					try {
						nr = n1.pow (n2.intValue());
					}
					catch (ArithmeticException ae) {
						nonerreur = false;
						tanr.setText ("n2 négatif");
					}
			} else {
				nr = un; nonerreur = false;
				tanr.setText ("attention n2 > " + Long.toString ((long)Integer.MAX_VALUE));
//for (BigInteger i = zero; i.compareTo (n2) < 0; i.add (un)) nr = nr.multiply (n2);
			} else if (evt.getSource() == pgcd)
				nr = n1.gcd (n2);
			else if (evt.getSource() == ppcm) {
				try {
					nr = n1.multiply(n2).divide(n1.gcd(n2));
				}
				catch (ArithmeticException ae) {
					nonerreur = false;
					tanr.setText ("0");
				}
			} else if (evt.getSource() == invmod) {
				try {
					nr = n1.modInverse (n2);
				}
				catch (ArithmeticException ae) {
					nonerreur = false;
					tanr.setText ("Impossible : n1 et n2 non premiers entre eux");
				}
			} else if (evt.getSource() == factorielle) {
				nr = un;
				for (BigInteger i = deux; i.compareTo (n1) <= 0; i = i.add (un))
					nr = nr.multiply (i);
			} else if (evt.getSource() == n2parmin1) {
				if (n2.compareTo (n1) > 0)
					nr = zero;
				else {
					nr = un;
					for (BigInteger i = un, j = n1; i.compareTo (n2) <= 0; i = i.add (un), j = j.subtract (un))
						nr = nr.multiply (j).divide(i);
				}
			} else if (evt.getSource() == pmod) {
				try {
					nr =n1.modPow (n2, n3);
				}
				catch (ArithmeticException ae) {
					nonerreur = false;
					tanr.setText ("erreur : n2 négatif ou nul");
				}
			} else if (evt.getSource() == divmod) {
				try {
					BigInteger[] bi = n1.divideAndRemainder (n2);
					tn3.setText (bi[0].toString());
					nr = bi [1];
				}
				catch (ArithmeticException ae) {
					nonerreur = false;
					tanr.setText (err0);
				}
			}
			if (nonerreur)
				tanr.setText (nr.toString());
		}
	}

	public static void main (String [] args) {
		calcbigint f = new calcbigint ("calcbigint");
		f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		f.setSize (500, 500);
		f.setVisible (true);
	}
}
