/* Copyright (C) 2002,2004 by Peter Eastman

   This program is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT ANY 
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
   PARTICULAR PURPOSE.  See the GNU General Public License for more details. */

package artofillusion.script;

import artofillusion.*;
import artofillusion.ui.*;
import bsh.*;
import buoy.event.*;
import buoy.widget.*;
import java.awt.*;
import java.io.*;
import java.util.*;
import javax.swing.*;

/** This class presents a user interface for entering scripts to be executed. */

public class ExecuteScriptWindow extends BFrame
{
  private LayoutWindow window;
  private BTextArea scriptText;
  private String scriptName;
  
  private static File scriptDir;
  private static String lastScript;
  private static String lastScriptName = "Untitled.bsh";
  
  public ExecuteScriptWindow(LayoutWindow win)
  {
    super(lastScriptName);
    scriptName = lastScriptName;
    BorderContainer content = new BorderContainer();
    setContent(content);
    window = win;
    if (scriptDir == null)
      scriptDir = new File(ModellingApp.TOOL_SCRIPT_DIRECTORY);
    scriptText = new BTextArea(25, 80);
    if (lastScript != null)
      scriptText.setText(lastScript);
    scriptText.setFont(new Font("Monospaced", Font.PLAIN, 11));
    scriptText.setTabSize(2);
    scriptText.addEventLink(KeyTypedEvent.class, this, "keyTyped");
    BScrollPane sp = new BScrollPane(scriptText, BScrollPane.SCROLLBAR_ALWAYS, BScrollPane.SCROLLBAR_ALWAYS);
    content.add(BOutline.createBevelBorder(sp, false), BorderContainer.CENTER);
    RowContainer buttons = new RowContainer();
    content.add(buttons, BorderContainer.SOUTH, new LayoutInfo());
    buttons.add(Translate.button("executeScript", this, "executeScript"));
    buttons.add(Translate.button("Load", "...", this, "loadScript"));
    buttons.add(Translate.button("Save", "...", this, "saveScript"));
    buttons.add(Translate.button("close", this, "closeWindow"));
    pack();
    UIUtilities.centerWindow(this);
    setVisible(true);
  }
  
  private void closeWindow()
  {
    lastScript = scriptText.getText();
    dispose();
  }
  
  /** Prompt the user to load a script. */
  
  private void loadScript()
  {
    BFileChooser fc = new BFileChooser(BFileChooser.OPEN_FILE, Translate.text("selectScriptToLoad"));
    fc.setDirectory(scriptDir);
    fc.showDialog(this);
    if (fc.getSelectedFile() == null)
      return;
    scriptDir = fc.getDirectory();
    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    File f = fc.getSelectedFile();
    try
    {
      BufferedReader in = new BufferedReader(new FileReader(f));
      StringBuffer buf = new StringBuffer();
      int c;
      while ((c = in.read()) != -1)
        buf.append((char) c);
      in.close();
      scriptText.setText(buf.toString());
    }
    catch (Exception ex)
    {
      new BStandardDialog(null, new String [] {Translate.text("errorReadingScript"),
        ex.getMessage()}, BStandardDialog.ERROR).showMessageDialog(this);
    }
    lastScriptName = scriptName = fc.getSelectedFile().getName();
    setTitle(scriptName);
    setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  }
  
  /** Prompt the user to save a script. */
  
  private void saveScript()
  {
    BFileChooser fc = new BFileChooser(BFileChooser.SAVE_FILE, Translate.text("saveScriptToFile"));
    fc.setDirectory(scriptDir);
    fc.setSelectedFile(new File(scriptDir, scriptName));
    fc.showDialog(this);
    if (fc.getSelectedFile() == null)
      return;
    scriptDir = fc.getDirectory();
    
    // Write the script to disk.
    
    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    File f = fc.getSelectedFile();
    try
    {
      BufferedWriter out = new BufferedWriter(new FileWriter(f));
      out.write(scriptText.getText().toCharArray());
      out.close();
    }
    catch (Exception ex)
    {
      new BStandardDialog(null, new String [] {Translate.text("errorWritingScript"),
        ex.getMessage()}, BStandardDialog.ERROR).showMessageDialog(this);
    }
    lastScriptName = scriptName = fc.getSelectedFile().getName();
    setTitle(scriptName);
    
    // Update the Scripts menus in all windows.
    
    EditingWindow allWindows[] = ModellingApp.getWindows();
    for (int i = 0; i < allWindows.length; i++)
      if (allWindows[i] instanceof LayoutWindow)
        ((LayoutWindow) allWindows[i]).rebuildMenuBar();
    setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  }
  
  /** Execute the script. */
  
  private void executeScript()
  {
    try
    {
      ToolScript script = ScriptRunner.parseToolScript(scriptText.getText());
      script.execute(window);
    }
    catch (Exception e)
    {
      int line = ScriptRunner.displayError(e, 1);
      if (line > -1)
        {
          // Find the start of the line containing the error.
          
          String text = scriptText.getText();
          int index = 0;
          for (int i = 0; i < line-1; i++)
            {
              int next = text.indexOf('\n', index);
              if (next == -1)
                {
                  index = -1;
                  break;
                }
              index = next+1;
            }
          if (index > -1)
            scriptText.setCaretPosition(index);
          scriptText.requestFocus();
        }
    }
    window.updateImage();
    scriptText.requestFocus();
  }
  
  /** Provide auto-indent behavior when the user presses Return. */

  private void keyTyped(KeyTypedEvent e)
  {
    if (e.getKeyChar() != '\r' && e.getKeyChar() != '\n')
      return;
    
    // The user has just pressed Return.  Find any white space characters
    // at the beginning of the previous line, and insert them before this line
    // as well.
    
    String text = scriptText.getText();
    int pos = scriptText.getCaretPosition()-1;
    int endWhiteSpace = pos;
    int startLine = pos;
    boolean extraIndent = (startLine > 0 && text.charAt(startLine-1) == '{');
    while (startLine > 0)
    {
      char c = text.charAt(startLine-1);
      if (c == '\r' || c == '\n')
        break;
      startLine--;
      if (!Character.isWhitespace(c))
        endWhiteSpace = startLine;
    }
    String insert = text.substring(startLine, endWhiteSpace);
    if (extraIndent)
      insert = insert+"\t";
    scriptText.insert(insert, pos+1);
  }
}
