001/*
002 * $RCSfile: MsgPrinter.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:26 $
005 * $State: Exp $
006 *
007 * Class:                   MsgPrinter
008 *
009 * Description:             Prints messages formatted for a specific
010 *                          line width.
011 *
012 *
013 *
014 * COPYRIGHT:
015 *
016 * This software module was originally developed by Raphaël Grosbois and
017 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
018 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
019 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
020 * Centre France S.A) in the course of development of the JPEG2000
021 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
022 * software module is an implementation of a part of the JPEG 2000
023 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
024 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
025 * Partners) agree not to assert against ISO/IEC and users of the JPEG
026 * 2000 Standard (Users) any of their rights under the copyright, not
027 * including other intellectual property rights, for this software module
028 * with respect to the usage by ISO/IEC and Users of this software module
029 * or modifications thereof for use in hardware or software products
030 * claiming conformance to the JPEG 2000 Standard. Those intending to use
031 * this software module in hardware or software products are advised that
032 * their use may infringe existing patents. The original developers of
033 * this software module, JJ2000 Partners and ISO/IEC assume no liability
034 * for use of this software module or modifications thereof. No license
035 * or right to this software module is granted for non JPEG 2000 Standard
036 * conforming products. JJ2000 Partners have full right to use this
037 * software module for his/her own purpose, assign or donate this
038 * software module to any third party and to inhibit third parties from
039 * using this software module for non JPEG 2000 Standard conforming
040 * products. This copyright notice must be included in all copies or
041 * derivative works of this software module.
042 *
043 * Copyright (c) 1999/2000 JJ2000 Partners.
044 *
045 *
046 *
047 */
048
049
050package jj2000.j2k.util;
051
052import java.io.*;
053
054/**
055 * This utility class formats messages to the specified line width, by
056 * inserting line-breaks between words, and printing the resulting
057 * lines.
058 * */
059public class MsgPrinter {
060
061    /** The line width to use */
062    public int lw;
063
064    /** Signals that a newline was found */
065    private static final int IS_NEWLINE = -2;
066
067    /** Signals that the end-of-string was reached */
068    private static final int IS_EOS = -1;
069
070    /**
071     * Creates a new message printer with the specified line width and
072     * with the default locale.
073     *
074     * @param linewidth The line width for which to format (in
075     * characters)
076     *
077     *
078     * */
079    public MsgPrinter(int linewidth) {
080        lw = linewidth;
081    }
082
083    /**
084     * Returns the line width that is used for formatting.
085     *
086     * @return The line width used for formatting
087     *
088     *
089     * */
090    public int getLineWidth() {
091        return lw;
092    }
093
094    /**
095     * Sets the line width to the specified value. This new value will
096     * be used in subsequent calls to the print() message.
097     *
098     * @param linewidth The new line width to use (in cahracters)
099     *
100     *
101     * */
102    public void setLineWidth(int linewidth) {
103        if (linewidth <1) {
104            throw new IllegalArgumentException();
105        }
106        lw = linewidth;
107    }
108
109    /**
110     * Formats the message to print in the current line width, by
111     * breaking the message into lines between words. The number of
112     * spaces to indent the first line is specified by 'flind' and the
113     * number of spaces to indent each of the following lines is
114     * specified by 'ind'. Newlines in 'msg' are respected. A newline is
115     * always printed at the end.
116     *
117     * @param out Where to print the message.
118     *
119     * @param flind The indentation for the first line.
120     *
121     * @param ind The indentation for the other lines.
122     *
123     * @param msg The message to format and print.
124     *
125     *
126     * */
127    public void print(PrintWriter out, int flind, int ind,
128                      String msg) {
129        int start,end,pend,efflw,lind,i;
130
131        start = 0;
132        end = 0;
133        pend = 0;
134        efflw = lw-flind;
135        lind = flind;
136        while ((end = nextLineEnd(msg,pend)) != IS_EOS) {
137            if (end == IS_NEWLINE) { // Forced line break
138                for (i=0; i<lind; i++) {
139                    out.print(" ");
140                }
141                out.println(msg.substring(start,pend));
142                if (nextWord(msg,pend) == msg.length()) {
143                    // Traling newline => print it and done
144                    out.println("");
145                    start = pend;
146                    break;
147                }
148            }
149            else {
150                if (efflw > end-pend) { // Room left on current line
151                    efflw -= end-pend;
152                    pend = end;
153                    continue;
154                }
155                else { // Filled-up current line => print it
156                    for (i=0; i<lind; i++) {
157                        out.print(" ");
158                    }
159                    if (start == pend) { // Word larger than line width
160                        // Print anyways
161                        out.println(msg.substring(start,end));
162                        pend = end;
163                    }
164                    else {
165                        out.println(msg.substring(start,pend));
166                    }
167                }
168            }
169            // Initialize for next line
170            lind = ind;
171            efflw = lw-ind;
172            start = nextWord(msg,pend);
173            pend = start;
174            if (start == IS_EOS) {
175                break; // Did all the string
176            }
177        }
178        if (pend != start) { // Part of a line left => print it
179            for (i=0; i<lind; i++) {
180                out.print(" ");
181            }
182            out.println(msg.substring(start,pend));
183        }
184
185    }
186
187    /**
188     * Returns the index of the last character of the next word, plus 1, or
189     * IS_NEWLINE if a newline character is encountered before the next word,
190     * or IS_EOS if the end of the string is ecnounterd before the next
191     * word. The method first skips all whitespace characters at or after
192     * 'from', except newlines. If a newline is found IS_NEWLINE is
193     * returned. Then it skips all non-whitespace characters and returns the
194     * position of the last non-whitespace character, plus 1. The returned
195     * index may be greater than the last valid index in the tsring, but it is
196     * always suitable to be used in the String.substring() method.
197     *
198     * <P>Non-whitespace characters are defined as in the
199     * Character.isWhitespace method (that method is used).
200     *
201     * @param str The string to parse
202     *
203     * @param from The index of the first position to search from
204     *
205     * @return The index of the last character in the next word, plus 1,
206     * IS_NEWLINE, or IS_EOS if there are no more words.
207     *
208     *
209     * */
210    private int nextLineEnd(String str, int from) {
211        final int len = str.length();
212        char c = '\0';
213        // First skip all whitespace, except new line
214        while (from < len && (c = str.charAt(from)) != '\n' &&
215               Character.isWhitespace(c)) {
216            from++;
217        }
218        if (c == '\n') {
219            return IS_NEWLINE;
220        }
221        if (from >= len) {
222            return IS_EOS;
223        }
224        // Now skip word characters
225        while (from < len && !Character.isWhitespace(str.charAt(from))) {
226            from++;
227        }
228        return from;
229    }
230
231    /**
232     * Returns the position of the first character in the next word, starting
233     * from 'from', if a newline is encountered first then the index of the
234     * newline character plus 1 is returned. If the end of the string is
235     * encountered then IS_EOS is returned. Words are defined as any
236     * concatenation of 1 or more characters which are not
237     * whitespace. Whitespace characters are those for which
238     * Character.isWhitespace() returns true (that method is used).
239     *
240     * <P>Non-whitespace characters are defined as in the
241     * Character.isWhitespace method (that method is used).
242     *
243     * @param str The string to parse
244     *
245     * @param from The index where to start parsing
246     *
247     * @return The index of the first character of the next word, or the index
248     * of the newline plus 1, or IS_EOS.
249     *
250     *
251     * */
252    private int nextWord(String str, int from) {
253        final int len = str.length();
254        char c = '\0';
255        // First skip all whitespace, but new lines
256        while (from < len && (c = str.charAt(from)) != '\n' &&
257               Character.isWhitespace(c)) {
258            from++;
259        }
260        if (from >= len) {
261            return IS_EOS;
262        }
263        else if (c == '\n') {
264            return from+1;
265        }
266        else {
267            return from;
268        }
269    }
270}