001package org.apache.maven.doxia.util;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.codehaus.plexus.util.IOUtil;
023
024import java.io.BufferedWriter;
025import java.io.IOException;
026import java.io.Writer;
027
028/**
029 * Allows to specify the line-length of an output writer.
030 *
031 * @version $Id$
032 */
033public class LineBreaker
034{
035    /** The default maximal line length. */
036    public static final int DEFAULT_MAX_LINE_LENGTH = 78;
037
038    /** The system dependent EOL. */
039    private static final String EOL = System.getProperty( "line.separator" );
040
041    /** The destination writer. */
042    private Writer destination;
043
044    /** The writer to use. */
045    private BufferedWriter writer;
046
047    /** The maximal line length. */
048    private int maxLineLength;
049
050    /** The current line length. */
051    private int lineLength = 0;
052
053    /** The string buffer to store the current text. */
054    private StringBuilder word = new StringBuilder( 1024 );
055
056    /**
057     * Constructs a new LineBreaker with DEFAULT_MAX_LINE_LENGTH.
058     *
059     * @param out The writer to use.
060     */
061    public LineBreaker( Writer out )
062    {
063        this( out, DEFAULT_MAX_LINE_LENGTH );
064    }
065
066    /**
067     * Constructs a new LineBreaker with the given max line length.
068     *
069     * @param out The writer to use.
070     * @param max The maximal line length.
071     */
072    public LineBreaker( Writer out, int max )
073    {
074        if ( max <= 0 )
075        {
076            throw new IllegalArgumentException( "maxLineLength <= 0" );
077        }
078
079        destination = out;
080        this.maxLineLength = max;
081        writer = new BufferedWriter( out );
082    }
083
084    /**
085     * Returns the current destination writer.
086     *
087     * @return The destination.
088     */
089    public Writer getDestination()
090    {
091        return destination;
092    }
093
094    /**
095     * Writes the given text to the writer. White space is not preserved.
096     *
097     * @param text The text to write.
098     * @throws java.io.IOException if there's a problem writing the text.
099     */
100    public void write( String text )
101        throws IOException
102    {
103        write( text, /*preserveSpace*/false );
104    }
105
106    /**
107     * Writes the given text to the writer.
108     *
109     * @param text The text to write.
110     * @param preserveSpace True to preserve white space.
111     */
112    public void write( String text, boolean preserveSpace )
113    {
114        int length = text.length();
115
116        try
117        {
118            for ( int i = 0; i < length; ++i )
119            {
120                char c = text.charAt( i );
121
122                switch ( c )
123                {
124                    case ' ':
125                        if ( preserveSpace )
126                        {
127                            word.append( c );
128                        }
129                        else
130                        {
131                            writeWord();
132                        }
133                        break;
134
135                    case '\r':
136                        // if \r\n (windows) then just pass along \n
137                        if ( i + 1 < length && text.charAt( i + 1 ) == '\n' )
138                        {
139                            break;
140                        }
141
142                    case '\n':
143                        writeWord();
144                        writer.write( EOL );
145                        lineLength = 0;
146                        break;
147
148                    default:
149                        word.append( c );
150                }
151
152            }
153        }
154        catch ( Exception e )
155        {
156            // TODO: log
157        }
158    }
159
160    /**
161     * Write out the current StringBuilder and flush the writer.
162     * Any IOException will be swallowed.
163     */
164    public void flush()
165    {
166        try
167        {
168            writeWord();
169            writer.flush();
170        }
171        catch ( IOException e )
172        {
173            // TODO: log
174        }
175    }
176
177    /**
178     * Writes the current StringBuilder to the writer.
179     *
180     * @throws IOException if an exception occurs during writing.
181     */
182    private void writeWord()
183        throws IOException
184    {
185        int length = word.length();
186        if ( length > 0 )
187        {
188            if ( lineLength > 0 )
189            {
190                if ( lineLength + 1 + length > maxLineLength )
191                {
192                    writer.write( EOL );
193                    lineLength = 0;
194                }
195                else
196                {
197                    writer.write( ' ' );
198                    ++lineLength;
199                }
200            }
201
202            writer.write( word.toString() );
203            word.setLength( 0 );
204
205            lineLength += length;
206        }
207    }
208
209    /**
210     * Close the writer.
211     */
212    public void close()
213    {
214        IOUtil.close( writer );
215    }
216}