import java.util.*;
import javax.swing.*;

/**
 * Compute pi using the van Wijngaarden transformation
 * of the Gregory-Leibniz series
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class PiCalculator extends SwingWorker<Double,Double>
{
// SwingWorker<T,V> where:
//     T is the result type returned by doInBackground() and get()
//     V is the type used for intermediate results by publish() and process()
//
    private int         digits;    
    
    /**
     * Explicit Value Constructor
     *
     * @param digits   The number of digits of accuracy
     */
    public PiCalculator(int digits)
    {
       this.digits   = digits;
    }

    /**
     * Calculate the i,j term in the transformation
     */
    private double pi(int i, int j)
    {
       if (isCancelled()) return 4.0;
       
       
       double     den, num, result;
       
       if (j == 0) return 0.0;

       // We could call setProgress() and pass an int in [0,100]
       // to cause PropertyChangeEvent objects to be fired
       // to listeners (in the Event Dispatch Thread).
       //
       // We could also call publish() to cause this object's
       // process() method to be called in the Event DispatchThread.
       

       if (i == 0)
       {
          // pi(0,1): 4/1   pi(0,2): 4/1 - 4/3   pi(0,3): 4/1-4/3+4/5  ...
          result = 0.0;          
          for (int k=1; k<=j; k++)
          {
             num = Math.pow(-1.0, k+1) * 4.0;
             den = (k * 2.0) - 1;
             result +=  num / den;
          }
       }
       else
       {
          result = (pi(i-1,j) + pi(i-1,j+1))/2.0;
       }
       
       return result;
    }
    
    /**
     * The code to execute in the background thread
     */
    public Double doInBackground()
    {
       double result;

       result = pi(digits+1, digits+1);

       // This will cause the result to be retrievable
       // using the get() method
       return Double.valueOf(result);
    }
}
