//----------------------------------------------------------------------------
// COMPONENT NAME: LPEX Editor
//
// © Copyright IBM Corporation 2004, 2007
// All Rights Reserved.
//
// DESCRIPTION:
// FindsCommand - sample user-defined command (finds)
//----------------------------------------------------------------------------

package com.ibm.lpex.samples;

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

/**
 * Sample command <b>finds</b> - count find-text matches in the document.
 * This command uses the current <b>findText.</b> settings to determine the
 * number of occurrences in the document of either <b>findText.findText</b>
 * or the specified text string.  It is a purely-informational "findText all".
 *
 * <p>Here is the FindsCommand <a href="doc-files/FindsCommand.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.finds com.ibm.lpex.samples.FindsCommand</pre></li>
 *  <li>Run it from the editor command line:
 *    <pre>finds [<i>text</i>]</pre></li>
 * </ul></p>
 *
 * When called with <code>?</code> as a parameter, the command displays its syntax
 * on the message line.
 *
 * @see MatchesCommand
 * @see com.ibm.lpex.samples All the samples
 */
public class FindsCommand implements LpexCommand
{
 /**
  * Runs this command.
  * Displays the number of find-text matches in the view.
  */
 public boolean doCommand(LpexView lpexView, String parameters)
 {
  if (lpexView == null)
   {
    return true;
   }

  if ("?".equals(parameters.trim())) // command help
   {
    lpexView.doCommand("set messageText Syntax: finds [<text>]");
    return true;
   }

  // do the searching
  doFinds(lpexView, parameters);
  return true;
 }

 /**
  * Searches the document.
  */
 void doFinds(LpexView lpexView, String parameters)
 {
  // build the "findText" command parameters, the options-used result message
  StringBuilder findTextParms = new StringBuilder(64);
  StringBuilder options = new StringBuilder(64);
  findTextParms.append(basicFindTextParms());
  if (lpexView.queryOn("current.findText.columns"))
   {
    String startColumn = lpexView.query("current.findText.startColumn");
    String endColumn = lpexView.query("current.findText.endColumn");
    findTextParms.append("columns ")
     .append(startColumn).append(' ').append(endColumn).append(' ');
    setOption(options, "in columns " + startColumn + ".." + endColumn);
   }
  if (lpexView.queryOn("current.findText.block"))
   {
    findTextParms.append("block ");
    setOption(options, "in selection");
   }
  if (lpexView.queryOn("current.findText.wholeWord"))
   {
    findTextParms.append("wholeWord ");
    setOption(options, "whole word");
   }
  if (lpexView.queryOn("current.findText.asis"))
   {
    findTextParms.append("asis ");
    setOption(options, "case sensitive");
   }

  // the text to find - explicitly specified / view's
  String text;
  if (parameters.length() != 0)
   {
    // as ? is used for help, \? is for finding ? (who'd try to find \?...)
    if ("\\?".equals(parameters.trim()))
     {
      int i = parameters.indexOf('\\');
      parameters = parameters.substring(0, i) + parameters.substring(i+1);
     }
    text = parameters;
    findTextParms.append(LpexStringTokenizer.addQuotes(parameters));
   }
  else
   {
    if (lpexView.queryOn("current.findText.regularExpression"))
     {
      findTextParms.append("regularExpression ");
      setOption(options, "regular expression");
     }
    text = lpexView.query("current.findText.findText");
    findTextParms.append(text);
    text = LpexStringTokenizer.removeQuotes(text); // for result
   }

  setOption(options, null); // close it up

  // walk-through document with any redefined "findText" command extras disabled
  String oldFindTextContext = lpexView.query("userParameter.view.findTextContext");
  /**/ lpexView.doCommand("set userParameter.view.findTextContext off");

  String findTextParmsString = findTextParms.toString();
  String cmd0 = "findText checkStart " + findTextParmsString;
  String cmd  = "findText " + findTextParmsString;
  int count = 0;

  // NB LpexView#doCommand(LpexDocumentLocation,String) forces all elements visible
  // while running the specified command - therefore, if we'd want to count only hits
  // in the visible elements we would have to check visibility ourselves in here...
  for (LpexDocumentLocation loc = new LpexDocumentLocation(1, 1); ; count++)
   {
    lpexView.doCommand(loc, ((count == 0)? cmd0 : cmd));
    if (lpexView.query("status") != null)
     {
      break;
     }
    found(lpexView, loc);
   }

  /**/ lpexView.doCommand("set userParameter.view.findTextContext " +
                          ((oldFindTextContext == null)? "" : oldFindTextContext));

  // clear status
  lpexView.doCommand("set status");

  // display result - text: occurrences (options used).
  String countText;
  switch (count)
   {
    case 0:  countText = "not found";     break;
    case 1:  countText = "1 occurrence";  break;
    default: countText = count + " occurrences";
   }
  lpexView.doCommand("set messageText " + text + ": " +
                     countText + options.toString() + ".");
 }

 /**
  * Returns the basic parameters for the "findText" command we'll use.
  */
 String basicFindTextParms()
 {
  return "quiet noBeep noWrap noEmphasis ";
 }

 /**
  * Notification from #doFinds() of a successful find.
  */
 void found(LpexView lpexView, LpexDocumentLocation loc) {}

 /**
  * Adds a setting to the 'options used' for the result message.
  */
 private static void setOption(StringBuilder sb, String option)
 {
  if (sb.length() == 0)
   {
    if (option != null)
     {
      sb.append(option);
     }
   }
  else
   {
    if (option != null)
     {
      sb.append(", ").append(option);
     }
    else
     {
      sb.insert(0, " (").append(')');
     }
   }
 }
}