/*----------------------------------------------------------------------+
|      Title:	BattleApplet.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/                           |
|           djoyce@clarku.edu                                           |
|                                                                       |
|      Date:    May, 2002.                                              |
+----------------------------------------------------------------------*/

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class BattleApplet extends Applet
  implements ActionListener, AdjustmentListener, KeyListener, Runnable {
  // parameters and their initial
  int players, iPlayers = 80; // number of players, must be even
  int gamesPerMatch, igamesPerMatch = 20;
  int matchesPerSim, imatchesPerSim = 20;
  int ipayoff[][] = {{3,0},{5,1}};
  int payoff[][] = new int[2][2];

  // variables
  Strategy S[];
  Battle battle;

  // thread control
  Thread thread = null;
  boolean doStop = false;

  // components
  Panel controlPanel;
  TextArea  reportArea;
  Button startButton, resetButton;
  Label players_label = new Label();
  Scrollbar players_scrollbar;
  Label gamesPerMatch_label = new Label();
  Scrollbar gamesPerMatch_scrollbar;
  Label matchesPerSim_label = new Label();
  Scrollbar matchesPerSim_scrollbar;
  Panel payoffMatrixPanel;
  TextField payoffField[][] = new TextField[2][2];
  final static int statWidth=400, statHeight=150;
  TimeGraph statGraph;
  Color statColors[] = {Color.green,Color.black,Color.white,Color.blue,
                    Color.yellow,Color.red,Color.orange,Color.cyan};

  // Initialize the applet
  public void init() {
    // construct and place the components in the applet window
    BorderLayout appletLayout = new BorderLayout();
    appletLayout.setHgap(5);
    appletLayout.setVgap(5);
    setLayout(appletLayout);
    setFont(new Font("Serif",Font.PLAIN,10));

    // set up the report area
    reportArea = new TextArea(5,20);
    reportArea.setEditable(false);
    //reportArea.setFont(new Font("Serif",Font.PLAIN,10));
    add(reportArea);

    // Set up the control panel
    controlPanel = new Panel();
    BorderLayout controlLayout = new BorderLayout();
    controlLayout.setHgap(20);
    controlPanel.setLayout(controlLayout);
    add("North",controlPanel);

    // The buttonPanel will make up part of the control panel
    Panel buttonPanel = new Panel();
    buttonPanel.setLayout(new GridLayout(2,1));
    controlPanel.add("West",buttonPanel);

    startButton = new Button("Start");
    startButton.addActionListener(this);
    buttonPanel.add(startButton);

    resetButton = new Button("Reset");
    resetButton.addActionListener(this);
    buttonPanel.add(resetButton);

    // Each parameter has a label and a scrollbar
    Panel parameterPanel = new Panel();
    parameterPanel.setLayout(new GridLayout(3,2));
    controlPanel.add(parameterPanel);

    players = iPlayers;
    parameterPanel.add(players_label);
    players_label.setText("players: "+players);
    players_scrollbar = new Scrollbar (Scrollbar.HORIZONTAL,players,20,2,519);
    players_scrollbar.addAdjustmentListener(this);
    parameterPanel.add(players_scrollbar);

    gamesPerMatch = igamesPerMatch;
    parameterPanel.add(gamesPerMatch_label);
    gamesPerMatch_label.setText("games/match: "+gamesPerMatch);
    gamesPerMatch_scrollbar = new Scrollbar (Scrollbar.HORIZONTAL,gamesPerMatch,10,1,210);
    gamesPerMatch_scrollbar.addAdjustmentListener(this);
    parameterPanel.add(gamesPerMatch_scrollbar);

    matchesPerSim = imatchesPerSim;
    parameterPanel.add(matchesPerSim_label);
    matchesPerSim_label.setText("matches/sim: "+matchesPerSim+"   ");
    matchesPerSim_scrollbar = new Scrollbar (Scrollbar.HORIZONTAL,matchesPerSim,10,1,210);
    matchesPerSim_scrollbar.addAdjustmentListener(this);
    parameterPanel.add(matchesPerSim_scrollbar);

    // set up the payoff matrix and its panel
    payoffMatrixPanel = new Panel();
    payoffMatrixPanel.setLayout(new GridLayout(2,2));
    for (int i=0; i<=1; ++i)
      for (int j=0; j<=1; ++j) {
        payoff[i][j] = ipayoff[i][j];
        payoffField[i][j] = new TextField(3);
        payoffField[i][j].setText(Integer.toString(payoff[i][j]));
        payoffField[i][j].addKeyListener(this);
        payoffMatrixPanel.add(payoffField[i][j]);
    }
    controlPanel.add("East",payoffMatrixPanel);

    // set up the statistics timegraph
    statGraph = new TimeGraph();
    statGraph.setSize(statWidth,statHeight);
    add("South",statGraph);

    // set up the Strategy array S
    S = new Strategy[8];
    S[0] = new Strategy(0,"Nice"); //Nice Strategy
    S[1] = new Nasty(1,"Nasty");
    S[2] = new TitForTat(2,"Tit4Tat");
    S[3] = new Moth(3,"Moth");
    S[4] = new HitAndRun(4,"Hit&Run");
    S[5] = new Santa(5,"Santa");
    S[6] = new NastyMoth(6,"NasMoth");
    S[7] = new NNHitRun(7,"NNHRun");

    battle = new Battle (S);
  }//init

  public void run() {
    int total[] = new int[S.length];
    reportArea.append("\n");
    for (int s=0; s<S.length; ++s) {
      total[s] = 0;
      reportArea.append(S[s].name+"\t");
    }
    reportArea.append("\n");
    int simulationNumber = 0;
    do {
      simulationNumber++;
      statGraph.init(Color.gray, statColors, matchesPerSim);
      battle.doSimulation(players,matchesPerSim,gamesPerMatch,payoff,statGraph);
      statGraph.repaint();
       // Report final populations
      for (int s=0; s<S.length; ++s) {
        reportArea.append(S[s].pop+"\t");
        total[s] += S[s].pop;
      }
      reportArea.append("\n");
      repaint();
      try {thread.sleep(1000);} // wait this many milliseconds
      catch (Exception e) {};
    } while (!doStop);
    thread = null;
    doStop = false;
    reportArea.append("\nTotals for "+simulationNumber+" simulations.\n");
    // Report totals
    for (int s=0; s<S.length; ++s)
      reportArea.append(S[s].name+"\t");
    reportArea.append("\n");
    for (int s=0; s<S.length; ++s)
      reportArea.append(total[s]+"\t");
    reportArea.append("\n___________________________________________________________________________");
  }//run

  public void actionPerformed(ActionEvent e) {
    if (e.getActionCommand().equals("Start")) {
      startButton.setLabel("Stop");
      if (thread == null) {
        thread = new Thread(this);
        thread.start();
      }
    } else if (e.getActionCommand().equals("Stop")) {
      doStop = true;
      startButton.setLabel("Start");
    } else if (e.getActionCommand().equals("Reset")) {
      players = iPlayers;
      gamesPerMatch = igamesPerMatch;
      matchesPerSim = imatchesPerSim;
      for (int i=0; i<=1; ++i)
        for (int j=0; j<=1; ++j)
          payoff[i][j] = ipayoff[i][j];
      resetControlPanel();
    }
  } // actionPerformed

  public void adjustmentValueChanged(AdjustmentEvent e) {
    if (e.getSource() == players_scrollbar) {
      players = e.getValue();
      players += (players%2); // make sure it's even
      resetControlPanel();
    } else if (e.getSource() == gamesPerMatch_scrollbar) {
      gamesPerMatch = e.getValue();
      resetControlPanel();
    } else if (e.getSource() == matchesPerSim_scrollbar) {
      matchesPerSim = e.getValue();
      resetControlPanel();
    }
  } // adjustmentValueChanged

  void resetControlPanel () {
    players_label.setText("players: "+players);
    players_scrollbar.setValue(players);
    gamesPerMatch_label.setText("games/match: "+gamesPerMatch);
    gamesPerMatch_scrollbar.setValue(gamesPerMatch);
    matchesPerSim_label.setText("matches/sim: "+matchesPerSim);
    matchesPerSim_scrollbar.setValue(matchesPerSim);
    for (int i=0; i<=1; ++i)
      for (int j=0; j<=1; ++j) {
        payoffField[i][j].setText(Integer.toString(payoff[i][j]));
    }
    repaint();
  } //resetScrollBars

  public void keyPressed(KeyEvent e) {}

  public void keyReleased(KeyEvent e) {
    for (int i=0; i<=1; ++i)
      for (int j=0; j<=1; ++j)
        if (e.getSource() == payoffField[i][j]) {
          String text = payoffField[i][j].getText();
          int newvalue;
          try { payoff[i][j] = Integer.parseInt(text);}
          catch (NumberFormatException exc) {
            payoffField[i][j].setText(Integer.toString(payoff[i][j]));
          }
          break;
        }
  }

  public void keyTyped(KeyEvent e) {}

} // applet

