/**
 * erdosp.java - 03/01/10 - 8/01/10 - 13/01/10
 * 
 * auteur : Jean-Paul QUELEN
 * 
 * Remplace le "carré" dans le théorème de Erdös par une puissance p > 1 quelconque
 * On peut interrompre le calcul
 * ajout de main() le 07/01/18
 * modification le 27/08/22
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.math.BigInteger;

public class erdosp extends JPanel implements Runnable, ActionListener {
	static final long serialVersionUID = 220828L;
	JTextField tn, tp;
	TextArea ta;
	JButton ok, stop, efface;
	Thread t;
	int p;
	BigInteger n;

	public erdosp() {
		setFont (new Font ("Arial, Helvetica, sans-serif", Font.PLAIN, 12));
		setBackground (Color.lightGray);
		setLayout (new BorderLayout ());
		JPanel p = new JPanel ();
		add (p, BorderLayout.NORTH);

// installe N = 1 et le bouton Ok dans le panneau "nord"
		p.add (new Label ("N ="));
		p.add (tn = new JTextField ("1", 10));
		p.add (new Label ("p ="));
		p.add (tp = new JTextField ("2", 2));
		p.add (ok = new JButton ("Ok"));
		ok.addActionListener (this);
		p.add (stop = new JButton ("Stop"));
		stop.addActionListener (this);
		p.add (efface = new JButton ("Efface"));
		efface.addActionListener (this);

// installe le champ de texte "ta" qui recevra les éléments de la suite dans le panneau central
		p = new JPanel ();
		add (p);
		p.add (ta = new TextArea ("", 20, 50, TextArea.SCROLLBARS_VERTICAL_ONLY), BorderLayout.CENTER);
	}

// Le Thread tourne mais le calcul ne se fait que si le bouton "ok" est pressé (bcalcul = true)
// Le calcul s'arrête si le bouton "stop" est pressé (bcalcul = false)

	public void run() {
		Thread t1 = Thread.currentThread();
		try {
			p = Integer.parseInt (tp.getText ());	// on récupère les paramètres et on relance le calcul
			n = new BigInteger (tn.getText());
			if ((n.compareTo (BigInteger.ZERO) < 0) || (p <= 1))
				ta.append ("\nN doit être un entier positif et p un entier supérieur à 2");
			else {
				ta.append ("\n");
				BigInteger pm = BigInteger.ONE;
				BigInteger pm2 = new BigInteger ("2");
				int lpm = 1;					// lpm contient le nombre de chiffres de la représentation binaire de pm
				while (t1 == t) {
					BigInteger m = BigInteger.ZERO;

// calcul de +/- 1^2 +/- 2^2 +/- 3^2...+/-lpm^2 que l'on met dans m
					BigInteger bi = BigInteger.ZERO;
					for (int i = 0; i < lpm; i ++) {
						bi = bi.add (BigInteger.ONE);
						BigInteger mk = bi.pow (p);
						m = (pm.testBit (i))? m.add (mk) : m.subtract(mk);
					}
					if (m.compareTo (n) == 0) {
						break;							// on a trouvé => on peut sortir de la boucle
					} else {
						pm = pm.add (BigInteger.ONE);	// on ajoute 1 à pm car on essaie toutes les combinaisons +/-
						if (pm.compareTo (pm2) == 0) {	// on a epuisé toutes les possibilités donc
							pm2 = pm2.add (pm2);		// on ajoute un terme dans la somme
							lpm++; 
							ta.append (".");
						}
					}
				}	// fin while
				if (t == null) {
					ta.append ("\nprocessus arrêté\n");
				} else {
					ta.append ("\n\n" + n.toString () + " = ");
					BigInteger bi = BigInteger.ZERO;
					for (int i = 0; i < lpm; i++) {
						if (pm.testBit (i))
							ta.append (" + ");
						else
							ta.append (" - ");
						bi = bi.add (BigInteger.ONE);
						BigInteger mk = bi.pow (p);
						ta.append (mk.toString() + " ");
					}
					ta.append ("\n\n" + n.toString () + " = ");
					for (int i = 0; i < lpm; i++) {
						if (pm.testBit (i))
							ta.append (" + ");
						else
							ta.append (" - ");
						ta.append ((i + 1) + "^" + p);
					}
//					tn.setText(n.add (BigInteger.ONE).toString());// n suivant
				}
			}
		}
		catch (NumberFormatException nfe) {
			ta.append ("\nN doit être un entier positif et p un entier supérieur à 2");
		}
	}

	public void actionPerformed (ActionEvent evt) {
		if (evt.getSource() == ok) 	{
			if (t != null) {
				t = null;
				try {
					Thread.sleep (1000);					// on attend une seconde
				}
				catch (InterruptedException ie) {}
			}
			t = new Thread (this);
			t.start();
		} else if (evt.getSource() == stop) {
			t = null;
		} else if (evt.getSource() == efface)
			ta.setText("");
	}


	public static void main (String args []) {
		int w = 500;
		int h = 400;

		erdosp e = new erdosp();
		JFrame f = new JFrame ("Erdös-Suranyi-Bodini");
		f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		f.add (e);
		f.setSize (w, h);
		f.setVisible (true);
	}

}
