/*
   Source code by David Eck
                  Department of Mathematics and Computer Science
                  Hobart and William Smith Colleges
                  Geneva, NY 14456
                  eck@hws.edu
                  
   This Java source code file can be used IN UNMODIFIED FORM for
   any purpose.  You can also make and distribute modified versions,
   as long as you include an acknowledgement of the original
   author in the modified version.
*/

package xca;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class NewWorldDialog extends JDialog implements ActionListener {

   private final static int MAX_RULE_COUNT = 1048576; // 2^20
   
   private boolean canceled;
   
   private Frame parent;
   
   private JButton defaultsButton, cancelButton, okButton;
   private JComboBox neighborhoodSizeSelect, numberOfStatesSelect,
                 isotropicSelect, wrappedSelect, worldSizeSelect,
                 imageHeightSelect;

   private int neighborhoodSize;
   private int numberOfStates;
   private int worldSize;
   private boolean isIsotropic;
   private boolean isWrapped;
   private int imageHeight;
   
   private int worldPaneWidth, worldPaneHeight;

   public NewWorldDialog(Frame parent) {
      super(parent,"Settings for New World",true);
      
      this.parent = parent;
      
      getContentPane().setLayout(new BorderLayout(7,7));
      ((JComponent)getContentPane()).setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
      
      JPanel top = new JPanel();
      getContentPane().add(top,BorderLayout.CENTER);
      top.setLayout(new GridLayout(6,2,5,5));
      JPanel bottom = new JPanel();
      getContentPane().add(bottom,BorderLayout.SOUTH);

      defaultsButton = new JButton("Defaults");
      defaultsButton.addActionListener(this);
      cancelButton = new JButton("Cancel");
      cancelButton.addActionListener(this);
      okButton = new JButton("Create World");
      okButton.addActionListener(this);
      bottom.add(defaultsButton);
      bottom.add(cancelButton);
      bottom.add(okButton);
      
      numberOfStatesSelect = new JComboBox( new String[] {
            "2","3","4","5","6","7","8","9","10","11",
            "12","13","14","15","16","17","18","19","20","21",
            "22","23","24","25","26","27","28","29","30","31", "32"
         });
      numberOfStatesSelect.addActionListener(this);
      neighborhoodSizeSelect = new JComboBox( new String[] {
            "3","5","7","9","11","13","15"
         });
      isotropicSelect = new JComboBox( new String[] { "Yes", "No" } );
      wrappedSelect = new JComboBox( new String[] { "Yes", "No" } );
      worldSizeSelect = new JComboBox( new String[] {
            "400", "512", "640", "800", "1024", "1280", "Fit to Window"
         });
      worldSizeSelect.setEditable(true);
      imageHeightSelect = new JComboBox( new String[] {
            "3/4 * WorldSize", "512", "1024", "Fit to Window"
         });
      imageHeightSelect.setEditable(true);
      setDefaults();
      
      top.add(new JLabel("Number of States"));
      top.add(numberOfStatesSelect);
      top.add(new JLabel("Neighborhood Size"));
      top.add(neighborhoodSizeSelect);
      top.add(new JLabel("Rules are Isotropic"));
      top.add(isotropicSelect);
      top.add(new JLabel("World is Circular"));
      top.add(wrappedSelect);
      top.add(new JLabel("Size of World"));
      top.add(worldSizeSelect);
      top.add(new JLabel("Height of Image"));
      top.add(imageHeightSelect);
      
      pack();
      
   }
   
   public World getWorld() {
      if (canceled)
         return null;
      return new World(neighborhoodSize, numberOfStates, worldSize,
                 isIsotropic, isWrapped);
   }
   
   public int getImageHeight() {
      return imageHeight;
   }
   
   public void show(int worldPaneWidth, int worldPaneHeight) {
      canceled = true;
      this.worldPaneWidth = worldPaneWidth;
      this.worldPaneHeight = worldPaneHeight;
      if (parent != null)
         setLocation(parent.getLocation().x + 80, parent.getLocation().y + 40);
      super.show();
   }
   
   public void actionPerformed(ActionEvent evt) {
      Object src = evt.getSource();
      if (src == cancelButton)
         hide();
      else if (src == defaultsButton) {
         setDefaults();
      }
      else if (src == okButton) {
         try {
            getData();
            canceled = false;
            hide();
         }
         catch (Exception e) {
            JOptionPane.showMessageDialog(this,"Your configuaration data has an error:\n"
                      + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
         }
      }
      else if (src == numberOfStatesSelect) {
         checkLegalNeighborhoodSizes();
      }
   }
   
   private void setDefaults() {
      numberOfStatesSelect.setSelectedIndex(2);
      neighborhoodSizeSelect.setSelectedIndex(1);
      isotropicSelect.setSelectedIndex(0);
      wrappedSelect.setSelectedIndex(0);
      worldSizeSelect.setSelectedIndex(6);
      imageHeightSelect.setSelectedIndex(3);
      checkLegalNeighborhoodSizes();
   }
   
   private void checkLegalNeighborhoodSizes() {
      int states = numberOfStatesSelect.getSelectedIndex() + 2;
      int itemCt = neighborhoodSizeSelect.getItemCount();
      int selected = neighborhoodSizeSelect.getSelectedIndex();
      int desiredItems = 1;
      int ct = 5;
      while (Math.pow(states, ct) < MAX_RULE_COUNT) {
         desiredItems++;
         ct += 2;
      }
      if (desiredItems != itemCt) {
         neighborhoodSizeSelect.removeAllItems();
         ct = 3;
         for (int i = 0; i < desiredItems; i++) {
            neighborhoodSizeSelect.addItem("" + ct);
            ct += 2;
         }
         if (selected < desiredItems)
            neighborhoodSizeSelect.setSelectedIndex(selected);
         else
            neighborhoodSizeSelect.setSelectedIndex(desiredItems-1);
       }
   }
   
   private void getData() {
      switch (worldSizeSelect.getSelectedIndex()) {
          case 0: worldSize =  400; break;  
          case 1: worldSize =  512; break;
          case 2: worldSize =  640; break;
          case 3: worldSize =  800; break;
          case 4: worldSize = 1024; break;
          case 5: worldSize = 1280; break;
          case 6: worldSize = worldPaneWidth; break;
          default:
             try {
                String s = ((String)worldSizeSelect.getSelectedItem()).trim();
                worldSize = Integer.parseInt(s);
                if (worldSize < 200 || worldSize > 5000)
                   throw new Exception();
             }
             catch (Exception e) {
                 throw new IllegalArgumentException("World size must be an integer between 200 and 10000.");
             }
      }
      switch (imageHeightSelect.getSelectedIndex()) {
          case 0: imageHeight =  (worldSize*3)/4; break;  
          case 1: imageHeight =  512; break;
          case 2: imageHeight =  1024; break;
          case 3: imageHeight = worldPaneHeight; break;
          default:
             try {
                String s = ((String)imageHeightSelect.getSelectedItem()).trim();
                imageHeight = Integer.parseInt(s);
                if (imageHeight < 200 || imageHeight > 5000)
                   throw new Exception();
             }
             catch (Exception e) {
                 throw new IllegalArgumentException("Image height must be an integer between 200 and 10000.");
             }
      }
      numberOfStates = numberOfStatesSelect.getSelectedIndex() + 2;
      neighborhoodSize = 2*neighborhoodSizeSelect.getSelectedIndex() + 3;
      isIsotropic = (isotropicSelect.getSelectedIndex() == 0);
      isWrapped = (wrappedSelect.getSelectedIndex() == 0);
   }

}

