//CommandBox.java

/*
CommandBox does triple duty: it is the Command Box: the
area where the user enters commands and receives feedback,
the Subroutine Editor, and the Batch Loader/Saver. (The
alternate modes are indicated to the user by changing
the labels at the top of the screen and on the button.)

In Command Entry mode, the user may either type a new
command and press enter, or they may use the arrow keys
to select a previous command for re-execution.

Some platforms seem to have trouble trapping the Enter
key in the handleEvent() loop, so there is an
'Enter' button as well.

In addition to typing commands into the Command Box or
Subroutine Editor, the user may use the Turtle Control
Panel Buttons, which will simulate commands via the
CommandBox's outString() method.
*/

package logo.ui;

import logo.lang.Interpreter;
import logo.lang.LogoSub;

import java.awt.TextArea;
import java.awt.TextField;
import java.awt.Event;
import java.awt.Panel;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Label;
import java.awt.FontMetrics;
import java.awt.Font;

public class CommandBox extends Panel  {

   TextArea ta;
   Interpreter i;
   Button Enter;
   Label label;
   String buffer;
   LogoSub currentSub;  //holds the subroutine that is being edited

   public CommandBox(Interpreter interp) {
      currentSub=null;
      setLayout(new BorderLayout());
      setInterpreter(interp);
      ta = new TextArea();
      Enter = new Button("");
      resetButton();
      label = new Label("",Label.CENTER);
      label.setFont(new Font("TimesRoman",Font.BOLD,14));
      resetLabel();
      add("North",label);
      add("South",Enter);
      add("Center",ta);
      requestFocus();
   }

   public void setInterpreter(Interpreter interp) {
      i=interp;
   }

   public void edit(LogoSub s) {
      currentSub=s;
      buffer=ta.getText(); //hold the CommandBox buffer until we're finished
      ta.setText(currentSub.getValue());
      if ( currentSub.getName().equals(i.rLOGO_BATCH) ) {
        setLabel("rLogo Batch Input");
      } else if ( currentSub.getName().equals(i.rLOGO_DUMP) ) {
        setLabel("rLogo Batch Dump");
        ta.setEditable(false);
      } else setLabel("to "+currentSub.getName());
      setButton("Finished");
   }

   public void setButton(String s) {
      Enter.setLabel(s);
   }

   public void resetButton() {
      Enter.setLabel("Enter");
   }

   public void setLabel(String l) {
      label.setText(l);
   }

   public void resetLabel() {
      label.setText("rLogo Command Box");
   }

   public void wrapString(String s) {
      clearIncompleteCommand();
      ta.appendText( wrap(s) );
      gotoBottom();
   }

   public void outString(String s) {
      clearIncompleteCommand();
      ta.appendText( s+"\n" );
      gotoBottom();
   }


   public void replaceLastLine(String s) {
      //replaces the last line with a new string
      clearIncompleteCommand();
      String text=ta.getText();
      int start=text.lastIndexOf("\n",text.length()-2)+1; //finds the 2nd to last 'newline'
      if (start<0) start=0;
      ta.replaceText(s+"\n",start,text.length());
   }

   public void clearIncompleteCommand() {
      //corrects a subtle quirk when a user begins to type
      //a command, but then decides to press a button on the
      //TurtleControlPanel before finishing.
      String text=ta.getText();
      if ( !text.endsWith("\n") ) {
        int lastLine=text.lastIndexOf("\n")+1;
        ta.replaceText(text.substring(0,lastLine),0,text.length());
      }
   }

/*   String thisLine() {
      return ta.getText();
   }*/

   public boolean handleEvent(Event e) {
      boolean result = false;
      if ( currentSub==null ) {
          if ( (e.id==Event.KEY_PRESS && e.key=='\n') || e.id==1001) {
              processNextCommand();
              result = true;
          }
      } else {
          if ( e.id==1001) { //finished editing subroutine...
              if ( currentSub.getName().equals(i.rLOGO_BATCH) ) {
                  i.load(ta.getText()); //process this program immediately...
              } else if ( currentSub.getName().equals(i.rLOGO_DUMP) ){
                  ta.setEditable(true); //turn editor back on
              } else {
                  currentSub.setValue(ta.getText());
              }
              currentSub=null;
              resetLabel();
              resetButton();
              ta.setText(buffer);
              gotoBottom();
              result = true;
          }
      }
      //return result;
      if (result==true) return true;
      else return super.handleEvent(e);
   }

  void gotoBottom() { //positions cursor at the end of the CommandBox
    ta.select(ta.getText().length(),ta.getText().length());
  }

  void processNextCommand() {
      i.resetMode();
      int start=ta.getSelectionStart()-1;
      String text=ta.getText();
      while (start>0 && text.charAt(start)!='\n') start--;
      if (start<0) start=0;
      if (text.charAt(start)=='\n') start++;
      String command = text.substring(start);
      if ( !command.startsWith(">") ) { //ignore lines starting with ">" (rLogo output)
        int stop=command.indexOf("\n");
        if (stop>=0) command = command.substring(0,stop);
        else stop=0;
        command.trim();
        if ( command.length()>0 ) {
            //if the user arrowed up to repeat a command, be sure to append it to the end:
            if ( !text.endsWith(command) ) ta.appendText(command+"\n");
            //otherwise, just append the newline that was trapped:
            else ta.appendText("\n");
            gotoBottom();
            if ( command.trim().toLowerCase().equals("break") ) {
              i.stop();
            } else i.queue(command);
        }
      } else gotoBottom();
  }

  public String wrap(String rawText) {
   int maxLength;
   int maxSize = (int)(ta.size().width * .8);
   //it would be nice to be able to access the vertical scrollbar,
   //get its length, and subtract it here. Instead, I approximate.
      FontMetrics fm = getFontMetrics(ta.getFont());
      String result = new String();
      while (rawText.length()>0) {
         for (maxLength=1; maxLength<rawText.length() && fm.stringWidth(rawText.substring(0,maxLength))<maxSize; maxLength++) {
            if (rawText.charAt(maxLength)=='\n') { //reset every time a 'hard' newline is encountered
               result=result.concat( "> "+rawText.substring(0,maxLength)+"\n" );
               if (rawText.length()>maxLength) {
                  rawText=rawText.substring(maxLength+1);
               } else {
                  rawText="";
               }
               maxLength=1;
            }
         }
         if ( maxLength>=rawText.length() ) {
            maxLength=rawText.length();
         } else {
            while (maxLength>0 && rawText.charAt(maxLength)!=' ') {
                maxLength--;
            }
            maxLength++;
         }
         result=result.concat( "> "+rawText.substring(0,maxLength)+"\n" );
         rawText=rawText.substring(maxLength);
      }
      return result;
  }

}
