import java.applet.Applet;

import java.awt.Panel;
import java.awt.Button;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Event;
import java.awt.Color;
import java.awt.Insets;
import java.lang.Integer;

import logo.ui.TurtleGraphicsPanel;
import logo.ui.ToggleButton;
import logo.ui.CommandBox;
import logo.ui.ColorChooser;
import logo.lang.Interpreter;
import logo.lang.LogoSub;

/**
   TurtleControlPanel allows the user to execute simple
   rLogo commands by pushing buttons, and provides a Command Box
   for serious programming, debugging, and learning.
*/

//this class was originally named "TurtleControlPanel," so some
//variable names might still reflect this.
public class rLogo extends Applet {

   String action; //holds a pending action, based on the user pushing a button
   boolean actionRequiresParameter;

   String mode; //tracks the action that occurred before the pending action
   Integer value = new Integer(0); //
   Integer increment=new Integer(10); //used to increment commands that require numeric parameters

   private int currentLayout=0;
   private final static int NORMAL_LAYOUT=1;
   private final static int SMALL_LAYOUT=2;

   LocalInterpreter i = null;
   TurtleGraphicsPanel tg = null;

   Panel movement = new Panel();
   Panel environment = new Panel();
   Panel controls = new Panel();
   Button leftButton = new Button("Left");;
   Button rightButton = new Button("Right");
   Button forwardButton = new Button("Forward");
   Button backwardButton = new Button("Back");
   public ToggleButton homeButton = new ToggleButton("Home","Clear",false);

   public ToggleButton penButton = new ToggleButton("Pen Now Down","Pen Now Up",false);
   public ToggleButton turtleButton = new ToggleButton("Turtle is Showing","Turtle is Hidden",false);
   Button breakButton = new Button("Break!");
   Button colorButton = new Button("Change Color");

   public CommandBox commandBox;

   public ColorChooser c = new ColorChooser();

   public void init() {
      resize(600,600);
      commandBox.outString("> Welcome to rLogo!");
      commandBox.outString("> For help, type:");
      commandBox.outString("help");
   }

   public rLogo() {
      tg=new TurtleGraphicsPanel();
      i=new LocalInterpreter(tg,this);
      commandBox = new CommandBox(i);
      i.start();
   }

   public final void start() {
      i.resume();
   }

   public final void stop() {
      i.suspend();
   }

   //The layout goals are to maximize the height of the
   //CommandBox, and to maximize the area of the
   //TurtleGraphicsPanel. The ControlPanel has a pretty much
   //fixed size. For smaller heights, it is necessary
   //to allow the Control Panel to span the area adjacent to
   //both the CommandBox & TurtleGraphicsPanel. For larger
   //heights, it is better to simply place it to the right
   //of the CommandBox, and let the TurtleGraphicsPanel
   //consume more area:

   private void doLayout(int style) {
      removeAll();
      environment.setLayout(new GridLayout(3,1));
      environment.add(penButton);
      environment.add(turtleButton);
      environment.add(breakButton);
      environment.add(colorButton);

      setupMovement();

      GridBagLayout gridBag = new GridBagLayout();
      GridBagConstraints gbc = new GridBagConstraints();
      controls.setLayout(gridBag);

      gbc.gridwidth=GridBagConstraints.REMAINDER;

      gbc.gridx=0;
      gbc.gridy=0;
      gridBag.setConstraints(movement,gbc);

      gbc.gridx=0;
      gbc.gridy=1;
      gridBag.setConstraints(environment,gbc);

      gbc.fill=GridBagConstraints.HORIZONTAL;
      gbc.weightx=3.0;

      gbc.gridx=0;
      gbc.gridy=2;
      gridBag.setConstraints(c,gbc);

      controls.add(movement);
      controls.add(environment);
      controls.add(c);

      if (style==SMALL_LAYOUT) {
        Panel centerPanel=new Panel();

        centerPanel.setLayout(new GridLayout(2,1));
        centerPanel.add(tg);
        centerPanel.add(commandBox);

        setLayout(new BorderLayout());
        add("East",controls);
        add("Center",centerPanel);
      } else {
        Panel bottomPanel=new Panel();

        bottomPanel.setLayout(new BorderLayout());
        bottomPanel.add("Center",commandBox);
        bottomPanel.add("East",controls);

        setLayout(new GridLayout(2,1));
        add(tg);
        add(bottomPanel);
      }

   }

    //If the user dynamically resizes the window (e.g. in the
    //AppletViewer), this code will adjust the layout
    //appropriately:

    public void reshape(int x, int y, int width, int height) {
      super.reshape(x,y,width,height);

      if (height<400) {
        if (currentLayout!=SMALL_LAYOUT) {
          doLayout(SMALL_LAYOUT);
          currentLayout=SMALL_LAYOUT;
        }
      } else {
        if (currentLayout!=NORMAL_LAYOUT) {
          doLayout(NORMAL_LAYOUT);
          currentLayout=NORMAL_LAYOUT;
        }
      }
    }

   //set up the movement & state buttons:

   void setupMovement() {
      GridBagLayout gridBag = new GridBagLayout();
      movement.setLayout(gridBag);
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.insets = new Insets(5,5,5,5);
      gbc.gridx=1;
      gbc.gridy=0;
      gridBag.setConstraints(forwardButton,gbc);
      movement.add(forwardButton);

      gbc.gridx=0;
      gbc.gridy=1;
      gridBag.setConstraints(leftButton,gbc);
      movement.add(leftButton);

      gbc.gridx=1;
      gbc.gridy=1;
      gridBag.setConstraints(homeButton,gbc);
      movement.add(homeButton);

      gbc.gridx=2;
      gbc.gridy=1;
      gridBag.setConstraints(rightButton,gbc);
      movement.add(rightButton);

      gbc.gridx=1;
      gbc.gridy=2;
      gridBag.setConstraints(backwardButton,gbc);
      movement.add(backwardButton);
   }

   //The next three methods are used to track the
   //current action as opposed to the previous action;
   //this helps "cumulative" commands to be built
   //(e.g. forward 10..forward 20..forward 30):

   private void setAction(String a) {
      action=a;
      actionRequiresParameter=false;
   }

   private void setAction(String a, boolean p) {
      action=a;
      actionRequiresParameter=p;
   }

   void setMode(String m) {
      mode=m;
   }

   //Here is the main event handling loop. Most of the
   //events generate an rLogo command; some of these
   //are cumulative.

   public boolean action(Event e, Object o) {

      setAction("");
      if (e.target==breakButton) { //lets user cancel a program that gets out of control...
         i.Break();
      } else if (e.target==rightButton) {
         setAction("right",true);
      } else if (e.target==leftButton) {
         setAction("left",true);
      } else if (e.target==forwardButton) {
         setAction("forward",true);
      } else if (e.target==backwardButton) {
         setAction("back",true);
      } else if (e.target==homeButton) {
         if (homeButton.getState()) {
            setAction("cs");
         }
         else {
            setAction("home");
         }
      } else if (e.target==colorButton) {
           Color l=c.getColor();
           setAction("setpencolor "+
              Integer.toString(l.getRed())+" "+
              Integer.toString(l.getGreen())+" "+
              Integer.toString(l.getBlue()));
      } else if (e.target==penButton) {
         if (penButton.getState()) {
            setAction("pendown");
         } else {
            setAction("penup");
         }
      } else if(e.target==turtleButton) {
         if (turtleButton.getState()) {
            setAction("showturtle");
         } else {
            setAction("hideturtle");
         }
      }

      if (action.length()>0) {
        if ( action==mode ) { //revise cumulative command
          if ( actionRequiresParameter ) {
              value=new Integer(value.intValue()+increment.intValue());
              commandBox.replaceLastLine(action+" "+value.toString());
          } else {
              commandBox.replaceLastLine(action);
          }
        } else { //new command; reset cumulative variables
          setMode(action);
          if (actionRequiresParameter ) {
              value=increment;
              commandBox.outString(action+" "+value.toString());
          } else {
              commandBox.outString(action);
          }
        }

        //Note that all commands are queued, not executed immediately
        if ( actionRequiresParameter ) {
          i.queue(action+" "+increment.toString());
        } else {
          i.queue(action);
        }
      }
      return true;
   }

}

/*
  LocalInterpreter extends Interpreter by invoking appropriate
  TurtleGraphicsPanel methods.

  Notice that many of the methods update the TurtleControlPanel,
  in order to reflect state changes.

  @see logo.lang.Interpreter

  This class can be contrasted with the RuntimeInterpreter class in
  rLogoRuntime.java

*/
final class LocalInterpreter extends Interpreter {
    TurtleGraphicsPanel tg;
    rLogo cp;
//    TurtleControlPanel cp;

   public LocalInterpreter(TurtleGraphicsPanel t,/*TurtleControlPanel*/rLogo controlPanel) {
      tg=t;
      cp=controlPanel;
   }

   public void wrapString(String s) {
      cp.commandBox.wrapString(s);
   }
   public void forward(int i) {
      tg.forward(i);
      cp.homeButton.setState(false);
   }
   public void backward(int i) {
      tg.backward(i);
      cp.homeButton.setState(false);
   }
   public void turnLeft(int i) {
      tg.turnLeft(i);
      cp.homeButton.setState(false);
   }
   public void turnRight(int i) {
      tg.turnRight(i);
      cp.homeButton.setState(false);
   }
   public void penUp() {
      tg.penUp();
      cp.penButton.setState(true);
   }
   public void penDown() {
      tg.penDown();
      cp.penButton.setState(false);
   }
   public void showTurtle() {
      tg.showTurtle();
      cp.turtleButton.setState(false);
   }
   public void hideTurtle() {
      tg.hideTurtle();
      cp.turtleButton.setState(true);
   }
   public void clearScreen() {
      tg.clearScreen();
      cp.homeButton.setState(false);
   }
   public void home() {
      tg.home();
      cp.homeButton.setState(true);
   }
   public void setColor(Color c) {
      tg.setColor(c);
      cp.c.setColor(c);
   }
   public void setBackColor(Color c) {
      tg.setBackColor(c);
   }
   public void edit(LogoSub s) {
      cp.commandBox.edit(s);
   }
   public void drawString(String s) {
      tg.drawString(s);
   }
   public void setRepaint(boolean b) {
      tg.setRepaint(b);
   }

   public void paint() {
      tg.repaint();
   }

   public void resetMode() {
   // This is called to reset the cumulative variables whenever the
   // user types in a command, so that the TurtleControlPanel::action()
   // loop doesn't get confused.

      cp.setMode("");
   }

}

