/*----------------------------------------------------------------------+
|   Title:  PoincareB.java                                              |
|                                                                       |
|   Author: David E. Joyce                                              |
|           Department of Mathematics and Computer Science              |
|           Clark University                                            |
|           Worcester, MA 01610-1477                                    |
|           U.S.A.                                                      |                                                                       |
|           http://aleph0.clarku.edu/~djoyce/                           |
|                                                                       |
|   Date:   April, 1987.  Pascal version for tektronix terminal         |
|           Modified June, 1991, to do quasiregular tessellations       |
|               and draw stars as well as polygons                      |
|           December, 2002, converted to Java applet version            |
+----------------------------------------------------------------------*/

import java.awt.*;
import java.applet.Applet;
import java.util.StringTokenizer;
import java.awt.event.*;

public class PoincareApplet
       extends Applet
       implements ActionListener, AdjustmentListener, ItemListener {

  TileParameters par = new TileParameters();
  boolean interactive;
  PoincareDisk disk;
  
  Panel controlPanel = new Panel();
  Button drawButton = new Button("Draw");
  Choice quasiChoice = new Choice();
  Choice altChoice = new Choice();
  Label n_label = new Label("",Label.CENTER);
  Scrollbar n_scrollbar;
  Label k_label = new Label("",Label.CENTER);
  Scrollbar k_scrollbar;
  Label skip_label = new Label("",Label.CENTER);
  Scrollbar skip_scrollbar;
  Label layers_label = new Label("",Label.CENTER);
  Scrollbar layers_scrollbar;

  public void init() {
    getParameters();
    disk = new PoincareDisk(par);
    initializePanels();
    checkPars();
    disk.init();
    disk.repaint();
  } // init

  private void getParameters() {
    String param = getParameter("n");
    par.n = (param == null) ? 5 : Integer.parseInt(param);

    param = getParameter("k");
    par.k = (param == null) ? 4 : Integer.parseInt(param);
    
    param = getParameter("quasiregular");
    par.quasiregular = (param == null) ?
      false :
      (param.equalsIgnoreCase("yes") || param.equalsIgnoreCase("true"));

    param = getParameter("layers");
    par.layers = (param == null) ? 4 : Integer.parseInt(param);

    param = getParameter("skipNumber");
    par.skipNumber = (param == null) ? 1 : Integer.parseInt(param);

    param = getParameter("bgColor");
    if (param != null)
      par.bgColor = parseColor(param);
    if (par.bgColor == null)
      par.bgColor = getBackground();

    param = getParameter("diskColor");
    if (param != null)
      par.diskColor = parseColor(param);
    if (par.diskColor == null)
      par.diskColor = Color.black;

    param = getParameter("fill");
    par.fill = (param == null) ?
      true :
      (param.equalsIgnoreCase("yes") || param.equalsIgnoreCase("true"));

    param = getParameter("outline");
    par.outline = (param == null) ?
      true :
      (param.equalsIgnoreCase("yes") || param.equalsIgnoreCase("true"));

    param = getParameter("grayScale");
    par.grayScale = (param == null) ?
      false :
      (param.equalsIgnoreCase("yes") || param.equalsIgnoreCase("true"));

    param = getParameter("alternating");
    par.alternating = (param == null  || par.k%2 == 1) ?
      false :
      (param.equalsIgnoreCase("yes") || param.equalsIgnoreCase("true"));

    param = getParameter("interactive");
    interactive = (param == null) ?
      true :
      (param.equalsIgnoreCase("yes") || param.equalsIgnoreCase("true"));
  } // getParameters
 
  private void initializePanels() {
    setLayout(new BorderLayout(10,10));
    setFont(new Font("TimesRoman",Font.PLAIN,12));
    controlPanel.setLayout(new GridLayout(11,1,5,5));
    
    drawButton.addActionListener(this);
    controlPanel.add(drawButton);

    quasiChoice.addItem("Regular");
    quasiChoice.addItem("Quasi");
    quasiChoice.addItemListener(this);
    controlPanel.add(quasiChoice);

    controlPanel.add(n_label);
    n_scrollbar = new Scrollbar (Scrollbar.HORIZONTAL,par.n,0,3,21);
    n_scrollbar.addAdjustmentListener(this);
    controlPanel.add(n_scrollbar);

    controlPanel.add(k_label);
    k_scrollbar = new Scrollbar (Scrollbar.HORIZONTAL,par.k,0,3,21);
    k_scrollbar.addAdjustmentListener(this);
    controlPanel.add(k_scrollbar);

    controlPanel.add(skip_label);
    skip_scrollbar = new Scrollbar (Scrollbar.HORIZONTAL,par.skipNumber,0,1,21);
    skip_scrollbar.addAdjustmentListener(this);
    controlPanel.add(skip_scrollbar);

    controlPanel.add(layers_label);
    layers_scrollbar = new Scrollbar (Scrollbar.HORIZONTAL,par.layers+1,0,0,6);
    layers_scrollbar.addAdjustmentListener(this);
    controlPanel.add(layers_scrollbar);

    altChoice.addItem("Random");
    altChoice.addItem("Alternating");
    altChoice.addItemListener(this);
    controlPanel.add(altChoice);

    if (interactive)
      add("West",controlPanel);
    
    Panel centerPanel = new Panel();
    centerPanel.setLayout(new GridLayout(1,1,10,10));
    centerPanel.add(disk);
    add(centerPanel);
  } // initializePanels
 
  private void checkPars() {
    par.checkPars();
    n_label.setText("n = "+par.n);
    n_scrollbar.setValue(par.n);
    k_label.setText("k = "+par.k); 
    k_scrollbar.setValue(par.k);
    skip_label.setText("skip="+par.skipNumber);
    skip_scrollbar.setValue(par.skipNumber);
    skip_scrollbar.setMaximum((par.n+1)/2);
    layers_label.setText("layers="+par.layers);
    layers_scrollbar.setValue(par.layers);
    if (par.quasiregular) 
      quasiChoice.select("Quasi");
    else 
      quasiChoice.select("Regular");
    if (par.alternating) 
      altChoice.select("Alternating");
    else 
      altChoice.select("Random");
    altChoice.setEnabled(par.k%2==0);
  }

  static String colorName[] = {
	"black", "blue", "cyan", "darkGray", "gray", "green","lightGray",
	"magenta", "orange", "pink", "red", "white", "yellow"};
  static Color constColor[] = {
	Color.black, Color.blue, Color.cyan, Color.darkGray, Color.gray,
	Color.green, Color.lightGray, Color.magenta, Color.orange,
	Color.pink, Color.red, Color.white, Color.yellow};

  Color parseColor (String str) {
    if (str==null || "none".equals(str) || "0".equals(str)) return null;
    for (int i=0; i<colorName.length; ++i)
      if (colorName[i].equals(str)) return constColor[i];
    try { return new Color(Integer.parseInt(str,16));}
    catch (NumberFormatException exc) {}
    StringTokenizer t = new StringTokenizer(str,",");
    if (!t.hasMoreTokens()) return null;
    try {
      float hue = (float)(Integer.parseInt(t.nextToken())/360.0);
      if (!t.hasMoreTokens()) return null;
      float sat = (float)(Integer.parseInt(t.nextToken())/100.0);
      if (!t.hasMoreTokens()) return null;
      float bri = (float)(Integer.parseInt(t.nextToken())/100.0);
      return new Color(Color.HSBtoRGB(hue,sat,bri));
    } catch (NumberFormatException exc) {
      return null;
    }
  } //parseColor

  public void actionPerformed(ActionEvent evt) {
    String command = evt.getActionCommand();
    if (command.equals("Draw")) {
      checkPars();  
      disk.init();
      disk.repaint();
    } 
  } // actionPerformed
  
  public void itemStateChanged(ItemEvent evt) {
    par.quasiregular = (quasiChoice.getSelectedIndex()==1);
    par.alternating = (altChoice.getSelectedIndex()==1);
    checkPars();
  } // itemStateChanged

  public void adjustmentValueChanged(AdjustmentEvent e) {
    if (e.getSource() == n_scrollbar) {
      par.n = e.getValue();
    } else if (e.getSource() == k_scrollbar) {
      par.k = e.getValue();
      if (par.k==3)      par.n = Math.max(par.n,7);
      else if (par.k==4) par.n = Math.max(par.n,5);
      else if (par.k<7)  par.n = Math.max(par.n,4);
      else               par.n = Math.max(par.n,3);
    } else if (e.getSource() == skip_scrollbar ) {
      par.skipNumber = e.getValue(); 
    } else if (e.getSource() == layers_scrollbar) {
      par.layers = e.getValue();
    }
    checkPars();
  } // adjustmentValueChanged

} // PoincareAp
