in progress
[jalview.git] / forester / java / src / org / forester / util / ForesterUtil.java
1 // $Id:
2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
4 //
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
7 // All rights reserved
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 //
23 // Contact: phylosoft @ gmail . com
24 // WWW: www.phylosoft.org/forester
25
26 package org.forester.util;
27
28 import java.awt.Color;
29 import java.io.BufferedReader;
30 import java.io.BufferedWriter;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.FileNotFoundException;
34 import java.io.FileOutputStream;
35 import java.io.FileReader;
36 import java.io.FileWriter;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.InputStreamReader;
40 import java.io.StringReader;
41 import java.io.Writer;
42 import java.math.BigDecimal;
43 import java.net.URL;
44 import java.text.DateFormat;
45 import java.text.DecimalFormat;
46 import java.text.DecimalFormatSymbols;
47 import java.text.NumberFormat;
48 import java.text.ParseException;
49 import java.text.SimpleDateFormat;
50 import java.util.ArrayList;
51 import java.util.Collection;
52 import java.util.Date;
53 import java.util.Iterator;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.Map.Entry;
57 import java.util.Set;
58 import java.util.SortedMap;
59 import java.util.SortedSet;
60 import java.util.TreeMap;
61 import java.util.TreeSet;
62 import java.util.regex.Pattern;
63
64 public final class ForesterUtil {
65
66     public final static String       FILE_SEPARATOR                   = System.getProperty( "file.separator" );
67     public final static String       LINE_SEPARATOR                   = System.getProperty( "line.separator" );
68     public final static String       JAVA_VENDOR                      = System.getProperty( "java.vendor" );
69     public final static String       JAVA_VERSION                     = System.getProperty( "java.version" );
70     public final static String       OS_ARCH                          = System.getProperty( "os.arch" );
71     public final static String       OS_NAME                          = System.getProperty( "os.name" );
72     public final static String       OS_VERSION                       = System.getProperty( "os.version" );
73     public final static Pattern      PARANTHESESABLE_NH_CHARS_PATTERN = Pattern.compile( "[(),;\\s]" );
74     public final static double       ZERO_DIFF                        = 1.0E-9;
75     public static final BigDecimal   NULL_BD                          = new BigDecimal( 0 );
76     public static final NumberFormat FORMATTER_9;
77     public static final NumberFormat FORMATTER_6;
78     public static final NumberFormat FORMATTER_06;
79     public static final NumberFormat FORMATTER_3;
80     static {
81         final DecimalFormatSymbols dfs = new DecimalFormatSymbols();
82         dfs.setDecimalSeparator( '.' );
83         // dfs.setGroupingSeparator( ( char ) 0 );
84         FORMATTER_9 = new DecimalFormat( "#.#########", dfs );
85         FORMATTER_6 = new DecimalFormat( "#.######", dfs );
86         FORMATTER_06 = new DecimalFormat( "0.######", dfs );
87         FORMATTER_3 = new DecimalFormat( "#.###", dfs );
88     }
89
90     private ForesterUtil() {
91     }
92
93     final public static void appendSeparatorIfNotEmpty( final StringBuffer sb, final char separator ) {
94         if ( sb.length() > 0 ) {
95             sb.append( separator );
96         }
97     }
98
99     public static boolean seqIsLikelyToBeAa( final String s ) {
100         final String seq = s.toLowerCase();
101         if ( ( seq.indexOf( 'r' ) > -1 ) || ( seq.indexOf( 'd' ) > -1 ) || ( seq.indexOf( 'e' ) > -1 )
102                 || ( seq.indexOf( 'q' ) > -1 ) || ( seq.indexOf( 'h' ) > -1 ) || ( seq.indexOf( 'k' ) > -1 )
103                 || ( seq.indexOf( 'w' ) > -1 ) || ( seq.indexOf( 's' ) > -1 ) || ( seq.indexOf( 'm' ) > -1 )
104                 || ( seq.indexOf( 'p' ) > -1 ) || ( seq.indexOf( 'v' ) > -1 ) ) {
105             return true;
106         }
107         return false;
108     }
109
110     /**
111      * This calculates a color. If value is equal to min the returned color is
112      * minColor, if value is equal to max the returned color is maxColor,
113      * otherwise a color 'proportional' to value is returned.
114      * 
115      * @param value
116      *            the value 
117      * @param min
118      *            the smallest value 
119      * @param max
120      *            the largest value 
121      * @param minColor
122      *            the color for min
123      * @param maxColor
124      *            the color for max
125      * @return a Color
126      */
127     final public static Color calcColor( double value,
128                                          final double min,
129                                          final double max,
130                                          final Color minColor,
131                                          final Color maxColor ) {
132         if ( value < min ) {
133             value = min;
134         }
135         if ( value > max ) {
136             value = max;
137         }
138         final double x = ForesterUtil.calculateColorFactor( value, max, min );
139         final int red = ForesterUtil.calculateColorComponent( minColor.getRed(), maxColor.getRed(), x );
140         final int green = ForesterUtil.calculateColorComponent( minColor.getGreen(), maxColor.getGreen(), x );
141         final int blue = ForesterUtil.calculateColorComponent( minColor.getBlue(), maxColor.getBlue(), x );
142         return new Color( red, green, blue );
143     }
144
145     /**
146      * This calculates a color. If value is equal to min the returned color is
147      * minColor, if value is equal to max the returned color is maxColor, if
148      * value is equal to mean the returned color is meanColor, otherwise a color
149      * 'proportional' to value is returned -- either between min-mean or
150      * mean-max
151      * 
152      * @param value
153      *            the value
154      * @param min
155      *            the smallest value
156      * @param max
157      *            the largest value 
158      * @param mean
159      *            the mean/median value 
160      * @param minColor
161      *            the color for min
162      * @param maxColor
163      *            the color for max
164      * @param meanColor
165      *            the color for mean
166      * @return a Color
167      */
168     final public static Color calcColor( double value,
169                                          final double min,
170                                          final double max,
171                                          final double mean,
172                                          final Color minColor,
173                                          final Color maxColor,
174                                          final Color meanColor ) {
175         if ( value < min ) {
176             value = min;
177         }
178         if ( value > max ) {
179             value = max;
180         }
181         if ( value < mean ) {
182             final double x = ForesterUtil.calculateColorFactor( value, mean, min );
183             final int red = ForesterUtil.calculateColorComponent( minColor.getRed(), meanColor.getRed(), x );
184             final int green = ForesterUtil.calculateColorComponent( minColor.getGreen(), meanColor.getGreen(), x );
185             final int blue = ForesterUtil.calculateColorComponent( minColor.getBlue(), meanColor.getBlue(), x );
186             return new Color( red, green, blue );
187         }
188         else if ( value > mean ) {
189             final double x = ForesterUtil.calculateColorFactor( value, max, mean );
190             final int red = ForesterUtil.calculateColorComponent( meanColor.getRed(), maxColor.getRed(), x );
191             final int green = ForesterUtil.calculateColorComponent( meanColor.getGreen(), maxColor.getGreen(), x );
192             final int blue = ForesterUtil.calculateColorComponent( meanColor.getBlue(), maxColor.getBlue(), x );
193             return new Color( red, green, blue );
194         }
195         else {
196             return meanColor;
197         }
198     }
199
200     /**
201      * Helper method for calcColor methods.
202      * 
203      * @param smallercolor_component_x
204      *            color component the smaller color
205      * @param largercolor_component_x
206      *            color component the larger color
207      * @param x
208      *            factor
209      * @return an int representing a color component
210      */
211     final private static int calculateColorComponent( final double smallercolor_component_x,
212                                                       final double largercolor_component_x,
213                                                       final double x ) {
214         return ( int ) ( smallercolor_component_x + ( ( x * ( largercolor_component_x - smallercolor_component_x ) ) / 255.0 ) );
215     }
216
217     /**
218      * Helper method for calcColor methods.
219      * 
220      * 
221      * @param value
222      *            the value
223      * @param larger
224      *            the largest value
225      * @param smaller
226      *            the smallest value
227      * @return a normalized value between larger and smaller
228      */
229     final private static double calculateColorFactor( final double value, final double larger, final double smaller ) {
230         return ( 255.0 * ( value - smaller ) ) / ( larger - smaller );
231     }
232
233     final public static String collapseWhiteSpace( final String s ) {
234         return s.replaceAll( "[\\s]+", " " );
235     }
236
237     final public static void collection2file( final File file, final Collection<?> data, final String separator )
238             throws IOException {
239         final Writer writer = new BufferedWriter( new FileWriter( file ) );
240         collection2writer( writer, data, separator );
241         writer.close();
242     }
243
244     final public static void collection2writer( final Writer writer, final Collection<?> data, final String separator )
245             throws IOException {
246         boolean first = true;
247         for( final Object object : data ) {
248             if ( !first ) {
249                 writer.write( separator );
250             }
251             else {
252                 first = false;
253             }
254             writer.write( object.toString() );
255         }
256     }
257
258     final public static String colorToHex( final Color color ) {
259         final String rgb = Integer.toHexString( color.getRGB() );
260         return rgb.substring( 2, rgb.length() );
261     }
262
263     synchronized public static void copyFile( final File in, final File out ) throws IOException {
264         final FileInputStream in_s = new FileInputStream( in );
265         final FileOutputStream out_s = new FileOutputStream( out );
266         try {
267             final byte[] buf = new byte[ 1024 ];
268             int i = 0;
269             while ( ( i = in_s.read( buf ) ) != -1 ) {
270                 out_s.write( buf, 0, i );
271             }
272         }
273         catch ( final IOException e ) {
274             throw e;
275         }
276         finally {
277             if ( in_s != null ) {
278                 in_s.close();
279             }
280             if ( out_s != null ) {
281                 out_s.close();
282             }
283         }
284     }
285
286     final public static int countChars( final String str, final char c ) {
287         int count = 0;
288         for( int i = 0; i < str.length(); ++i ) {
289             if ( str.charAt( i ) == c ) {
290                 ++count;
291             }
292         }
293         return count;
294     }
295
296     final public static BufferedWriter createBufferedWriter( final File file ) throws IOException {
297         if ( file.exists() ) {
298             throw new IOException( "[" + file + "] already exists" );
299         }
300         return new BufferedWriter( new FileWriter( file ) );
301     }
302
303     final public static BufferedWriter createBufferedWriter( final String name ) throws IOException {
304         return new BufferedWriter( new FileWriter( createFileForWriting( name ) ) );
305     }
306
307     final public static File createFileForWriting( final String name ) throws IOException {
308         final File file = new File( name );
309         if ( file.exists() ) {
310             throw new IOException( "[" + name + "] already exists" );
311         }
312         return file;
313     }
314
315     public static void fatalError( final String prg_name, final String message ) {
316         System.err.println();
317         System.err.println( "[" + prg_name + "] > " + message );
318         System.err.println();
319         System.exit( -1 );
320     }
321
322     public static String[] file2array( final File file ) throws IOException {
323         final List<String> list = file2list( file );
324         final String[] ary = new String[ list.size() ];
325         int i = 0;
326         for( final String s : list ) {
327             ary[ i++ ] = s;
328         }
329         return ary;
330     }
331
332     final public static List<String> file2list( final File file ) throws IOException {
333         final List<String> list = new ArrayList<String>();
334         final BufferedReader in = new BufferedReader( new FileReader( file ) );
335         String str;
336         while ( ( str = in.readLine() ) != null ) {
337             str = str.trim();
338             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
339                 for( final String s : splitString( str ) ) {
340                     list.add( s );
341                 }
342             }
343         }
344         in.close();
345         return list;
346     }
347
348     final public static SortedSet<String> file2set( final File file ) throws IOException {
349         final SortedSet<String> set = new TreeSet<String>();
350         final BufferedReader in = new BufferedReader( new FileReader( file ) );
351         String str;
352         while ( ( str = in.readLine() ) != null ) {
353             str = str.trim();
354             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
355                 for( final String s : splitString( str ) ) {
356                     set.add( s );
357                 }
358             }
359         }
360         in.close();
361         return set;
362     }
363
364     final public static String getCurrentDateTime() {
365         final DateFormat format = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" );
366         return format.format( new Date() );
367     }
368
369     final public static String getFileSeparator() {
370         return ForesterUtil.FILE_SEPARATOR;
371     }
372
373     final public static String getFirstLine( final Object source ) throws FileNotFoundException, IOException {
374         BufferedReader reader = null;
375         if ( source instanceof File ) {
376             final File f = ( File ) source;
377             if ( !f.exists() ) {
378                 throw new IOException( "[" + f.getAbsolutePath() + "] does not exist" );
379             }
380             else if ( !f.isFile() ) {
381                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a file" );
382             }
383             else if ( !f.canRead() ) {
384                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a readable" );
385             }
386             reader = new BufferedReader( new FileReader( f ) );
387         }
388         else if ( source instanceof InputStream ) {
389             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
390         }
391         else if ( source instanceof String ) {
392             reader = new BufferedReader( new StringReader( ( String ) source ) );
393         }
394         else if ( source instanceof StringBuffer ) {
395             reader = new BufferedReader( new StringReader( source.toString() ) );
396         }
397         else if ( source instanceof URL ) {
398             reader = new BufferedReader( new InputStreamReader( ( ( URL ) source ).openStream() ) );
399         }
400         else {
401             throw new IllegalArgumentException( "dont know how to read [" + source.getClass() + "]" );
402         }
403         String line;
404         while ( ( line = reader.readLine() ) != null ) {
405             line = line.trim();
406             if ( !ForesterUtil.isEmpty( line ) ) {
407                 if ( reader != null ) {
408                     reader.close();
409                 }
410                 return line;
411             }
412         }
413         if ( reader != null ) {
414             reader.close();
415         }
416         return line;
417     }
418
419     final public static String getLineSeparator() {
420         return ForesterUtil.LINE_SEPARATOR;
421     }
422
423     final public static void increaseCountingMap( final Map<String, Integer> counting_map, final String item_name ) {
424         if ( !counting_map.containsKey( item_name ) ) {
425             counting_map.put( item_name, 1 );
426         }
427         else {
428             counting_map.put( item_name, counting_map.get( item_name ) + 1 );
429         }
430     }
431
432     final public static boolean isContainsParanthesesableNhCharacter( final String nh ) {
433         return PARANTHESESABLE_NH_CHARS_PATTERN.matcher( nh ).find();
434     }
435
436     final public static boolean isEmpty( final List<?> l ) {
437         if ( ( l == null ) || l.isEmpty() ) {
438             return true;
439         }
440         for( final Object o : l ) {
441             if ( o != null ) {
442                 return false;
443             }
444         }
445         return true;
446     }
447
448     final public static boolean isEmpty( final Set<?> s ) {
449         if ( ( s == null ) || s.isEmpty() ) {
450             return true;
451         }
452         for( final Object o : s ) {
453             if ( o != null ) {
454                 return false;
455             }
456         }
457         return true;
458     }
459
460     final public static boolean isEmpty( final String s ) {
461         return ( ( s == null ) || ( s.length() < 1 ) );
462     }
463
464     final public static boolean isEqual( final double a, final double b ) {
465         return ( ( Math.abs( a - b ) ) < ZERO_DIFF );
466     }
467
468     final public static boolean isEven( final int n ) {
469         return n % 2 == 0;
470     }
471
472     /**
473      * This determines whether String[] a and String[] b have at least one
474      * String in common (intersect). Returns false if at least one String[] is
475      * null or empty.
476      * 
477      * @param a
478      *            a String[] b a String[]
479      * @return true if both a and b or not empty or null and contain at least
480      *         one element in common false otherwise
481      */
482     final public static boolean isIntersecting( final String[] a, final String[] b ) {
483         if ( ( a == null ) || ( b == null ) ) {
484             return false;
485         }
486         if ( ( a.length < 1 ) || ( b.length < 1 ) ) {
487             return false;
488         }
489         for( int i = 0; i < a.length; ++i ) {
490             final String ai = a[ i ];
491             for( int j = 0; j < b.length; ++j ) {
492                 if ( ( ai != null ) && ( b[ j ] != null ) && ai.equals( b[ j ] ) ) {
493                     return true;
494                 }
495             }
496         }
497         return false;
498     }
499
500     final public static double isLargerOrEqualToZero( final double d ) {
501         if ( d > 0.0 ) {
502             return d;
503         }
504         else {
505             return 0.0;
506         }
507     }
508
509     final public static boolean isNull( final BigDecimal s ) {
510         return ( ( s == null ) || ( s.compareTo( NULL_BD ) == 0 ) );
511     }
512
513     final public static String isReadableFile( final File f ) {
514         if ( !f.exists() ) {
515             return "file [" + f + "] does not exist";
516         }
517         if ( f.isDirectory() ) {
518             return "[" + f + "] is a directory";
519         }
520         if ( !f.isFile() ) {
521             return "[" + f + "] is not a file";
522         }
523         if ( !f.canRead() ) {
524             return "file [" + f + "] is not readable";
525         }
526         if ( f.length() < 1 ) {
527             return "file [" + f + "] is empty";
528         }
529         return null;
530     }
531
532     final public static String isReadableFile( final String s ) {
533         return isReadableFile( new File( s ) );
534     }
535
536     final public static String isWritableFile( final File f ) {
537         if ( f.isDirectory() ) {
538             return "[" + f + "] is a directory";
539         }
540         if ( f.exists() ) {
541             return "[" + f + "] already exists";
542         }
543         return null;
544     }
545
546     /**
547      * Helper for method "stringToColor".
548      * <p>
549      * (Last modified: 12/20/03)
550      */
551     final public static int limitRangeForColor( int i ) {
552         if ( i > 255 ) {
553             i = 255;
554         }
555         else if ( i < 0 ) {
556             i = 0;
557         }
558         return i;
559     }
560
561     final public static SortedMap<Object, Integer> listToSortedCountsMap( final List list ) {
562         final SortedMap<Object, Integer> map = new TreeMap<Object, Integer>();
563         for( final Object key : list ) {
564             if ( !map.containsKey( key ) ) {
565                 map.put( key, 1 );
566             }
567             else {
568                 map.put( key, map.get( key ) + 1 );
569             }
570         }
571         return map;
572     }
573
574     final public static void map2file( final File file,
575                                        final Map<?, ?> data,
576                                        final String entry_separator,
577                                        final String data_separator ) throws IOException {
578         final Writer writer = new BufferedWriter( new FileWriter( file ) );
579         map2writer( writer, data, entry_separator, data_separator );
580         writer.close();
581     }
582
583     final public static void map2writer( final Writer writer,
584                                          final Map<?, ?> data,
585                                          final String entry_separator,
586                                          final String data_separator ) throws IOException {
587         boolean first = true;
588         for( final Entry<?, ?> entry : data.entrySet() ) {
589             if ( !first ) {
590                 writer.write( data_separator );
591             }
592             else {
593                 first = false;
594             }
595             writer.write( entry.getKey().toString() );
596             writer.write( entry_separator );
597             writer.write( entry.getValue().toString() );
598         }
599     }
600
601     final public static StringBuffer mapToStringBuffer( final Map map, final String key_value_separator ) {
602         final StringBuffer sb = new StringBuffer();
603         for( final Iterator iter = map.keySet().iterator(); iter.hasNext(); ) {
604             final Object key = iter.next();
605             sb.append( key.toString() );
606             sb.append( key_value_separator );
607             sb.append( map.get( key ).toString() );
608             sb.append( ForesterUtil.getLineSeparator() );
609         }
610         return sb;
611     }
612
613     final public static String normalizeString( final String s,
614                                                 final int length,
615                                                 final boolean left_pad,
616                                                 final char pad_char ) {
617         if ( s.length() > length ) {
618             return s.substring( 0, length );
619         }
620         else {
621             final StringBuffer pad = new StringBuffer( length - s.length() );
622             for( int i = 0; i < ( length - s.length() ); ++i ) {
623                 pad.append( pad_char );
624             }
625             if ( left_pad ) {
626                 return pad + s;
627             }
628             else {
629                 return s + pad;
630             }
631         }
632     }
633
634     final public static BufferedReader obtainReader( final Object source ) throws IOException, FileNotFoundException {
635         BufferedReader reader = null;
636         if ( source instanceof File ) {
637             final File f = ( File ) source;
638             if ( !f.exists() ) {
639                 throw new IOException( "\"" + f.getAbsolutePath() + "\" does not exist" );
640             }
641             else if ( !f.isFile() ) {
642                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a file" );
643             }
644             else if ( !f.canRead() ) {
645                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a readable" );
646             }
647             reader = new BufferedReader( new FileReader( f ) );
648         }
649         else if ( source instanceof InputStream ) {
650             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
651         }
652         else if ( source instanceof String ) {
653             reader = new BufferedReader( new StringReader( ( String ) source ) );
654         }
655         else if ( source instanceof StringBuffer ) {
656             reader = new BufferedReader( new StringReader( source.toString() ) );
657         }
658         else {
659             throw new IllegalArgumentException( "attempt to parse object of type [" + source.getClass()
660                     + "] (can only parse objects of type File, InputStream, String, or StringBuffer)" );
661         }
662         return reader;
663     }
664
665     final public static StringBuffer pad( final double number, final int size, final char pad, final boolean left_pad ) {
666         return pad( new StringBuffer( number + "" ), size, pad, left_pad );
667     }
668
669     final public static StringBuffer pad( final String string, final int size, final char pad, final boolean left_pad ) {
670         return pad( new StringBuffer( string ), size, pad, left_pad );
671     }
672
673     final public static StringBuffer pad( final StringBuffer string,
674                                           final int size,
675                                           final char pad,
676                                           final boolean left_pad ) {
677         final StringBuffer padding = new StringBuffer();
678         final int s = size - string.length();
679         if ( s < 1 ) {
680             return new StringBuffer( string.substring( 0, size ) );
681         }
682         for( int i = 0; i < s; ++i ) {
683             padding.append( pad );
684         }
685         if ( left_pad ) {
686             return padding.append( string );
687         }
688         else {
689             return string.append( padding );
690         }
691     }
692
693     final public static double parseDouble( final String str ) throws ParseException {
694         if ( ForesterUtil.isEmpty( str ) ) {
695             return 0.0;
696         }
697         return Double.parseDouble( str );
698     }
699
700     final public static int parseInt( final String str ) throws ParseException {
701         if ( ForesterUtil.isEmpty( str ) ) {
702             return 0;
703         }
704         return Integer.parseInt( str );
705     }
706
707     final public static void printArray( final Object[] a ) {
708         for( int i = 0; i < a.length; ++i ) {
709             System.out.println( "[" + i + "]=" + a[ i ] );
710         }
711     }
712
713     final public static void printCountingMap( final Map<String, Integer> counting_map ) {
714         for( final String key : counting_map.keySet() ) {
715             System.out.println( key + ": " + counting_map.get( key ) );
716         }
717     }
718
719     final public static void printErrorMessage( final String prg_name, final String message ) {
720         System.out.println( "[" + prg_name + "] > error: " + message );
721     }
722
723     final public static void printProgramInformation( final String prg_name, final String prg_version, final String date ) {
724         final int l = prg_name.length() + prg_version.length() + date.length() + 4;
725         System.out.println();
726         System.out.println( prg_name + " " + prg_version + " (" + date + ")" );
727         for( int i = 0; i < l; ++i ) {
728             System.out.print( "_" );
729         }
730         System.out.println();
731     }
732
733     final public static void printProgramInformation( final String prg_name,
734                                                       final String prg_version,
735                                                       final String date,
736                                                       final String email,
737                                                       final String www ) {
738         final int l = prg_name.length() + prg_version.length() + date.length() + 4;
739         System.out.println();
740         System.out.println( prg_name + " " + prg_version + " (" + date + ")" );
741         for( int i = 0; i < l; ++i ) {
742             System.out.print( "_" );
743         }
744         System.out.println();
745         System.out.println();
746         System.out.println( "WWW    : " + www );
747         System.out.println( "Contact: " + email );
748         if ( !ForesterUtil.isEmpty( ForesterUtil.JAVA_VERSION ) && !ForesterUtil.isEmpty( ForesterUtil.JAVA_VENDOR ) ) {
749             System.out.println();
750             System.out.println( "[running on Java " + ForesterUtil.JAVA_VERSION + " " + ForesterUtil.JAVA_VENDOR + "]" );
751         }
752         System.out.println();
753     }
754
755     final public static void printWarningMessage( final String prg_name, final String message ) {
756         System.out.println( "[" + prg_name + "] > warning: " + message );
757     }
758
759     final public static void programMessage( final String prg_name, final String message ) {
760         System.out.println( "[" + prg_name + "] > " + message );
761     }
762
763     final public static String removeSuffix( final String file_name ) {
764         final int i = file_name.lastIndexOf( '.' );
765         if ( i > 1 ) {
766             return file_name.substring( 0, i );
767         }
768         return file_name;
769     }
770
771     /**
772      * Removes all white space from String s.
773      * 
774      * @return String s with white space removed
775      */
776     final public static String removeWhiteSpace( String s ) {
777         int i;
778         for( i = 0; i <= s.length() - 1; i++ ) {
779             if ( ( s.charAt( i ) == ' ' ) || ( s.charAt( i ) == '\t' ) || ( s.charAt( i ) == '\n' )
780                     || ( s.charAt( i ) == '\r' ) ) {
781                 s = s.substring( 0, i ) + s.substring( i + 1 );
782                 i--;
783             }
784         }
785         return s;
786     }
787
788     final public static String replaceIllegalNhCharacters( final String nh ) {
789         if ( nh == null ) {
790             return "";
791         }
792         return nh.trim().replaceAll( "[\\[\\]:]+", "_" );
793     }
794
795     final public static String replaceIllegalNhxCharacters( final String nhx ) {
796         if ( nhx == null ) {
797             return "";
798         }
799         return nhx.trim().replaceAll( "[\\[\\](),:;\\s]+", "_" );
800     }
801
802     final public static double round( final double value, final int decimal_place ) {
803         BigDecimal bd = new BigDecimal( value );
804         bd = bd.setScale( decimal_place, BigDecimal.ROUND_HALF_UP );
805         return bd.doubleValue();
806     }
807
808     /**
809      * Rounds d to an int.
810      */
811     final public static int roundToInt( final double d ) {
812         return ( int ) ( d + 0.5 );
813     }
814
815     final public static int roundToInt( final float f ) {
816         return ( int ) ( f + 0.5f );
817     }
818
819     final public static short roundToShort( final double d ) {
820         return ( short ) ( d + 0.5 );
821     }
822
823     final public static String sanitizeString( final String s ) {
824         if ( s == null ) {
825             return "";
826         }
827         else {
828             return s.trim();
829         }
830     }
831
832     final private static String[] splitString( final String str ) {
833         final String regex = "[\\s;,]+";
834         return str.split( regex );
835     }
836
837     final public static String stringArrayToString( final String[] a ) {
838         return stringArrayToString( a, ", " );
839     }
840
841     final public static String stringArrayToString( final String[] a, final String separator ) {
842         final StringBuilder sb = new StringBuilder();
843         if ( ( a != null ) && ( a.length > 0 ) ) {
844             for( int i = 0; i < a.length - 1; ++i ) {
845                 sb.append( a[ i ] + separator );
846             }
847             sb.append( a[ a.length - 1 ] );
848         }
849         return sb.toString();
850     }
851
852     final public static String[] stringListToArray( final List<String> list ) {
853         if ( list != null ) {
854             final String[] str = new String[ list.size() ];
855             int i = 0;
856             for( final String l : list ) {
857                 str[ i++ ] = l;
858             }
859             return str;
860         }
861         return null;
862     }
863
864     final public static String stringListToString( final List<String> l, final String separator ) {
865         final StringBuilder sb = new StringBuilder();
866         if ( ( l != null ) && ( l.size() > 0 ) ) {
867             for( int i = 0; i < l.size() - 1; ++i ) {
868                 sb.append( l.get( i ) + separator );
869             }
870             sb.append( l.get( l.size() - 1 ) );
871         }
872         return sb.toString();
873     }
874
875     final public static String[] stringSetToArray( final Set<String> strings ) {
876         final String[] str_array = new String[ strings.size() ];
877         int i = 0;
878         for( final String e : strings ) {
879             str_array[ i++ ] = e;
880         }
881         return str_array;
882     }
883
884     final public static void unexpectedFatalError( final String prg_name, final Exception e ) {
885         System.err.println();
886         System.err.println( "[" + prg_name
887                 + "] > unexpected error (Should not have occured! Please contact program author(s).)" );
888         e.printStackTrace( System.err );
889         System.err.println();
890         System.exit( -1 );
891     }
892
893     final public static void unexpectedFatalError( final String prg_name, final String message ) {
894         System.err.println();
895         System.err.println( "[" + prg_name
896                 + "] > unexpected error. Should not have occured! Please contact program author(s)." );
897         System.err.println( message );
898         System.err.println();
899         System.exit( -1 );
900     }
901
902     final public static void unexpectedFatalError( final String prg_name, final String message, final Exception e ) {
903         System.err.println();
904         System.err.println( "[" + prg_name
905                 + "] > unexpected error. Should not have occured! Please contact program author(s)." );
906         System.err.println( message );
907         e.printStackTrace( System.err );
908         System.err.println();
909         System.exit( -1 );
910     }
911
912     public final static String wordWrap( final String str, final int width ) {
913         final StringBuilder sb = new StringBuilder( str );
914         int start = 0;
915         int ls = -1;
916         int i = 0;
917         while ( i < sb.length() ) {
918             if ( sb.charAt( i ) == ' ' ) {
919                 ls = i;
920             }
921             if ( sb.charAt( i ) == '\n' ) {
922                 ls = -1;
923                 start = i + 1;
924             }
925             if ( i > start + width - 1 ) {
926                 if ( ls != -1 ) {
927                     sb.setCharAt( ls, '\n' );
928                     start = ls + 1;
929                     ls = -1;
930                 }
931                 else {
932                     sb.insert( i, '\n' );
933                     start = i + 1;
934                 }
935             }
936             i++;
937         }
938         return sb.toString();
939     }
940 }