/*
 * Copyright 2006 Ralf Joachim
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.exolab.javasource;

/**
 * A class to format comments. 
 * 
 * @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
 * @version $Revision: 6668 $ $Date: 2005-05-08 12:32:06 -0600 (Sun, 08 May 2005) $
 * @since 1.1
 */
public final class JCommentFormatter {
    //--------------------------------------------------------------------------

    private String _comment = null;
    private int _maxLength = JComment.MAX_LENGTH;
    private int _offset = 0;
    private int _length = 0;
    private String _prefix = null;
    private StringBuffer _sb = null;

    //--------------------------------------------------------------------------

    /**
     * Creates a new LineFormatter for the given comment.
     *
     * @param comment The String to format.
     * @param maxLength The maximum number of characters per line.
     * @param prefix A prefix to append to the beginning of each line.
     */
    public JCommentFormatter(final String comment, final int maxLength, final String prefix) {
        _comment = comment;
        if (comment != null) { _length = comment.length(); }
        _sb = new StringBuffer();
        _maxLength = maxLength;
        _prefix = prefix;
    }

    //--------------------------------------------------------------------------

    public boolean hasMoreLines() {
        if (_comment == null) { return false; }
        return (_offset < _length);
    }

    public String nextLine() {
        if (_comment == null) { return null; }
        if (_offset >= _length) { return null; }

        _sb.setLength(0);
        if (_prefix != null) { _sb.append(_prefix); }

        int max = _offset + _maxLength;
        if (max > this._length) { max = this._length; }

        int index = _offset;
        int breakable = _offset;
        for ( ; index < max; index++) {
            char ch = _comment.charAt(index);
            if (isNewLine(ch)) {
                _sb.append(_comment.substring(_offset, index));
                _offset = index + 1;
                return _sb.toString();
            }
            if (isWhitespace(ch)) { breakable = index; }
        }

        if (index < _length - 1) {
            //-- if we could not find a breakable character, we must look
            //-- ahead
            if (_offset == breakable) {
                while (index < _length) {
                    if (isBreakable(_comment.charAt(index))) { break; }
                    ++index;
                }
            } else {
                index = breakable;
            }
        }
        _sb.append(_comment.substring(_offset, index));
        _offset = index + 1;
        return _sb.toString();
    }

    /**
     * Returns true if we can break a line at this character.
     *
     * @param ch Character to examine.
     * @return True if we can break a line at this character.
     */
    private boolean isBreakable(final char ch) {
        return (isWhitespace(ch) || isNewLine(ch));
    }

    /**
     * Returns true if this character is whitespace.
     *
     * @param ch Character to examine.
     * @return True if this character is whitespace.
     */
    private boolean isWhitespace(final char ch) {
        return ((ch == ' ') || (ch == '\t'));
    }

    /**
     * Returns true if this character is a new line character.
     *
     * @param ch Character to examine.
     * @return True if this character is a new line character.
     */
    private boolean isNewLine(final char ch) {
        return ((ch == '\n') || (ch == '\r'));
    }

    //--------------------------------------------------------------------------
}
