/**
   * Wraps lines at and below the caret that exceed the number of characters per line.
   *
   * <p>Lines are wrapped at spaces between words when possible. Lines that don't exceed the number
   * of characters per line are not changed.
   *
   * <p>Currently this cannot be undone.
   */
  public void rewrapFromCaret() {
    StringBuilder stringBuilder = new StringBuilder(charsPerLine * 3);

    for (int i = content.getLineAtOffset(currentText.getCaretOffset());
        i < content.getLineCount();
        i++) {
      String line = content.getLine(i);
      if (line.length() == 0) continue;

      //   line too long
      if (line.length() > charsPerLine) {
        int wordWrap, wordEnd;

        //   find beginning of word being wrapped
        if (line.charAt(charsPerLine) != ' ') {
          for (wordWrap = charsPerLine; wordWrap > charsPerLine / 2; wordWrap--)
            if (line.charAt(wordWrap) == ' ') break;
          if (wordWrap == charsPerLine / 2) continue;
          wordWrap++;
        } else {
          for (wordWrap = charsPerLine; wordWrap < line.length(); wordWrap++)
            if (line.charAt(wordWrap) != ' ') break;
          if (wordWrap == line.length()) continue;
        }

        //   find end of word before word being wrapped
        for (wordEnd = wordWrap - 1; wordEnd > charsPerLine / 4; wordEnd--)
          if (line.charAt(wordEnd) != ' ') break;
        if (wordEnd == charsPerLine / 4) continue;
        wordEnd++;

        //   build replacement text
        int length = line.length();
        stringBuilder.setLength(0);
        stringBuilder
            .append(line.substring(0, wordEnd))
            .append(eol)
            .append(line.substring(wordWrap, length));
        if (length > 0 && line.charAt(length - 1) != PARAGRAPH_END)
          if (i < content.getLineCount() - 1) {
            String next = content.getLine(i + 1);
            stringBuilder.append(' ').append(next);
            length += eol.length() + next.length();
          }

        content.replaceTextRange(content.getOffsetAtLine(i), length, stringBuilder.toString());
      } else if (line.length() > 0 && line.charAt(line.length() - 1) == PARAGRAPH_END) break;
    }

    clearChanges();
  }
  /**
   * Reads data in BrailleZephyr file format from <code>Reader</code>.
   *
   * @param reader the reader stream from which to read the data.
   * @exception IOException
   * @see #writeBZY(Writer)
   */
  public void readBZY(Reader reader) throws IOException, BZException {
    String line;
    boolean returnAtEnd = false;
    int caretOffset = 0;
    int unknown = 0;

    content.setText("");
    eol = System.getProperty("line.separator");
    BufferedReader buffer = new BufferedReader(reader);

    //   read configuration lines
    header:
    while ((line = buffer.readLine()) != null) {
      String tokens[] = line.split(" ");
      switch (tokens[0]) {

          //   don't do anything for now
        case "Version":
          break;

        case "CharsPerLine":
          charsPerLine = Integer.parseInt(tokens[1]);
          break;
        case "LinesPerPage":
          linesPerPage = Integer.parseInt(tokens[1]);
          break;

        case "CaretOffset":
          caretOffset = Integer.parseInt(tokens[1]);
          break;
        case "ViewFocus":
          if (tokens[1].equals("braille")) {
            if (brailleText.isVisible()) brailleText.setFocus();
          } else if (tokens[1].equals("ascii")) {
            if (asciiText.isVisible()) asciiText.setFocus();
          } else logWriter.println("ERROR:  Invalid ViewFocus value:  " + line);
          break;

        case "ReturnAtEnd":
          returnAtEnd = Boolean.parseBoolean(tokens[1]);
          break;

        case "HeaderEnd":
          break header;

        default:
          logWriter.println("WARNING:  Unknown file format parameter:  " + line);
          unknown++;
          if (unknown > 6) throw new BZException("Invalid file format");
          break;
      }
    }
    if (line == null) throw new BZException("Invalid file format");

    //   read first line, may be null for empty document
    if ((line = buffer.readLine()) != null) {
      if (line.length() > 0 && line.charAt(line.length() - 1) == 0xb6)
        content.replaceTextRange(0, 0, line.substring(0, line.length() - 1) + PARAGRAPH_END);
      else content.replaceTextRange(0, 0, line);

      //   read next lines
      while ((line = buffer.readLine()) != null) {
        content.replaceTextRange(content.getCharCount(), 0, eol);
        if (line.length() > 0 && line.charAt(line.length() - 1) == 0xb6)
          content.replaceTextRange(
              content.getCharCount(), 0, line.substring(0, line.length() - 1) + PARAGRAPH_END);
        else content.replaceTextRange(content.getCharCount(), 0, line);
      }
    }

    if (returnAtEnd) content.replaceTextRange(content.getCharCount(), 0, eol);

    clearChanges();
    brailleText.setCaretOffset(caretOffset);
    asciiText.setCaretOffset(caretOffset);
  }