import edu.neu.ccs.*;
import edu.neu.ccs.gui.*;
import edu.neu.ccs.codec.*;
import edu.neu.ccs.console.*;
import edu.neu.ccs.filter.*;
import edu.neu.ccs.jpf.*;
import edu.neu.ccs.parser.*;
import edu.neu.ccs.pedagogy.*;
import edu.neu.ccs.quick.*;
import edu.neu.ccs.util.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.font.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
import java.util.*;
import java.math.*;
import java.beans.*;
import java.lang.reflect.*;
import java.net.URL;
import java.util.regex.*;
import java.text.ParseException;

/**
 * <p>Class <code>FibonacciBI</code> shows the iterative
 * computation of Fibonacci numbers using a GUI
 * interface that both presents and maintains the data.</p>
 * 
 * <p>Calculations are done using type
 * <code>BigInteger</code>.</p>
 */
public class FibonacciBI
    extends DisplayPanel
{
    // The views
    
    private static int smallWidth = 100;
    
    private static int largeWidth = 800;
    
    private TextFieldView index0 =
        new TextFieldView("0", smallWidth);
    
    private TextFieldView index1 =
        new TextFieldView("1", smallWidth);
    
    private TextFieldView index2 =
        new TextFieldView("2", smallWidth);
    
    private TextFieldView fibonacci0 =
        new TextFieldView("1", largeWidth);
    
    private TextFieldView fibonacci1 =
        new TextFieldView("1", largeWidth);
    
    private TextFieldView fibonacci2 =
        new TextFieldView("2", largeWidth);
    
    
    private int gap = 8;
    
    // Put views into a table
    
    private Object[][] viewStuff =
        { { index0, fibonacci0},
          { index1, fibonacci1},
          { index2, fibonacci2} };
    
    private TablePanel viewPanel =
        new TablePanel(viewStuff, gap, gap, CENTER);
    
    // Create actions for the buttons
    
    private SimpleAction start =
        new SimpleAction("Start Fibonacci") {
            public void perform() { start(); }
    };
    
    private SimpleAction next =
        new SimpleAction("Next Fibonacci") {
            public void perform() { next(); }
    };
    
    private SimpleAction repeat =
        new SimpleAction("Repeat Next ...") {
            public void perform() { repeat(); }
    };
    
    // Put actions into a table as buttons
    
    private Object[] actionStuff = { start, next, repeat };
    
    private HTable actionPanel =
        new HTable(actionStuff, gap, gap, CENTER);
    
    // Combine views and buttons
    
    private Object[] mainStuff = { viewPanel, actionPanel };
    
    private VTable mainPanel =
        new VTable(mainStuff, gap, gap, CENTER);
    
    
    // Constructor
    
    public FibonacciBI() {
        mainPanel.emptyBorder(gap/2);
        
        add(mainPanel);
    }
    
    
    /** Initialize the start state of FibonacciBI. */
    private void start() {
        index0.setViewState("0");
        index1.setViewState("1");
        index2.setViewState("2");
        fibonacci0.setViewState("1");
        fibonacci1.setViewState("1");
        fibonacci2.setViewState("2");
    }
    
    
    /**
     * Use the current state of FibonacciBI
     * to set the next state.
     */
    private void next() {
        // move rows up
        index0.setViewState(index1.getViewState());
        index1.setViewState(index2.getViewState());
        
        fibonacci0.setViewState(fibonacci1.getViewState());
        fibonacci1.setViewState(fibonacci2.getViewState());
        
        // set index in last row
        long n = index1.demandLong();
        
        index2.setViewState("" + (n + 1));
        
        // set fibonacci in last row
        BigInteger a = fibonacci0.demandBigInteger();
        BigInteger b = fibonacci1.demandBigInteger();
        BigInteger c = a.add(b);
        
        fibonacci2.setViewState("" + c);
    }
    
    
    /**
     * Repeat the next computation until the index in the
     * last row is greater than or equals to the index in
     * the dialog presented to the user.
     */
    private void repeat() {
        String prompt = "Repeat Next Fibonacci up to what index?";
        String title  = "Repeat Query";
        
        long limit = SimpleDialog.demandLong(prompt, title);
        
        long n = index2.demandLong();
        
        while (n < limit) {
            next();
            n = index2.demandLong();
        }
    }
    
    
    /**
     * The main program to launch FibonacciBI.
     * @param args ignored
     */
    public static void main(String[] args) {
        LookAndFeelTools.setNetFontSizeAdjustment(8);
        new FibonacciBI().frame("Fibonacci with BigInteger");
    }
}

