//----------------------------------------------------------------------------
// COMPONENT NAME: LPEX Editor
//
// © Copyright IBM Corporation 2006
// All Rights Reserved.
//
// DESCRIPTION:
// ExecCommand - sample user-defined command (exec)
//----------------------------------------------------------------------------

package com.ibm.lpex.samples;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

import com.ibm.lpex.core.LpexCommand;
import com.ibm.lpex.core.LpexStringTokenizer;
import com.ibm.lpex.core.LpexView;

/**
 * Sample command <b>exec</b> - execute the specified file, visible selected
 * text, or current line as editor commands. This command is similar to the
 * <b>execCommand</b> editor action, but extends it to allow the execution of
 * several editor commands.  Comment lines, starting with <code>"//"</code>,
 * are ignored.
 *
 * <p>Here is the ExecCommand
 * <a href="doc-files/ExecCommand.java.html">source code</a>.</p>
 *
 * <p>To run this sample:
 * <ul>
 *  <li>Define this user command via an editor preference page, where available,
 *    or from the editor command line:
 *    <pre>set commandClass.exec com.ibm.lpex.samples.ExecCommand</pre></li>
 *  <li>Run it from the editor command line:
 *    <pre>exec [<i>fileName</i>]</pre></li>
 * </ul></p>
 *
 * @see com.ibm.lpex.samples All the samples
 */
public class ExecCommand implements LpexCommand
{
 boolean _inExec;

 /**
  * Runs this command.
  * Executes the specified file, selected text, or current line as editor commands.
  *
  * @param lpexView the document view in which the command was issued
  * @param fileName optional name of a file to use
  */
 public boolean doCommand(LpexView lpexView, String fileName)
 {
  if ("?".equals(fileName.trim())) // command help
   {
    lpexView.doCommand("set messageText Syntax: exec [<file name>]");
    return true;
   }

  // prevent recursive calls
  if (_inExec)
   {
    if (lpexView != null)
     {
      lpexView.doCommand("set messageText Command \"exec\" already in progress, canceled.");
     }
    return true;
   }

  /**/ _inExec = true;
  fileName = LpexStringTokenizer.trimQuotes(fileName.trim());
  if (fileName.length() != 0)
   {
    exec(lpexView, fileName);
   }
  else
   {
    exec(lpexView);
   }
  /**/ _inExec = false;

  return true;
 }

 /**
  * Executes as editor commands the lines in the specified text file.
  */
 private void exec(LpexView lpexView, String fileName)
 {
  BufferedReader br = null;
  try
   {
    br = new BufferedReader(new FileReader(fileName));
    for (String line; (line = br.readLine()) != null;)
     {
      execOneLine(lpexView, line);
     }
   }
  catch (IOException e)
   {
    if (lpexView != null)
     {
      lpexView.doCommand("set messageText Cannot read file \"" + fileName + "\".");
     }
   }
  finally
   {
    if (br != null)
     {
      try
       {
        br.close();
       }
      catch(Exception e) {} // ignore exceptions on close
     }
   }
 }

 /**
  * Executes as editor commands any visible selection, or else the current element.
  */
 private void exec(LpexView lpexView)
 {
  if (lpexView != null)
   {
    String commands = lpexView.query("block.text");
    if (commands == null)
     {
      commands = lpexView.query("text");
     }

    if (commands != null)
     {
      String[] lines = commands.split("\\r\\n|\\r|\\n");
      for (int i = 0; i < lines.length; i++)
       {
        execOneLine(lpexView, lines[i]);
       }
     }
   }
 }

 /**
  * Executes the editor command in the given line of text.
  * It the text starts with a comment "//", it is ignored.
  * @return true the line is correct (empty / comment / valid editor command)
  */
 private boolean execOneLine(LpexView lpexView, String text)
 {
  int i = 0;

  // skip leading whitespace
  while (i < text.length() && (text.charAt(i) == ' ' || text.charAt(i) == '\t')) { i++; }

  // ignore comment "//" lines
  if (text.startsWith("//", i))
   {
    return true;
   }

  if (i != 0)
   {
    text = text.substring(i);
   }

  // if there is anything in the line, run it
  return (text.length() == 0)? true :
         (lpexView != null)? lpexView.doCommand(text) :
                             LpexView.doGlobalCommand(text);
 }
}