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

package com.ibm.lpex.samples;

import java.util.HashSet;
import java.util.Iterator;

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

/**
 * Sample command <b>matches</b> - highlight find-text matches in the document.
 * This command extends {@link FindsCommand} to determine, and also highlight, the
 * occurrences in the document of either <b>findText.findText</b> or the
 * specified text string.  It is a "findText all" which highlights the results
 * rather than filtering the view.
 *
 * <p>Here is the MatchesCommand <a href="doc-files/MatchesCommand.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.matches com.ibm.lpex.samples.MatchesCommand</pre></li>
 *  <li>Run it from the editor command line:
 *    <pre>matches [<i>text</i>]</pre></li>
 * </ul></p>
 *
 * When called with <code>?</code> as a parameter, the command displays its syntax
 * on the message line.  It also clears any existing matches.
 *
 * @see com.ibm.lpex.samples All the samples
 */
public class MatchesCommand extends FindsCommand
{
 // choose an unlikely style character for the match marks
 // (TODO create parameter to return an unassigned styleAttributes character!?)
 private static final char _matchStyleChar = '`';

 // use a yellow background to highlight the matches
 private static final String _matchStyle = "-1 -1 -1 255 255 0";

 // set of match marks
 private HashSet<String> _marks = new HashSet<String>();

 // "findText" command stuff
 private int _foundTextLength;
 private LpexCommand _oldFindTextCommand;
 private LpexCommand _findTextCommand = new LpexCommand() {
  public boolean doCommand(LpexView lpexView, String parameters) {
   return doFindTextCommand(lpexView, parameters);
  }};


 /**
  * Runs this command.
  * Highlights the find-text matches on the current screen.
  */
 public boolean doCommand(LpexView lpexView, String parameters)
 {
  if (lpexView == null)
   {
    return true;
   }

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

  // ensure the mark highlight character style is still defined
  lpexView.doCommand("set styleAttributes." + _matchStyleChar + ' ' + _matchStyle);

  // in order to get found-text's length for each match (which may differ each time
  // in the case of regular expression), temporarily extend the "findText" command
  // in this view so we can query the emphasisLength after each find
  _oldFindTextCommand = lpexView.defineCommand("findText", _findTextCommand);
  // System.out.println(" class="+lpexView.query("commandClass.findText"));

  // clear any old matches
  clearMatches(lpexView);

  // do the searching
  doFinds(lpexView, parameters);

  // restore the original "findText" command in this view
  lpexView.defineCommand("findText", _oldFindTextCommand);
  // System.out.println(" class="+lpexView.query("commandClass.findText"));

  return true;
 }

 /**
  * Implementation of the temporarily redefined "findText" command.
  */
 boolean doFindTextCommand(LpexView lpexView, String parameters)
 {
  boolean rc;
  if (_oldFindTextCommand != null)
   {
    rc = _oldFindTextCommand.doCommand(lpexView, parameters);
   }
  else
   {
    rc = lpexView.doDefaultCommand("findText " + parameters);
   }

  _foundTextLength = lpexView.queryInt("emphasisLength");
  return rc;
 }

 /**
  * Clear all the match marks from a previous run.
  */
 void clearMatches(LpexView lpexView)
 {
  if (!_marks.isEmpty())
   {
    Iterator<String> iterator = _marks.iterator();
    while (iterator.hasNext())
     {
      String markId = iterator.next();
      lpexView.doCommand("set mark.#" + markId + " clear");
     }

    _marks.clear();
   }
 }

 /**
  * Returns the basic parameters for the "findText" command we'll use.
  * Overrides FindsCommand's in order to drop the noEmphasis option -
  * we need emphasisLength for the match mark.
  */
 String basicFindTextParms()
 {
  return "quiet noBeep noWrap ";
 }

 /**
  * Notification from #doFinds() of a successful find.
  * Overrides FindsCommand's in order to set a match mark.
  */
 void found(LpexView lpexView, LpexDocumentLocation loc)
 {
  lpexView.doCommand("set mark. " + loc.element + ' ' + loc.position + ' ' +
                     loc.element + ' ' + (loc.position + _foundTextLength -1));
  String markId = lpexView.query("markId.");
  lpexView.doCommand("set markHighlight.#" + markId + " on");
  lpexView.doCommand("set markStyle.#" + markId + ' ' + _matchStyleChar);
  _marks.add(markId);
 }
}