import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.awt.*;
import java.net.*;
import java.util.*;
class TA extends JTextArea implements KeyListener,MouseMotionListener, MouseListener
 {
  //ref
  int pre10=0,lastj=0;
  CC cc;
  Font ft;
  int ftsize,ftstyle;
  String ftname;
  Action[] actions;
  Action caretdown,caretbeginline;
  Dimension size = new Dimension(0,0);
  String terpstr="",terpstrold="";
  String pos="";
  int carposold=0,carpos,kc0,kc1=0,kc2=0;
  int carposmemory=0;
  char keychar;
  char ca2[],chararray[];
  URL codebase;
  static M parent;
  Te te;
  dP s=new dP(300,500);
  String name="none",host="nohost";
  boolean gbd=false;
  K fk,bk,ck;
  int lastcarpos=0;
  boolean tecon=true;
  LSpP lspp;
  LScP lscp;
  Rec lscprec;
  public TA(M p,String n,LSpP lspp,String pos,boolean tecon,Rec lscprec,K fk, K bk,K ck)
   {
    super();
    this.fk=fk;
    this.bk=bk;
    this.ck=ck;
    this.setForeground(fk.c);
    this.setCaretColor(ck.c);
    this.setBackground(bk.c);
    tacom(p,n,lspp,pos,lscprec,tecon);
   }
  public TA(M p,String n,LSpP lspp,String pos,boolean tecon)
   {
    super();
    fk=new K(10.0,0.0,0.0,255.0);
    bk=new K(225.0,200.0,150.0,255.0);
    ck=new K(20.0,0.0,0.0,255.0);
    setForeground(fk.c);
    setCaretColor(ck.c);
    setBackground(bk.c);
    tacom(p,n,lspp,pos,new Rec(0,0,600,200),tecon);
   }
  public void tacom(M p,String n,LSpP lspp,String pos,Rec lscprec,boolean tecon)
   {
    parent=p;
    te=parent.te;
    this.lspp=lspp;
    name=n;
    this.pos=pos;
    this.tecon=tecon;
    this.lscprec=lscprec;
    host=lspp.name;
    lscp = new LScP(parent,name+"lscp",lscprec);
    //lscp.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
    lscp.getViewport().add(this);
    if(pos.equals("top")) lspp.setTopComponent(lscp);
    if(pos.equals("bottom")) lspp.setBottomComponent(lscp);
    if(pos.equals("right")) lspp.setRightComponent(lscp);
    if(pos.equals("left")) lspp.setLeftComponent(lscp);
    Te.TAh.put(name,this);
    init();
   }
  public void dofin()
   {
    lscp.remove(this);
    lspp.remove(lscp);
    lspp.doLayout();
    lspp.repaint();
   }
  public void initb()
   {
   }
  static int ivoftstyle(String s)
   {
    if(s.equals("bold")) return Font.BOLD;
    else if(s.equals("plain")) return Font.PLAIN;
    else if(s.equals("italic")) return Font.ITALIC;
    return -1;
   }
  static String Svoftstyle(Font f)
   {
    return Svoftstyle(f.getStyle());
   }
  static String Svoftstyle(int i)
   {
    if(i==Font.BOLD) return "bold";
    else if(i==Font.PLAIN) return "plain";
    return "unknown font style";
   }
  void setftname(String ftname)
   {
    this.ftname=ftname;
    setft();
   }
  void setftstyle(String s)
   {
    ftstyle=ivoftstyle(s);
    setft();
   }
  void setftsize(double d)
   {
    this.ftsize=(int)d;
    setft();
   }
  void setft() 
   {
    ft=new Font(ftname,ftstyle,ftsize);
    setFont(ft);
   }
  void fk(K k) 
   {
    fk=k;
    setForeground(fk.c);
   }
  void ck(K k)
   {
    ck=k;
    setCaretColor(ck.c);
   }
  void bk(K k)
   {
    bk=k;
    setBackground(bk.c);
   }
  void init()
   {
    ftsize=15;
    ftname="Default";
    ftstyle=ivoftstyle("plain");
    setft();
    setEditable(true);
    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    setLineWrap(false);
    addMouseListener(this);
    addMouseMotionListener(this);
    addKeyListener(this);
    getCaret().setBlinkRate(500);
    size= new Dimension(500,300);
    Rectangle rect = new Rectangle(0,0,500,500);
    scrollRectToVisible(rect);
    actions = getActions();
    for(int i=0; i < actions.length; ++i)
     {
      if(((String)actions[i].getValue(Action.NAME)).equals("caret-down")) caretdown=actions[i];
      else if(((String)actions[i].getValue(Action.NAME)).equals("caret-begin-line")) caretbeginline=actions[i];
     }
    Keymap km=getKeymap();
    KeyStroke ks=KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
    Action act=new TextAction("Ctrl-Z")
     {
      public void actionPerformed(ActionEvent e)
       {
        caretdown.actionPerformed(null);
        caretbeginline.actionPerformed(null);
       }
     }
    ;
    km.addActionForKeyStroke(ks, act);
    //km.addActionForKeyStroke(ks, caretdown);
    //km.addActionForKeyStroke(ks, caretbeginline);
    this.requestFocus();
   }
  void ct() { replaceRange("",0,getText().length()); }
  static void tta(String s) { ttancr(s+"\n"); }
  static void ttancr(String s) 
   {
    parent.ta.append(s);
    //setCaretPosition(carposold+s.length()); 
   }
  void carettoend() 
   {
    carposold=getText().length();
    setCaretPosition(carposold); 
   }
  int rcp() { return carposmemory=getCaretPosition(); }
  void scp() { setCaretPosition(carposmemory); }
  void scp(int i) { setCaretPosition(i); }
  public void keyPressed( KeyEvent e ) 
   {
    //System.out.println("keyPressed:"+e.getKeyCode());
   }
  public void keyTyped( KeyEvent e ) { }
  public void keyReleased( KeyEvent e )
   {
    kc0=e.getKeyCode(); 
    //tta("kc0:"+kc0);
    keychar=e.getKeyChar();
    carpos=getCaretPosition();
    int carposorg=carpos;
    chararray=getText().toCharArray();
    terpstr="";
    pre10=0;
    lastj=0;
    int post10=0,i=0;
    if(carposold>chararray.length) carposold=chararray.length;
    for(int j=0;j<carposold;j++) { if((int)chararray[j]== 10) pre10=j+1; }
    for(int j=pre10;j<chararray.length;j++)
     {
      if((int)chararray[j]== 10)
       {
        post10=j;
        break;
       }
      else terpstr=terpstr+chararray[j];
      lastj=j;
     }
    if(post10==0 && (kc0==10 || kc0==122 ))
     {
      //ttab("return not found, setting caret at end of chararray");
      append("\n");
      insert("\n",carpos);
      setCaretPosition(carpos);
      preTerp(terpstr);
     }
    else if(kc0==10) 
     {
      if(tecon)
       {
        insert("\n",carpos);
        setCaretPosition(carpos);
       }
      else
       {
        insert("\n",carposold);
        setCaretPosition(carposold+1);
       }
      preTerp(terpstr);
     }
    else 
     {
      tree();
      kc2=kc1;
      kc1=kc0;
      kc0=0;
      carposold=getCaretPosition();
     }
   }
  void tree() { tree(kc0,kc1,kc2); }
  void tree(int a,int b,int c)
   {
    //tta("tree kc0:"+kc0+" kc1:"+kc1+" kc2:"+kc2);
    kc0=a;
    kc1=b;
    kc2=c;
    if(kc1==123)
     {
      if(kc0==123)
       {
        parent.newTeS("lMeth");
        tree(0,0,0);
       }
      else tree(kc0,0,0);
     }
    else if(kc0==123) replaceRange("",0,getText().length());  //F12 clear TA
    else if(kc0==122)
     {
      // Clear current line and below
      insert("\n",carpos);
      replaceRange("",pre10,getText().length());
     }
    else if(kc0==121) //F10
     {
      replaceRange("",pre10,1+lastj);
     }
    else if(kc0==118) refdocs(); //F7 Reference Docs
    else if(kc0==117) //F6  interpret old string
     {
      preTerp(terpstrold);
     }
    else if(kc0==116) //F5  interpret and stay on line
     {
      preTerp(terpstr);
      setCaretPosition(carposold);
     }
    else if(kc0==115) //F4 insert a line above
     {
      if(tecon)
       {
        insert("\n",pre10);
        setCaretPosition(pre10);
       }
      else ZZ(0);
     }
    else if(kc0==114) //F3 insert a line below
     {
      if(tecon)
       {
        insert("\n",1+lastj);
        setCaretPosition(lastj+2);
       }
      else ZZ(1);
     }
    else if(kc0==113) //F2 function key help
     {
      if(tecon)
       {
        if(kc1==113)replaceRange("",0,getText().length()); 
        else genhelp();
       }
     }
   }
  static void genhelp()
   {
    tta("");
    tta("F12 Clear text area. Hit F12 again and it lists Methods");
    tta("F11 Clear to bottom");
    tta("F10 Clear current line");
    //tta("F7 Reference Documentation");
    //tta("F6 Command Dictionary");
    tta("F5 Interpret and stay on current line (very useful in the editor)");
    tta("F4 Insert line above current or exit editor with no changes");
    tta("F3 Insert line below current or exit editor making changes");
    tta("F2 This listing.");
   }
  static void simplecd() 
   {
    tta("");
    tta("F6 Simple Command Dictionary");
    tta("F6 F6 for full Dictionary (F6 from here)");
    tta("Command           name   example");
    tta("clear screen      cs     cs");
    tta("draw forward      fd     fd 100");
    tta("right turn        rt     rt 45");
    tta("left turn         lt     lt 45");
    tta("repeat            rp     rp 4[ fd 50 rt 90]");
    tta("add a Slider      aSl    aSl aa");
    tta("make a procedure  mk     mk oct(cs rp 8[fd 100 rt 45])");
    tta("run a procedure   --     oct   this runs the above procedure");
    tta("use editor        ed     ed oct   this brings oct up in the editor");
    tta("F2 for General Help                 Use F12 to clear screen");
   }
  static void fullcd()
   {
    tta("");
    tta("F6 F6 Full Command Dictionary");
    tta("F6 F6 F3 turtle commands  (F3 from here)");
    tta("F6 F6 F4 math commands");
   }
  static void Tuco()
   {
    tta("");
    tta("F6 F6 F3 turtle commands");
    tta("This is where the turtle commands will be");
   }
  void clear() { replaceRange("",0,getText().length()); }
  static void refdocs()
   {
    tta("");
    tta("F7 Reference Documentation");
    tta("F7 F3 Using the Slider (F3 from here)");
    tta("F7 F4 Using Chat");
    tta("F7 F5 Using AJLogo as an application");
    tta("F12 to clear screen");
   }
  static void Sldocs() { tta("This will be the Slider doc area"); }
  static void CCdocs() { tta("This will be the Chat doc area"); }
  static void Appdocs() { tta("This will be the Application doc area"); }
  void preTerp(String s)
   {
    terpstrold=s;
    //tta(name+" preTerp s:"+s+" cc.conn:"+cc.conn);
    if(s.equals("aAJLogo"))
     {
      tta("Adding new AJLogo");
     }
    else if(name.equals("ta2") && cc.conn)
     {
      if(s.indexOf("!")==0) parent.newTeS(s.substring(1));
      if (cc !=null ) cc.sendo(s);
     }
    else if(tecon || kc0==116) 
    	{
    	parent.newTeSTC(s); //F5  interpret and stay on line
    	}
   }
  void ZZ(int mode)
   {
    String t=getText();
    replaceRange("",0,t.length());
    te.teS("ZZ");
    if(mode ==1) te.teS(t);
   }
  public void mousePressed(MouseEvent e) 
   {
    carposold=getCaretPosition();
    int a=carposold;
    boolean bo=true;
    chararray=getText().toCharArray();
    while(a>0 && a< chararray.length -1 && bo)
     {
      if(chararray[a] == 10)
       {
        if(a< chararray.length -1) a++;
        bo=false;
       }
      else  a--;
     }
    int b=a;
    a=carposold;
    bo=true;
    while(a< chararray.length -1 && bo)
     {
      if(chararray[a] == 10) 
       {
        bo=false;
        if(a>0) a--;
       }
      else a++;
     }
    int f=a;  
    //tta("pressed"+carposold+" b:"+b+" f:"+f);
    String ls="";
    if(f!=chararray.length)
     {
      for(int i=b;i<=f;i++) ls=ls+chararray[i];
     }
    else ls="End of string";
    // tta("Result:"+ls);
   }
  public void mouseDragged(MouseEvent e) { }
  public void mouseMoved(MouseEvent e) { this.requestFocus(); }
  public void mouseClicked(MouseEvent e) { }
  public void mouseReleased(MouseEvent e) { }
  public void mouseEntered(MouseEvent e) { this.requestFocus(); }
  public void mouseExited(MouseEvent e) { }
  dP getSize(int mode) { return s=new dP(getSize()); }
  public void sSize(Dimension size)
   {
    this.size=size;
    setPreferredSize(size);
    revalidate();
   }
  void ed()
   {
    tta1(name+".ftname "+ftname);
    tta1(name+".ftstyle "+Svoftstyle(ftstyle));
    tta1(name+".ftsize "+Te.Svo(ftsize));
    tta1(name+".fk "+Te.Svo(fk));
    tta1(name+".bk "+Te.Svo(bk));
    tta1(name+".ck "+Te.Svo(ck));
    tta1(name+".editable "+Te.Svo(isEditable()));
   }
  void tta1(String s) { parent.tta1(s); }
 }
