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>Fibonacci</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>long</code>.
 * Hence, eventually, calculations will overflow.</p>
 */
public class Fibonacci
    extends DisplayPanel
{
    // The views
    
    private static int smallWidth = 100;
    
    private static int largeWidth = 400;
    
    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 Fibonacci() {
        mainPanel.emptyBorder(gap/2);
        
        add(mainPanel);
    }
    
    
    /** Initialize the start state of Fibonacci. */
    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 Fibonacci
     * 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
        long a = fibonacci0.demandLong();
        long b = fibonacci1.demandLong();
        long c = a + 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 Fibonacci.
     * @param args ignored
     */
    public static void main(String[] args) {
        LookAndFeelTools.setNetFontSizeAdjustment(8);
        new Fibonacci().frame("Fibonacci");
    }
}

