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 */
031public class LineBreaker
032{
033    /** The default maximal line length. */
034    public static final int DEFAULT_MAX_LINE_LENGTH = 78;
035
036    /** The system dependent EOL. */
037    private static final String EOL = System.getProperty( "line.separator" );
038
039    /** The destination writer. */
040    private Writer destination;
041
042    /** The writer to use. */
043    private BufferedWriter writer;
044
045    /** The maximal line length. */
046    private int maxLineLength;
047
048    /** The current line length. */
049    private int lineLength = 0;
050
051    /** The string buffer to store the current text. */
052    private StringBuilder word = new StringBuilder( 1024 );
053
054    /**
055     * Constructs a new LineBreaker with DEFAULT_MAX_LINE_LENGTH.
056     *
057     * @param out The writer to use.
058     */
059    public LineBreaker( Writer out )
060    {
061        this( out, DEFAULT_MAX_LINE_LENGTH );
062    }
063
064    /**
065     * Constructs a new LineBreaker with the given max line length.
066     *
067     * @param out The writer to use.
068     * @param max The maximal line length.
069     */
070    public LineBreaker( Writer out, int max )
071    {
072        if ( max <= 0 )
073        {
074            throw new IllegalArgumentException( "maxLineLength <= 0" );
075        }
076
077        destination = out;
078        this.maxLineLength = max;
079        writer = new BufferedWriter( out );
080    }
081
082    /**
083     * Returns the current destination writer.
084     *
085     * @return The destination.
086     */
087    public Writer getDestination()
088    {
089        return destination;
090    }
091
092    /**
093     * Writes the given text to the writer. White space is not preserved.
094     *
095     * @param text The text to write.
096     * @throws java.io.IOException if there's a problem writing the text.
097     */
098    public void write( String text )
099        throws IOException
100    {
101        write( text, /*preserveSpace*/false );
102    }
103
104    /**
105     * Writes the given text to the writer.
106     *
107     * @param text The text to write.
108     * @param preserveSpace True to preserve white space.
109     */
110    public void write( String text, boolean preserveSpace )
111    {
112        int length = text.length();
113
114        try
115        {
116            for ( int i = 0; i < length; ++i )
117            {
118                char c = text.charAt( i );
119
120                switch ( c )
121                {
122                    case ' ':
123                        if ( preserveSpace )
124                        {
125                            word.append( c );
126                        }
127                        else
128                        {
129                            writeWord();
130                        }
131                        break;
132
133                    case '\r':
134                        // if \r\n (windows) then just pass along \n
135                        if ( i + 1 < length && text.charAt( i + 1 ) == '\n' )
136                        {
137                            break;
138                        }
139
140                    case '\n':
141                        writeWord();
142                        writer.write( EOL );
143                        lineLength = 0;
144                        break;
145
146                    default:
147                        word.append( c );
148                }
149
150            }
151        }
152        catch ( Exception e )
153        {
154            // TODO: log
155        }
156    }
157
158    /**
159     * Write out the current StringBuilder and flush the writer.
160     * Any IOException will be swallowed.
161     */
162    public void flush()
163    {
164        try
165        {
166            writeWord();
167            writer.flush();
168        }
169        catch ( IOException e )
170        {
171            // TODO: log
172        }
173    }
174
175    /**
176     * Writes the current StringBuilder to the writer.
177     *
178     * @throws IOException if an exception occurs during writing.
179     */
180    private void writeWord()
181        throws IOException
182    {
183        int length = word.length();
184        if ( length > 0 )
185        {
186            if ( lineLength > 0 )
187            {
188                if ( lineLength + 1 + length > maxLineLength )
189                {
190                    writer.write( EOL );
191                    lineLength = 0;
192                }
193                else
194                {
195                    writer.write( ' ' );
196                    ++lineLength;
197                }
198            }
199
200            writer.write( word.toString() );
201            word.setLength( 0 );
202
203            lineLength += length;
204        }
205    }
206
207    /**
208     * Close the writer.
209     */
210    public void close()
211    {
212        IOUtil.close( writer );
213    }
214}