/**
   * Tries to determine script type (of all four types).
   *
   * <p>Has <b>OK</b> status if <code>LATIN</code> type returned for ACSII character, <code>ASIAN
   * </code> for Katakana Unicode codepoints, <code>COMPLEX</code> for Arabic Unicode codepoints and
   * <code>WEAK</code> for codepoints from Arrows Unicode block.
   */
  public void _getScriptType() {
    boolean res = true;

    res &= oObj.getScriptType("abcd", 0) == ScriptType.LATIN;
    res &= oObj.getScriptType(katakana, 0) == ScriptType.ASIAN;
    res &= oObj.getScriptType(arabic, 0) == ScriptType.COMPLEX;
    res &= oObj.getScriptType(arrows, 0) == ScriptType.WEAK;

    tRes.tested("getScriptType()", res);
  }
  /**
   * Compares returned previous character positions with expected values.
   *
   * <p>Has <b>OK</b> status if position after travel and traveled length has expected values.
   */
  public void _previousCharacters() {
    short nCharacterIteratorMode = com.sun.star.i18n.CharacterIteratorMode.SKIPCHARACTER;

    // Start from position : Travel ... chars : Actual position after :
    // How many chars traveled
    int[][] previousCharacters = {
      {5, 5000, 0, 5},
      {10, 6, 4, 6}
    };

    boolean bRes = true;
    for (int i = 0; i < previousCharacters.length; i++) {
      int[] lDone = new int[1];
      int lRes =
          oObj.previousCharacters(
              UnicodeString,
              previousCharacters[i][0],
              locale,
              nCharacterIteratorMode,
              previousCharacters[i][1],
              lDone);
      log.println(
          "Expected result is: lRes = "
              + previousCharacters[i][2]
              + "; lDone = "
              + previousCharacters[i][3]);
      log.println("Actual result is: lRes = " + lRes + "; lDone = " + lDone[0]);

      bRes = bRes && lRes == previousCharacters[i][2];
      bRes = bRes && lDone[0] == previousCharacters[i][3];
    }

    tRes.tested("previousCharacters()", bRes);
  }
  /**
   * For every word in array obtained by <code>nextWord</code> method test computes bounds of the
   * word, passing its internal character position.
   *
   * <p>Has <b>OK</b> status if bounds calculated by <code>getWordBoundary()</code> method are the
   * same as bounds obtained by <code>nextWord</code> method.
   */
  public void _getWordBoundary() {
    requiredMethod("nextWord()");

    boolean bRes = true;

    for (int i = 0; i < vBounds.size(); i++) {
      // calculate middle of the word
      Boundary iBounds = vBounds.get(i);
      int iPos = (iBounds.endPos - iBounds.startPos) / 2 + iBounds.startPos;
      Boundary bounds = oObj.getWordBoundary(UnicodeString, iPos, locale, wordType, true);
      log.println(
          "Expected result is: startPos = " + iBounds.startPos + "; endPos = " + iBounds.endPos);
      log.println(
          "Actual result is: startPos = "
              + bounds.startPos
              + "; endPos = "
              + bounds.endPos
              + " Word is: '"
              + UnicodeString.substring(bounds.startPos, bounds.endPos)
              + "'");

      bRes = bRes && iBounds.startPos == bounds.startPos;
      bRes = bRes && iBounds.endPos == bounds.endPos;
    }

    tRes.tested("getWordBoundary()", bRes);
  }
  /**
   * Compares number of word bounds with number of word bounds saved by the method _nextWord().
   *
   * <p>Has <b>OK</b> status if number of word bounds are equal.
   */
  public void _previousWord() {
    requiredMethod("nextWord()");

    int i = UnicodeString.length() - 1;
    ArrayList<Boundary> vPrevBounds = new ArrayList<Boundary>();
    while (i > 0) {
      Boundary bounds = oObj.previousWord(UnicodeString, i, locale, wordType);
      if (bounds.endPos - bounds.startPos > 3) {
        vPrevBounds.add(bounds);
        log.println(
            "Word "
                + vPrevBounds.size()
                + "("
                + bounds.startPos
                + ","
                + bounds.endPos
                + "): '"
                + UnicodeString.substring(bounds.startPos, bounds.endPos)
                + "'");
      }
      i = bounds.startPos;
    }
    log.println("In text there are " + vPrevBounds.size() + " words, if count from right to left");
    tRes.tested("previousWord()", vPrevBounds.size() == vBounds.size());
  }
  /**
   * Tries to break a string in position other than 0 iterating characters from the string beginning
   * (Hyphenation is not used for a while).
   *
   * <p>Has <b>OK</b> status if non-zero break position was found and it is less or equal than
   * position we trying to break.
   */
  public void _getLineBreak() {
    boolean bRes = true;
    LineBreakResults lineBreakResults;
    LineBreakHyphenationOptions lineBreakHyphenationOptions = new LineBreakHyphenationOptions();
    LineBreakUserOptions lineBreakUserOptions = new LineBreakUserOptions();

    lineBreakUserOptions.applyForbiddenRules = false;
    lineBreakUserOptions.allowHyphenateEnglish = false;

    int breakPos = 0;
    int pos = 0;

    while (breakPos == 0 && pos < UnicodeString.length()) {
      lineBreakResults =
          oObj.getLineBreak(
              UnicodeString, pos, locale, 0, lineBreakHyphenationOptions, lineBreakUserOptions);
      breakPos = lineBreakResults.breakIndex;
      pos++;
    }

    // finally the position of break must be found in the middle and
    // it must be before the break position specified
    bRes = breakPos <= pos && breakPos > 0;

    if (!bRes) {
      log.println("The last position was: " + pos + ", and the break position was: " + breakPos);
    }

    tRes.tested("getLineBreak()", bRes);
  }
  /**
   * Tries to find the previous script starting position specified relatively to position passed.
   *
   * <p>Has <b>OK</b> status if the appropriate position is returned.
   */
  public void _previousScript() {
    String multiScript = "ab" + katakana + "cd";

    int pos = oObj.previousScript(multiScript, 5, ScriptType.ASIAN);

    log.println("Position = " + pos);

    tRes.tested("previousScript()", pos == 2);
  }
  /**
   * Tries to find the next script starting position specified relatively to position passed.
   *
   * <p>Has <b>OK</b> status if the appropriate position is returned.
   */
  public void _nextScript() {
    String multiScript = "ab" + katakana + "cd";

    int pos = oObj.nextScript(multiScript, 0, ScriptType.LATIN);

    log.println("Position = " + pos);

    tRes.tested("nextScript()", pos == 4);
  }
  /**
   * Tries to find the end of the nearest script specified relatively to position passed.
   *
   * <p>Has <b>OK</b> status if the end position of script is returned.
   */
  public void _endOfScript() {
    String multiScript = "ab" + katakana + "cd";

    int pos = oObj.endOfScript(multiScript, 2, ScriptType.ASIAN);

    log.println("Position = " + pos);

    tRes.tested("endOfScript()", pos == 4);
  }
  /**
   * Tries to find the beginning of the nearest script specified relatively to position passed.
   *
   * <p>Has <b>OK</b> status if the starting position of script is returned.
   */
  public void _beginOfScript() {
    String multiScript = "ab" + katakana;

    int pos = oObj.beginOfScript(multiScript, 3, ScriptType.ASIAN);

    log.println("Position = " + pos);

    tRes.tested("beginOfScript()", pos == 2);
  }
  /**
   * For every sentence starting position found in <code>beginOfSentence()</code> test tries to
   * compute end position of a sentence and checks that the end position is greater than starting.
   * Then wrong position arguments are passed.
   *
   * <p>Has <b>OK</b> status if the end position of every sentence greater than starting and -1
   * returned for invalid arguments.
   */
  public void _endOfSentence() {
    boolean bRes = true;
    for (int i = 0; i < vSentenceStart.size(); i++) {
      int start = vSentenceStart.get(i).intValue();
      int end = oObj.endOfSentence(UnicodeString, start, locale);
      bRes &= end > start;
      log.println("Sentence " + i + " range is [" + start + ", " + end + "]");
    }

    // test for invalid nStartPosition
    boolean bInvRes = oObj.endOfSentence(UnicodeString, -10, locale) == -1;
    bInvRes &= oObj.endOfSentence(UnicodeString, UnicodeString.length() + 1, locale) == -1;

    if (!bInvRes) {
      log.println("When invalid position, returned value isn't equal to -1");
    }

    tRes.tested("endOfSentence()", bRes && bInvRes);
  }
  /**
   * For every word in array obtained by <code>nextWord</code> method test tries to determine if the
   * character at a position ends a word. First word ending position is passed, then internal
   * character position is passed.
   *
   * <p>Has <b>OK</b> status if in the first case <code>true</code> returned and in the second -
   * <code>false</code> for every word.
   */
  public void _isEndWord() {
    requiredMethod("nextWord()");

    boolean bRes = true;

    for (int i = 0; i < vBounds.size(); i++) {
      Boundary iBounds = vBounds.get(i);
      boolean isEnd = oObj.isEndWord(UnicodeString, iBounds.endPos, locale, WordType.ANY_WORD);
      bRes = bRes && isEnd;
      boolean isNotEnd =
          !oObj.isEndWord(UnicodeString, iBounds.endPos - 1, locale, WordType.ANY_WORD);
      bRes = bRes && isNotEnd;

      log.println("At position + " + iBounds.endPos + " isEndWord? " + isEnd);
      log.println("At position + " + (iBounds.endPos - 1) + " isEndWord? " + !isNotEnd);
    }

    tRes.tested("isEndWord()", bRes);
  }
  /**
   * Tries to find all sentences starting positions passing every character as position parameter
   * and stores them. Then tries to pass invalid position parameters.
   *
   * <p>Has <b>OK</b> status if -1 is returned for wrong position arguments.
   */
  public void _beginOfSentence() {
    int iPos = 0;
    while (iPos < UnicodeString.length()) {
      Integer start = new Integer(oObj.beginOfSentence(UnicodeString, iPos, locale));
      if (start.intValue() >= 0 && !vSentenceStart.contains(start)) {
        vSentenceStart.add(start);
        log.println("Sentence " + vSentenceStart.size() + " : start from position " + start);
      }
      iPos++;
    }

    // test for invalid nStartPosition
    boolean bRes = oObj.beginOfSentence(UnicodeString, -10, locale) == -1;
    bRes &= oObj.beginOfSentence(UnicodeString, UnicodeString.length() + 1, locale) == -1;

    if (!bRes) {
      log.println("When invalid position, returned value isn't equal to -1");
    }

    tRes.tested("beginOfSentence()", bRes);
  }
  protected short getCharBlockType(int pos) {
    short i = 1;
    short cType = 0;
    while (i < 31) {
      if (oObj.beginOfCharBlock(UnicodeString, pos, locale, i) != -1) {
        cType = i;
        i = 100;
      }
      i++;
    }

    return cType;
  }
  /**
   * Creates array of all char blocks with their boundaries and types using <code>beginOfCharBlock()
   * </code> and <code>endOfCharBlock()</code> methods.
   *
   * <p>Has <b>OK</b> status if the end of each boundary is the same as start of the next one and if
   * the start of the first block has position 0 and the end of the last block is at the end of the
   * whole string.
   */
  public void _beginOfCharBlock() {
    int iPos = 0;

    while (iPos < UnicodeString.length() && iPos > -1) {
      short charType = getCharBlockType(iPos);
      int startPos = oObj.beginOfCharBlock(UnicodeString, iPos, locale, charType);
      int endPos = oObj.endOfCharBlock(UnicodeString, iPos, locale, charType);
      iPos = endPos;
      vCharBlockBounds.add(new Boundary(startPos, endPos));
      log.println(
          ""
              + vCharBlockBounds.size()
              + "). Bounds: ["
              + startPos
              + ","
              + endPos
              + "]; Type = "
              + charType);
      vCharBlockTypes.add(new Short(charType));
    }

    for (int i = 0; i < vCharBlockBounds.size() - 1; i++) {
      int endPos = vCharBlockBounds.get(i).endPos;
      int startPos = vCharBlockBounds.get(i + 1).startPos;
      bCharBlockRes &= endPos == startPos;
    }

    log.println("Testing for no intersections : " + bCharBlockRes);
    int startPos = vCharBlockBounds.get(0).startPos;
    bCharBlockRes &= startPos == 0;
    int endPos = vCharBlockBounds.get(vCharBlockBounds.size() - 1).endPos;
    bCharBlockRes &= endPos == UnicodeString.length();
    log.println("Regions should starts with 0 and ends with " + UnicodeString.length());

    tRes.tested("beginOfCharBlock()", bCharBlockRes);
  }
  /**
   * For every word in array obtained by <code>nextWord</code> method test get its type, passing its
   * internal character position.
   *
   * <p>Has <b>OK</b> status if every word has type <code>WordType.ANY_WORD</code>
   */
  public void _getWordType() {
    requiredMethod("nextWord()");

    boolean bRes = true;

    for (int i = 0; i < vBounds.size(); i++) {
      // calculate middle of the word
      Boundary iBounds = vBounds.get(i);
      int iPos = (iBounds.endPos - iBounds.startPos) / 2 + iBounds.startPos;

      short type = oObj.getWordType(UnicodeString, iPos, locale);

      bRes = bRes && type == WordType.ANY_WORD;
    }

    tRes.tested("getWordType()", bRes);
  }
  /**
   * Saves bounds of all returned words for the future tests.
   *
   * <p>Has <b>OK</b> status.
   */
  public void _nextWord() {
    int i = 0;

    while (i < UnicodeString.length() - 1) {
      Boundary bounds = oObj.nextWord(UnicodeString, i, locale, wordType);
      if (bounds.endPos - bounds.startPos > 3) {
        vBounds.add(bounds);
        log.println(
            "Word "
                + vBounds.size()
                + "("
                + bounds.startPos
                + ","
                + bounds.endPos
                + "): '"
                + UnicodeString.substring(bounds.startPos, bounds.endPos)
                + "'");
      }
      i = bounds.endPos - 1;
    }
    log.println("In text there are " + vBounds.size() + " words, if count from left to right");
    tRes.tested("nextWord()", true);
  }
  /**
   * Compares returned next character positions with expected values.
   *
   * <p>Has <b>OK</b> status if position after travel and traveled length has expected values.
   */
  public void _nextCharacters() {
    short nCharacterIteratorMode = com.sun.star.i18n.CharacterIteratorMode.SKIPCHARACTER;

    int strLength = UnicodeString.length();

    // Start from position : Travel ... chars :
    // Actual position after : How many chars traveled
    int[][] nextCharacters = {
      {1, 5000, strLength, strLength - 1},
      {10, 6, 16, 6}
    };

    boolean bRes = true;

    for (int i = 0; i < nextCharacters.length; i++) {
      int[] lDone = new int[1];
      long lRes =
          oObj.nextCharacters(
              UnicodeString,
              nextCharacters[i][0],
              locale,
              nCharacterIteratorMode,
              nextCharacters[i][1],
              lDone);
      log.println(
          "Expected result is: lRes = "
              + nextCharacters[i][2]
              + "; lDone = "
              + nextCharacters[i][3]);
      log.println("Actual result is: lRes = " + lRes + "; lDone = " + lDone[0]);

      bRes = bRes && lRes == nextCharacters[i][2];
      bRes = bRes && lDone[0] == nextCharacters[i][3];
    }

    tRes.tested("nextCharacters()", bRes);
  }
  /**
   * For every character block obtained in <code>beginOfCharBlock()</code> method test (except the
   * first) tries to find its starting position by mean of <code>previousCharBlock()</code> method
   * passing as position argument the position after the end of a block.
   *
   * <p>Has <b>OK</b> status if the start of every block was found and it's equal to this block
   * boundary start.
   */
  public void _previousCharBlock() {
    requiredMethod("beginOfCharBlock()");

    boolean bRes = true;
    for (int i = 0; i < vCharBlockBounds.size(); i++) {
      Boundary bounds = vCharBlockBounds.get(i);
      Short type = vCharBlockTypes.get(i);
      int iPos =
          oObj.previousCharBlock(UnicodeString, bounds.endPos + 1, locale, type.shortValue());
      if (iPos != bounds.startPos) {
        bRes = false;
        log.println(
            "previousCharBlock(UnicodeString, "
                + (bounds.endPos + 1)
                + ", locale, "
                + type
                + ") should return "
                + bounds.startPos);
        log.println("... and actual value is " + iPos);
      }
    }

    tRes.tested("previousCharBlock()", bRes);
  }