//
// Mini Java Editor window
//

import iss.util.*;

import java.io.*;
import java.awt.*;

// Text Area

class MJETextArea extends TextArea implements MJELabels {
  MJEWindow window;
  boolean dirty;
  static final int CTRL_A = 1;
  static final int CTRL_F = 6;
  static final int CTRL_G = 7;
  static final int CTRL_O = 15;
  static final int CTRL_R = 18;
  static final int CTRL_S = 19;

  MJETextArea(MJEWindow win, int row, int col) {
    super(row, col);
    window = win;  
  }

  boolean isDirty() {
    return dirty;
  }

  void clean() {
    dirty = false;
  }

  void dirty() {
    dirty = true;
  }

  public boolean keyDown(Event evt, int key) {
    switch (key) {
      case CTRL_A:
	window.action(evt, SELECT_ALL);
	return true;

      case CTRL_F:
	window.action(evt, FIND);
	return true;

      case CTRL_G:
	window.action(evt, GOTO_LINE);
	return true;

      case CTRL_R:
	window.action(evt, REVERT);
	return true;

      case CTRL_S:
	window.action(evt, SAVE);
	return true;

      case Event.F7:
	window.action(evt, INDENT_LEFT);
	return true;

      case Event.F8:
	window.action(evt, INDENT_RIGHT);
	return true;

      case Event.F12:
	//window.action(evt, COMPILE);
	window.action(evt, EXIT);
	return true;
    }

    dirty = true;
    return false;
  }
}

class MJEWindow extends Frame implements MJELabels {
  MJETextArea area;
  String clipboard = "";
  String savePath = null;
  GotoDialog gotoDialog = null;
  FindDialog findDialog = null;

  MenuItem saveItem = new MenuItem(SAVE);
  MenuItem compileItem = new MenuItem(COMPILE);
  MenuItem closeItem = new MenuItem(CLOSE);

  MJEWindow(String title, Font fnt) {

  // Initialize

    area = new MJETextArea(this, 25, 80);
    MenuBar menuBar = new MenuBar();

  // Create file menu

    Menu fileMenu = new Menu("File");
    fileMenu.add(new MenuItem(NEW));
    fileMenu.add(new MenuItem(OPEN));
    fileMenu.add(saveItem);
    fileMenu.add(new MenuItem(SAVE_AS));
    fileMenu.add("-");
    fileMenu.add("Revert");
    fileMenu.add("-");
    //fileMenu.add(compileItem);
    fileMenu.add(closeItem);
    menuBar.add(fileMenu);

  // Create edit menu

    Menu editMenu = new Menu("Edit");
    editMenu.add(new MenuItem(CUT));
    editMenu.add(new MenuItem(COPY));
    editMenu.add(new MenuItem(PASTE));
    editMenu.add(new MenuItem(SELECT_ALL));
    editMenu.add("-");
    editMenu.add(new MenuItem(INDENT_LEFT));
    editMenu.add(new MenuItem(INDENT_RIGHT));
    editMenu.add("-");
    editMenu.add(new MenuItem(GOTO_LINE));
    editMenu.add(new MenuItem(FIND));
    menuBar.add(editMenu);
 
  // Show window

    setMenuBar(menuBar);
    saveItem.disable();
    //compileItem.disable();

    changeFont(fnt);
    setTitle(title);

    open(title);

    add("Center", area);
    pack();
    show();
  }

// Open file

  public boolean open(String path) {
    if (path != null) {
      setTitle(getFile(path));
      savePath = path;
      area.setText(readFile(path));
      saveItem.enable();
/*
      if (path.endsWith(".java")) 
	compileItem.enable();
      else
	compileItem.disable();
*/
      return true;
    }

    return false;
  }

  public boolean save() {
    if (area.isDirty()) {
      writeFile(savePath, area.getText());
      area.clean();
    }

    return true;
  }

// Read file

  public String readFile(String fl) {
    File file = new File(fl);
    StringBuffer text = new StringBuffer((int) file.length());

    try {
      FileInputStream fs = new FileInputStream(fl);
      BufferedInputStream bs = new BufferedInputStream(fs, 5000);
      DataInputStream ds = new DataInputStream(bs);
      String str = ds.readLine();

      while (str != null) {
  	text.append(str);
	text.append("\n");
	str = ds.readLine();
      }

      fs.close();
    } catch (Exception err) {
      //editor.console.set("Cannot read file.");
    }

    return text.toString();
  }

// Write file

  public void writeFile(String fl, String txt) {
    try {
      //editor.console.set("Saving " + savePath + "...");
      StringBufferInputStream ss = new StringBufferInputStream(txt);
      DataInputStream ds = new DataInputStream(ss);
      FileOutputStream fs = new FileOutputStream(fl);
      BufferedOutputStream bs = new BufferedOutputStream(fs);
      PrintStream ps = new PrintStream(bs);
      String ls = System.getProperty("line.separator");
      String str = ds.readLine();
   
      while (str != null) {
	ps.print(str);
	ps.print(ls);
  	str = ds.readLine();
      }

      ps.close();
      //editor.console.add("Done.");
    } catch (Exception err) {
      //editor.console.set("Cannot write file.");
    }
  }

// Handle system event

  public boolean handleEvent(Event evt) {
    if (evt.id == Event.WINDOW_DESTROY && evt.target == this)
      hide();

    return super.handleEvent(evt);
  }

// Handle component events

  public boolean action(Event evt, Object obj) {
    String label = (String) obj;
    String file = null;
  
  // Handle file menu

    if (label.equals(NEW)) {
      area.setText("");
      area.clean();
      setTitle("Untitled");
      saveItem.disable();
      return true;
    }

    if (label.equals(OPEN)) {
      FileDialog dialog = new FileDialog(this, "Open...", FileDialog.LOAD);

      dialog.show();
      file = dialog.getFile();

      if (file != null)
	open(dialog.getDirectory() + file);

      area.clean();
      return true;
    }

    if (label.equals(SAVE)) {
      writeFile(savePath, area.getText());
      area.clean();
    }

    if (label.equals(SAVE_AS)) {
      FileDialog dialog = new FileDialog(this, "Save As...", FileDialog.SAVE);
      
      dialog.setFile(savePath);
      dialog.show();
      file = dialog.getFile();

      if (file != null) {
	setTitle(file);
	savePath = dialog.getDirectory() + file;
        saveItem.enable();
	writeFile(file, area.getText());
      }

      area.clean();
      return true;
    }

    if (label.equals(REVERT)) {
      open(savePath);
      area.clean();
    }

    if (label.equals(CLOSE)) {
      hide();
      return true;
    }

    if (label.equals(COMPILE)) {
      if (area.isDirty()) {
        //editor.console.set("Saving " + savePath + "...");
        writeFile(savePath, area.getText());
	area.clean();
      }

      //editor.compile(savePath, true);
    }

  // Handle edit menu

    if (label.equals(CUT)) {
      this.clipboard = area.getSelectedText();
      area.replaceText("", area.getSelectionStart(), 
      area.getSelectionEnd());
      area.dirty();

      return true;
    }

    if (label.equals(COPY)) {
      this.clipboard = area.getSelectedText();
      return true;
    }

    if (label.equals(PASTE)) {
      int start = area.getSelectionStart();
      int end = area.getSelectionEnd();

      if (start == end) 
        area.insertText(this.clipboard, start);
      else
        area.replaceText(this.clipboard, start, end);

      area.dirty();
      return true;
    }

    if (label.equals(SELECT_ALL))
      area.selectAll();

    if (label.equals(INDENT_LEFT)) {
      int start = getLine(area.getSelectionStart());
      int end = getLine(area.getSelectionEnd());
      String str = area.getText();
      String rstr = "";

      for (int i = start; i < end + 1; i++) {
	int pos = getPosition(str, i);

        int count = 0; 
        int j = pos;
        char ch = str.charAt(j);

        while (ch == ' ' || ch == '\t') {
	  if (ch == ' ')
	    count++;
  	  else
	    count += ((count + 8) / 8 * 8 - count);

	  j++;
	  ch = str.charAt(j);
        }

        rstr = str.substring(0, pos);

	if (count > 2)
          for (int k = 0; k < count - 2; k++)
	    rstr = rstr + " ";

        str = rstr + str.substring(j);
      }

      area.setText(str);
      area.select(getPosition(start), getPosition(end + 1) - 1);
    }

    if (label.equals(INDENT_RIGHT)) {
      int start = getLine(area.getSelectionStart());
      int end = getLine(area.getSelectionEnd());
      String str = area.getText();
      String rstr = "";

      for (int i = start; i < end + 1; i++) {
	int pos = getPosition(str, i);

        int count = 0; 
        int j = pos;
        char ch = str.charAt(j);

        while (ch == ' ' || ch == '\t') {
	  if (ch == ' ')
	    count++;
  	  else
	    count += ((count + 8) / 8 * 8 - count);

	  j++;
	  ch = str.charAt(j);
        }

        rstr = str.substring(0, pos);

        for (int k = 0; k < count + 2; k++)
	  rstr = rstr + " ";

        str = rstr + str.substring(j);
      }

      area.setText(str);
      area.select(getPosition(start), getPosition(end + 1) - 1);
    }

    if (label.equals(GOTO_LINE)) {
      if (gotoDialog == null) {
      	gotoDialog = new GotoDialog(this);
     	gotoDialog.pack();
      }

      gotoDialog.show();	
      return true;
    }

    if (label.equals(FIND)) {
      if (findDialog == null) {
      	findDialog = new FindDialog(this);
      	findDialog.pack();
      }

      area.dirty();
      findDialog.show();	
      return true;
    }
    
    return false; 
  }

// Change font

  public void changeFont(Font fnt) {
    if (fnt != null)
      area.setFont(fnt);
  }

// Get text area

  public TextArea getTextArea() {
    return area;
  }

// Get file name from path

  public String getFile(String path) {
    char sp = System.getProperty("file.separator").charAt(0);

    for (int i = path.length() - 1; i > 0; i--)
      if (path.charAt(i) == sp)
	return path.substring(i + 1, path.length());

    return path;  
  }

// Go to line

  public void gotoLine(int line) {
    gotoLine(line, 0);
  }

  public void gotoLine(int line, int col) {
    int pos = getPosition(line);

    area.requestFocus();
    area.select(pos + col, pos + col);
  }

// Get position

  public int getPosition(int line) {
    return getPosition(area.getText(), line);
  }

  public int getPosition(String str, int line) {
    int i = 1, pos = 0;

    while (i < line) {
      if (str.charAt(pos) == '\n')
	i++;

      pos++;
    }

    return pos;
  }

// Get line

  public int getLine(int pos) {
    int i = 0, line = 1;
    String str = area.getText();

    while (i < pos) {
      if (str.charAt(i) == '\n')
	line++;

      i++;
    }

    return line;
  }
}
