inprogress
[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: https://sites.google.com/site/cmzmasek/home/software/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.Matcher;
63 import java.util.regex.Pattern;
64
65 import org.forester.archaeopteryx.Constants;
66 import org.forester.phylogeny.PhylogenyNode;
67 import org.forester.phylogeny.data.Distribution;
68 import org.forester.phylogeny.data.Sequence;
69 import org.forester.phylogeny.data.Taxonomy;
70
71 public final class ForesterUtil {
72
73     public final static String       FILE_SEPARATOR                   = System.getProperty( "file.separator" );
74     public final static String       LINE_SEPARATOR                   = System.getProperty( "line.separator" );
75     public final static String       JAVA_VENDOR                      = System.getProperty( "java.vendor" );
76     public final static String       JAVA_VERSION                     = System.getProperty( "java.version" );
77     public final static String       OS_ARCH                          = System.getProperty( "os.arch" );
78     public final static String       OS_NAME                          = System.getProperty( "os.name" );
79     public final static String       OS_VERSION                       = System.getProperty( "os.version" );
80     public final static Pattern      PARANTHESESABLE_NH_CHARS_PATTERN = Pattern.compile( "[(),;\\s]" );
81     public final static double       ZERO_DIFF                        = 1.0E-9;
82     public static final BigDecimal   NULL_BD                          = new BigDecimal( 0 );
83     public static final NumberFormat FORMATTER_9;
84     public static final NumberFormat FORMATTER_6;
85     public static final NumberFormat FORMATTER_06;
86     public static final NumberFormat FORMATTER_3;
87     public static final String       NCBI_PROTEIN                     = "http://www.ncbi.nlm.nih.gov/protein/";
88     public static final String       NCBI_NUCCORE                     = "http://www.ncbi.nlm.nih.gov/nuccore/";
89     public final static String       UNIPROT_KB                       = "http://www.uniprot.org/uniprot/";
90     public static final String       NCBI_GI                          = "http://www.ncbi.nlm.nih.gov/protein/gi:";
91     static {
92         final DecimalFormatSymbols dfs = new DecimalFormatSymbols();
93         dfs.setDecimalSeparator( '.' );
94         // dfs.setGroupingSeparator( ( char ) 0 );
95         FORMATTER_9 = new DecimalFormat( "#.#########", dfs );
96         FORMATTER_6 = new DecimalFormat( "#.######", dfs );
97         FORMATTER_06 = new DecimalFormat( "0.######", dfs );
98         FORMATTER_3 = new DecimalFormat( "#.###", dfs );
99     }
100
101     private ForesterUtil() {
102     }
103
104     final public static void appendSeparatorIfNotEmpty( final StringBuffer sb, final char separator ) {
105         if ( sb.length() > 0 ) {
106             sb.append( separator );
107         }
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     final public static String collapseWhiteSpace( final String s ) {
201         return s.replaceAll( "[\\s]+", " " );
202     }
203
204     final public static void collection2file( final File file, final Collection<?> data, final String separator )
205             throws IOException {
206         final Writer writer = new BufferedWriter( new FileWriter( file ) );
207         collection2writer( writer, data, separator );
208         writer.close();
209     }
210
211     final public static void collection2writer( final Writer writer, final Collection<?> data, final String separator )
212             throws IOException {
213         boolean first = true;
214         for( final Object object : data ) {
215             if ( !first ) {
216                 writer.write( separator );
217             }
218             else {
219                 first = false;
220             }
221             writer.write( object.toString() );
222         }
223     }
224
225     final public static String colorToHex( final Color color ) {
226         final String rgb = Integer.toHexString( color.getRGB() );
227         return rgb.substring( 2, rgb.length() );
228     }
229
230     synchronized public static void copyFile( final File in, final File out ) throws IOException {
231         final FileInputStream in_s = new FileInputStream( in );
232         final FileOutputStream out_s = new FileOutputStream( out );
233         try {
234             final byte[] buf = new byte[ 1024 ];
235             int i = 0;
236             while ( ( i = in_s.read( buf ) ) != -1 ) {
237                 out_s.write( buf, 0, i );
238             }
239         }
240         catch ( final IOException e ) {
241             throw e;
242         }
243         finally {
244             if ( in_s != null ) {
245                 in_s.close();
246             }
247             if ( out_s != null ) {
248                 out_s.close();
249             }
250         }
251     }
252
253     final public static int countChars( final String str, final char c ) {
254         int count = 0;
255         for( int i = 0; i < str.length(); ++i ) {
256             if ( str.charAt( i ) == c ) {
257                 ++count;
258             }
259         }
260         return count;
261     }
262
263     final public static BufferedWriter createBufferedWriter( final File file ) throws IOException {
264         if ( file.exists() ) {
265             throw new IOException( "[" + file + "] already exists" );
266         }
267         return new BufferedWriter( new FileWriter( file ) );
268     }
269
270     final public static BufferedWriter createBufferedWriter( final String name ) throws IOException {
271         return new BufferedWriter( new FileWriter( createFileForWriting( name ) ) );
272     }
273
274     final public static EasyWriter createEasyWriter( final File file ) throws IOException {
275         return new EasyWriter( createBufferedWriter( file ) );
276     }
277
278     final public static BufferedWriter createEasyWriter( final String name ) throws IOException {
279         return createEasyWriter( createFileForWriting( name ) );
280     }
281
282     final public static File createFileForWriting( final String name ) throws IOException {
283         final File file = new File( name );
284         if ( file.exists() ) {
285             throw new IOException( "[" + name + "] already exists" );
286         }
287         return file;
288     }
289
290     final public static void ensurePresenceOfDate( final PhylogenyNode node ) {
291         if ( !node.getNodeData().isHasDate() ) {
292             node.getNodeData().setDate( new org.forester.phylogeny.data.Date() );
293         }
294     }
295
296     final public static void ensurePresenceOfDistribution( final PhylogenyNode node ) {
297         if ( !node.getNodeData().isHasDistribution() ) {
298             node.getNodeData().setDistribution( new Distribution( "" ) );
299         }
300     }
301
302     public static void ensurePresenceOfSequence( final PhylogenyNode node ) {
303         if ( !node.getNodeData().isHasSequence() ) {
304             node.getNodeData().setSequence( new Sequence() );
305         }
306     }
307
308     public static void ensurePresenceOfTaxonomy( final PhylogenyNode node ) {
309         if ( !node.getNodeData().isHasTaxonomy() ) {
310             node.getNodeData().setTaxonomy( new Taxonomy() );
311         }
312     }
313
314     public static void fatalError( final String message ) {
315         System.err.println();
316         System.err.println( "error: " + message );
317         System.err.println();
318         System.exit( -1 );
319     }
320
321     public static void fatalError( final String prg_name, final String message ) {
322         System.err.println();
323         System.err.println( "[" + prg_name + "] > " + message );
324         System.err.println();
325         System.exit( -1 );
326     }
327
328     public static void fatalErrorIfFileNotReadable( final File file ) {
329         final String error = isReadableFile( file );
330         if ( !isEmpty( error ) ) {
331             System.err.println();
332             System.err.println( "error: " + error );
333             System.err.println();
334             System.exit( -1 );
335         }
336     }
337
338     public static void fatalErrorIfFileNotReadable( final String prg_name, final File file ) {
339         final String error = isReadableFile( file );
340         if ( !isEmpty( error ) ) {
341             System.err.println();
342             System.err.println( "[" + prg_name + "] > " + error );
343             System.err.println();
344             System.exit( -1 );
345         }
346     }
347
348     public static String[] file2array( final File file ) throws IOException {
349         final List<String> list = file2list( file );
350         final String[] ary = new String[ list.size() ];
351         int i = 0;
352         for( final String s : list ) {
353             ary[ i++ ] = s;
354         }
355         return ary;
356     }
357
358     public static String[][] file22dArray( final File file ) throws IOException {
359         final List<String> list = new ArrayList<String>();
360         final BufferedReader in = new BufferedReader( new FileReader( file ) );
361         String str;
362         while ( ( str = in.readLine() ) != null ) {
363             str = str.trim();
364             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
365                 list.add( str );
366             }
367         }
368         in.close();
369         final String[][] ary = new String[ list.size() ][ 2 ];
370         final Pattern pa = Pattern.compile( "(\\S+)\\s+(\\S+)" );
371         int i = 0;
372         for( final String s : list ) {
373             final Matcher m = pa.matcher( s );
374             if ( m.matches() ) {
375                 ary[ i ][ 0 ] = m.group( 1 );
376                 ary[ i ][ 1 ] = m.group( 2 );
377                 ++i;
378             }
379             else {
380                 throw new IOException( "unexpcted format: " + s );
381             }
382         }
383         return ary;
384     }
385
386     final public static List<String> file2list( final File file ) throws IOException {
387         final List<String> list = new ArrayList<String>();
388         final BufferedReader in = new BufferedReader( new FileReader( file ) );
389         String str;
390         while ( ( str = in.readLine() ) != null ) {
391             str = str.trim();
392             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
393                 for( final String s : splitString( str ) ) {
394                     list.add( s );
395                 }
396             }
397         }
398         in.close();
399         return list;
400     }
401
402     final public static SortedSet<String> file2set( final File file ) throws IOException {
403         final SortedSet<String> set = new TreeSet<String>();
404         final BufferedReader in = new BufferedReader( new FileReader( file ) );
405         String str;
406         while ( ( str = in.readLine() ) != null ) {
407             str = str.trim();
408             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
409                 for( final String s : splitString( str ) ) {
410                     set.add( s );
411                 }
412             }
413         }
414         in.close();
415         return set;
416     }
417
418     final public static String getCurrentDateTime() {
419         final DateFormat format = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" );
420         return format.format( new Date() );
421     }
422
423     final public static String getFileSeparator() {
424         return ForesterUtil.FILE_SEPARATOR;
425     }
426
427     final public static String getFirstLine( final Object source ) throws FileNotFoundException, IOException {
428         BufferedReader reader = null;
429         if ( source instanceof File ) {
430             final File f = ( File ) source;
431             if ( !f.exists() ) {
432                 throw new IOException( "[" + f.getAbsolutePath() + "] does not exist" );
433             }
434             else if ( !f.isFile() ) {
435                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a file" );
436             }
437             else if ( !f.canRead() ) {
438                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a readable" );
439             }
440             reader = new BufferedReader( new FileReader( f ) );
441         }
442         else if ( source instanceof InputStream ) {
443             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
444         }
445         else if ( source instanceof String ) {
446             reader = new BufferedReader( new StringReader( ( String ) source ) );
447         }
448         else if ( source instanceof StringBuffer ) {
449             reader = new BufferedReader( new StringReader( source.toString() ) );
450         }
451         else if ( source instanceof URL ) {
452             reader = new BufferedReader( new InputStreamReader( ( ( URL ) source ).openStream() ) );
453         }
454         else {
455             throw new IllegalArgumentException( "dont know how to read [" + source.getClass() + "]" );
456         }
457         String line;
458         while ( ( line = reader.readLine() ) != null ) {
459             line = line.trim();
460             if ( !ForesterUtil.isEmpty( line ) ) {
461                 if ( reader != null ) {
462                     reader.close();
463                 }
464                 return line;
465             }
466         }
467         if ( reader != null ) {
468             reader.close();
469         }
470         return line;
471     }
472
473     final public static String getForesterLibraryInformation() {
474         return "forester " + ForesterConstants.FORESTER_VERSION + " (" + ForesterConstants.FORESTER_DATE + ")";
475     }
476
477     final public static String getLineSeparator() {
478         return ForesterUtil.LINE_SEPARATOR;
479     }
480
481     final public static void increaseCountingMap( final Map<String, Integer> counting_map, final String item_name ) {
482         if ( !counting_map.containsKey( item_name ) ) {
483             counting_map.put( item_name, 1 );
484         }
485         else {
486             counting_map.put( item_name, counting_map.get( item_name ) + 1 );
487         }
488     }
489
490     final public static boolean isContainsParanthesesableNhCharacter( final String nh ) {
491         return PARANTHESESABLE_NH_CHARS_PATTERN.matcher( nh ).find();
492     }
493
494     final public static boolean isEmpty( final List<?> l ) {
495         if ( ( l == null ) || l.isEmpty() ) {
496             return true;
497         }
498         for( final Object o : l ) {
499             if ( o != null ) {
500                 return false;
501             }
502         }
503         return true;
504     }
505
506     final public static boolean isEmpty( final Set<?> s ) {
507         if ( ( s == null ) || s.isEmpty() ) {
508             return true;
509         }
510         for( final Object o : s ) {
511             if ( o != null ) {
512                 return false;
513             }
514         }
515         return true;
516     }
517
518     final public static boolean isEmpty( final String s ) {
519         return ( ( s == null ) || ( s.length() < 1 ) );
520     }
521
522     final public static boolean isEqual( final double a, final double b ) {
523         return ( ( Math.abs( a - b ) ) < ZERO_DIFF );
524     }
525
526     final public static boolean isEven( final int n ) {
527         return ( n % 2 ) == 0;
528     }
529
530     /**
531      * This determines whether String[] a and String[] b have at least one
532      * String in common (intersect). Returns false if at least one String[] is
533      * null or empty.
534      * 
535      * @param a
536      *            a String[] b a String[]
537      * @return true if both a and b or not empty or null and contain at least
538      *         one element in common false otherwise
539      */
540     final public static boolean isIntersecting( final String[] a, final String[] b ) {
541         if ( ( a == null ) || ( b == null ) ) {
542             return false;
543         }
544         if ( ( a.length < 1 ) || ( b.length < 1 ) ) {
545             return false;
546         }
547         for( final String ai : a ) {
548             for( final String element : b ) {
549                 if ( ( ai != null ) && ( element != null ) && ai.equals( element ) ) {
550                     return true;
551                 }
552             }
553         }
554         return false;
555     }
556
557     final public static double isLargerOrEqualToZero( final double d ) {
558         if ( d > 0.0 ) {
559             return d;
560         }
561         else {
562             return 0.0;
563         }
564     }
565
566     final public static boolean isNull( final BigDecimal s ) {
567         return ( ( s == null ) || ( s.compareTo( NULL_BD ) == 0 ) );
568     }
569
570     final public static String isReadableFile( final File f ) {
571         if ( !f.exists() ) {
572             return "file [" + f + "] does not exist";
573         }
574         if ( f.isDirectory() ) {
575             return "[" + f + "] is a directory";
576         }
577         if ( !f.isFile() ) {
578             return "[" + f + "] is not a file";
579         }
580         if ( !f.canRead() ) {
581             return "file [" + f + "] is not readable";
582         }
583         if ( f.length() < 1 ) {
584             return "file [" + f + "] is empty";
585         }
586         return null;
587     }
588
589     final public static String isReadableFile( final String s ) {
590         return isReadableFile( new File( s ) );
591     }
592
593     public final static boolean isWindows() {
594         try {
595             return OS_NAME.toLowerCase().indexOf( "win" ) > -1;
596         }
597         catch ( final Exception e ) {
598             ForesterUtil.printWarningMessage( Constants.PRG_NAME, "minor error: " + e );
599             return false;
600         }
601     }
602
603     public final static boolean isMac() {
604         try {
605             return OS_NAME.toLowerCase().startsWith( "mac" );
606         }
607         catch ( final Exception e ) {
608             ForesterUtil.printWarningMessage( Constants.PRG_NAME, "minor error: " + e );
609             return false;
610         }
611     }
612
613     final public static String isWritableFile( final File f ) {
614         if ( f.isDirectory() ) {
615             return "[" + f + "] is a directory";
616         }
617         if ( f.exists() ) {
618             return "[" + f + "] already exists";
619         }
620         return null;
621     }
622
623     /**
624      * Helper for method "stringToColor".
625      * <p>
626      * (Last modified: 12/20/03)
627      */
628     final public static int limitRangeForColor( int i ) {
629         if ( i > 255 ) {
630             i = 255;
631         }
632         else if ( i < 0 ) {
633             i = 0;
634         }
635         return i;
636     }
637
638     final public static SortedMap<Object, Integer> listToSortedCountsMap( final List list ) {
639         final SortedMap<Object, Integer> map = new TreeMap<Object, Integer>();
640         for( final Object key : list ) {
641             if ( !map.containsKey( key ) ) {
642                 map.put( key, 1 );
643             }
644             else {
645                 map.put( key, map.get( key ) + 1 );
646             }
647         }
648         return map;
649     }
650
651     final public static void map2file( final File file,
652                                        final Map<?, ?> data,
653                                        final String entry_separator,
654                                        final String data_separator ) throws IOException {
655         final Writer writer = new BufferedWriter( new FileWriter( file ) );
656         map2writer( writer, data, entry_separator, data_separator );
657         writer.close();
658     }
659
660     final public static void map2writer( final Writer writer,
661                                          final Map<?, ?> data,
662                                          final String entry_separator,
663                                          final String data_separator ) throws IOException {
664         boolean first = true;
665         for( final Entry<?, ?> entry : data.entrySet() ) {
666             if ( !first ) {
667                 writer.write( data_separator );
668             }
669             else {
670                 first = false;
671             }
672             writer.write( entry.getKey().toString() );
673             writer.write( entry_separator );
674             writer.write( entry.getValue().toString() );
675         }
676     }
677
678     final public static StringBuffer mapToStringBuffer( final Map map, final String key_value_separator ) {
679         final StringBuffer sb = new StringBuffer();
680         for( final Iterator iter = map.keySet().iterator(); iter.hasNext(); ) {
681             final Object key = iter.next();
682             sb.append( key.toString() );
683             sb.append( key_value_separator );
684             sb.append( map.get( key ).toString() );
685             sb.append( ForesterUtil.getLineSeparator() );
686         }
687         return sb;
688     }
689
690     final public static String normalizeString( final String s,
691                                                 final int length,
692                                                 final boolean left_pad,
693                                                 final char pad_char ) {
694         if ( s.length() > length ) {
695             return s.substring( 0, length );
696         }
697         else {
698             final StringBuffer pad = new StringBuffer( length - s.length() );
699             for( int i = 0; i < ( length - s.length() ); ++i ) {
700                 pad.append( pad_char );
701             }
702             if ( left_pad ) {
703                 return pad + s;
704             }
705             else {
706                 return s + pad;
707             }
708         }
709     }
710
711     final public static BufferedReader obtainReader( final Object source ) throws IOException, FileNotFoundException {
712         BufferedReader reader = null;
713         if ( source instanceof File ) {
714             final File f = ( File ) source;
715             if ( !f.exists() ) {
716                 throw new IOException( "\"" + f.getAbsolutePath() + "\" does not exist" );
717             }
718             else if ( !f.isFile() ) {
719                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a file" );
720             }
721             else if ( !f.canRead() ) {
722                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a readable" );
723             }
724             reader = new BufferedReader( new FileReader( f ) );
725         }
726         else if ( source instanceof InputStream ) {
727             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
728         }
729         else if ( source instanceof String ) {
730             reader = new BufferedReader( new StringReader( ( String ) source ) );
731         }
732         else if ( source instanceof StringBuffer ) {
733             reader = new BufferedReader( new StringReader( source.toString() ) );
734         }
735         else {
736             throw new IllegalArgumentException( "attempt to parse object of type [" + source.getClass()
737                     + "] (can only parse objects of type File, InputStream, String, or StringBuffer)" );
738         }
739         return reader;
740     }
741
742     final public static StringBuffer pad( final double number, final int size, final char pad, final boolean left_pad ) {
743         return pad( new StringBuffer( number + "" ), size, pad, left_pad );
744     }
745
746     final public static StringBuffer pad( final String string, final int size, final char pad, final boolean left_pad ) {
747         return pad( new StringBuffer( string ), size, pad, left_pad );
748     }
749
750     final public static StringBuffer pad( final StringBuffer string,
751                                           final int size,
752                                           final char pad,
753                                           final boolean left_pad ) {
754         final StringBuffer padding = new StringBuffer();
755         final int s = size - string.length();
756         if ( s < 1 ) {
757             return new StringBuffer( string.substring( 0, size ) );
758         }
759         for( int i = 0; i < s; ++i ) {
760             padding.append( pad );
761         }
762         if ( left_pad ) {
763             return padding.append( string );
764         }
765         else {
766             return string.append( padding );
767         }
768     }
769
770     final public static double parseDouble( final String str ) throws ParseException {
771         if ( ForesterUtil.isEmpty( str ) ) {
772             return 0.0;
773         }
774         return Double.parseDouble( str );
775     }
776
777     final public static int parseInt( final String str ) throws ParseException {
778         if ( ForesterUtil.isEmpty( str ) ) {
779             return 0;
780         }
781         return Integer.parseInt( str );
782     }
783
784     final public static void printArray( final Object[] a ) {
785         for( int i = 0; i < a.length; ++i ) {
786             System.out.println( "[" + i + "]=" + a[ i ] );
787         }
788     }
789
790     final public static void printCountingMap( final Map<String, Integer> counting_map ) {
791         for( final String key : counting_map.keySet() ) {
792             System.out.println( key + ": " + counting_map.get( key ) );
793         }
794     }
795
796     final public static void printErrorMessage( final String prg_name, final String message ) {
797         System.err.println( "[" + prg_name + "] > error: " + message );
798     }
799
800     final public static void printProgramInformation( final String prg_name, final String prg_version, final String date ) {
801         final int l = prg_name.length() + prg_version.length() + date.length() + 4;
802         System.out.println();
803         System.out.println( prg_name + " " + prg_version + " (" + date + ")" );
804         for( int i = 0; i < l; ++i ) {
805             System.out.print( "_" );
806         }
807         System.out.println();
808     }
809
810     final public static void printProgramInformation( final String prg_name,
811                                                       final String prg_version,
812                                                       final String date,
813                                                       final String email,
814                                                       final String www ) {
815         printProgramInformation( prg_name, null, prg_version, date, email, www, null );
816     }
817
818     final public static void printProgramInformation( final String prg_name,
819                                                       final String desc,
820                                                       final String prg_version,
821                                                       final String date,
822                                                       final String email,
823                                                       final String www,
824                                                       final String based_on ) {
825         String my_prg_name = new String( prg_name );
826         if ( !ForesterUtil.isEmpty( desc ) ) {
827             my_prg_name += ( " - " + desc );
828         }
829         final int l = my_prg_name.length() + prg_version.length() + date.length() + 4;
830         System.out.println();
831         System.out.println( my_prg_name + " " + prg_version + " (" + date + ")" );
832         for( int i = 0; i < l; ++i ) {
833             System.out.print( "_" );
834         }
835         System.out.println();
836         System.out.println();
837         System.out.println( "WWW     : " + www );
838         System.out.println( "Contact : " + email );
839         if ( !ForesterUtil.isEmpty( based_on ) ) {
840             System.out.println( "Based on: " + based_on );
841         }
842         if ( !ForesterUtil.isEmpty( ForesterUtil.JAVA_VERSION ) && !ForesterUtil.isEmpty( ForesterUtil.JAVA_VENDOR ) ) {
843             System.out.println();
844             System.out.println( "[running on Java " + ForesterUtil.JAVA_VERSION + " " + ForesterUtil.JAVA_VENDOR + "]" );
845         }
846         System.out.println();
847     }
848
849     final public static void printWarningMessage( final String prg_name, final String message ) {
850         System.out.println( "[" + prg_name + "] > warning: " + message );
851     }
852
853     final public static void programMessage( final String prg_name, final String message ) {
854         System.out.println( "[" + prg_name + "] > " + message );
855     }
856
857     final public static String removeSuffix( final String file_name ) {
858         final int i = file_name.lastIndexOf( '.' );
859         if ( i > 1 ) {
860             return file_name.substring( 0, i );
861         }
862         return file_name;
863     }
864
865     /**
866      * Removes all white space from String s.
867      * 
868      * @return String s with white space removed
869      */
870     final public static String removeWhiteSpace( String s ) {
871         int i;
872         for( i = 0; i <= ( s.length() - 1 ); i++ ) {
873             if ( ( s.charAt( i ) == ' ' ) || ( s.charAt( i ) == '\t' ) || ( s.charAt( i ) == '\n' )
874                     || ( s.charAt( i ) == '\r' ) ) {
875                 s = s.substring( 0, i ) + s.substring( i + 1 );
876                 i--;
877             }
878         }
879         return s;
880     }
881
882     final public static String replaceIllegalNhCharacters( final String nh ) {
883         if ( nh == null ) {
884             return "";
885         }
886         return nh.trim().replaceAll( "[\\[\\]:]+", "_" );
887     }
888
889     final public static String replaceIllegalNhxCharacters( final String nhx ) {
890         if ( nhx == null ) {
891             return "";
892         }
893         return nhx.trim().replaceAll( "[\\[\\](),:;\\s]+", "_" );
894     }
895
896     final public static double round( final double value, final int decimal_place ) {
897         BigDecimal bd = new BigDecimal( value );
898         bd = bd.setScale( decimal_place, BigDecimal.ROUND_HALF_UP );
899         return bd.doubleValue();
900     }
901
902     /**
903      * Rounds d to an int.
904      */
905     final public static int roundToInt( final double d ) {
906         return ( int ) ( d + 0.5 );
907     }
908
909     final public static int roundToInt( final float f ) {
910         return ( int ) ( f + 0.5f );
911     }
912
913     final public static short roundToShort( final double d ) {
914         return ( short ) ( d + 0.5 );
915     }
916
917     final public static String sanitizeString( final String s ) {
918         if ( s == null ) {
919             return "";
920         }
921         else {
922             return s.trim();
923         }
924     }
925
926     public static boolean seqIsLikelyToBeAa( final String s ) {
927         final String seq = s.toLowerCase();
928         if ( ( seq.indexOf( 'r' ) > -1 ) || ( seq.indexOf( 'd' ) > -1 ) || ( seq.indexOf( 'e' ) > -1 )
929                 || ( seq.indexOf( 'q' ) > -1 ) || ( seq.indexOf( 'h' ) > -1 ) || ( seq.indexOf( 'k' ) > -1 )
930                 || ( seq.indexOf( 'w' ) > -1 ) || ( seq.indexOf( 's' ) > -1 ) || ( seq.indexOf( 'm' ) > -1 )
931                 || ( seq.indexOf( 'p' ) > -1 ) || ( seq.indexOf( 'v' ) > -1 ) ) {
932             return true;
933         }
934         return false;
935     }
936
937     final public static String stringArrayToString( final String[] a ) {
938         return stringArrayToString( a, ", " );
939     }
940
941     final public static String stringArrayToString( final String[] a, final String separator ) {
942         final StringBuilder sb = new StringBuilder();
943         if ( ( a != null ) && ( a.length > 0 ) ) {
944             for( int i = 0; i < ( a.length - 1 ); ++i ) {
945                 sb.append( a[ i ] + separator );
946             }
947             sb.append( a[ a.length - 1 ] );
948         }
949         return sb.toString();
950     }
951
952     final public static String[] stringListToArray( final List<String> list ) {
953         if ( list != null ) {
954             final String[] str = new String[ list.size() ];
955             int i = 0;
956             for( final String l : list ) {
957                 str[ i++ ] = l;
958             }
959             return str;
960         }
961         return null;
962     }
963
964     final public static String stringListToString( final List<String> l, final String separator ) {
965         final StringBuilder sb = new StringBuilder();
966         if ( ( l != null ) && ( l.size() > 0 ) ) {
967             for( int i = 0; i < ( l.size() - 1 ); ++i ) {
968                 sb.append( l.get( i ) + separator );
969             }
970             sb.append( l.get( l.size() - 1 ) );
971         }
972         return sb.toString();
973     }
974
975     final public static String[] stringSetToArray( final Set<String> strings ) {
976         final String[] str_array = new String[ strings.size() ];
977         int i = 0;
978         for( final String e : strings ) {
979             str_array[ i++ ] = e;
980         }
981         return str_array;
982     }
983
984     final public static void unexpectedFatalError( final Exception e ) {
985         System.err.println();
986         System.err.println( "unexpected exception: should not have occured! Please contact program author(s)." );
987         e.printStackTrace( System.err );
988         System.err.println();
989         System.exit( -1 );
990     }
991
992     final public static void unexpectedFatalError( final Error e ) {
993         System.err.println();
994         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
995         e.printStackTrace( System.err );
996         System.err.println();
997         System.exit( -1 );
998     }
999
1000     final public static void unexpectedFatalError( final String message ) {
1001         System.err.println();
1002         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
1003         System.err.println( message );
1004         System.err.println();
1005         System.exit( -1 );
1006     }
1007
1008     final public static void unexpectedFatalError( final String prg_name, final Exception e ) {
1009         System.err.println();
1010         System.err.println( "[" + prg_name
1011                 + "] > unexpected error; should not have occured! Please contact program author(s)." );
1012         e.printStackTrace( System.err );
1013         System.err.println();
1014         System.exit( -1 );
1015     }
1016
1017     final public static void unexpectedFatalError( final String prg_name, final String message ) {
1018         System.err.println();
1019         System.err.println( "[" + prg_name
1020                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1021         System.err.println( message );
1022         System.err.println();
1023         System.exit( -1 );
1024     }
1025
1026     final public static void unexpectedFatalError( final String prg_name, final String message, final Exception e ) {
1027         System.err.println();
1028         System.err.println( "[" + prg_name
1029                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1030         System.err.println( message );
1031         e.printStackTrace( System.err );
1032         System.err.println();
1033         System.exit( -1 );
1034     }
1035
1036     public final static void updateProgress( final double progress_percentage ) {
1037         final int width = 50;
1038         System.out.print( "\r[" );
1039         int i = 0;
1040         for( ; i <= ForesterUtil.roundToInt( progress_percentage * width ); i++ ) {
1041             System.out.print( "." );
1042         }
1043         for( ; i < width; i++ ) {
1044             System.out.print( " " );
1045         }
1046         System.out.print( "]" );
1047     }
1048
1049     public final static void updateProgress( final int i, final DecimalFormat f ) {
1050         System.out.print( "\r[" + f.format( i ) + "]" );
1051     }
1052
1053     public final static String wordWrap( final String str, final int width ) {
1054         final StringBuilder sb = new StringBuilder( str );
1055         int start = 0;
1056         int ls = -1;
1057         int i = 0;
1058         while ( i < sb.length() ) {
1059             if ( sb.charAt( i ) == ' ' ) {
1060                 ls = i;
1061             }
1062             if ( sb.charAt( i ) == '\n' ) {
1063                 ls = -1;
1064                 start = i + 1;
1065             }
1066             if ( i > ( ( start + width ) - 1 ) ) {
1067                 if ( ls != -1 ) {
1068                     sb.setCharAt( ls, '\n' );
1069                     start = ls + 1;
1070                     ls = -1;
1071                 }
1072                 else {
1073                     sb.insert( i, '\n' );
1074                     start = i + 1;
1075                 }
1076             }
1077             i++;
1078         }
1079         return sb.toString();
1080     }
1081
1082     /**
1083      * Helper method for calcColor methods.
1084      * 
1085      * @param smallercolor_component_x
1086      *            color component the smaller color
1087      * @param largercolor_component_x
1088      *            color component the larger color
1089      * @param x
1090      *            factor
1091      * @return an int representing a color component
1092      */
1093     final private static int calculateColorComponent( final double smallercolor_component_x,
1094                                                       final double largercolor_component_x,
1095                                                       final double x ) {
1096         return ( int ) ( smallercolor_component_x + ( ( x * ( largercolor_component_x - smallercolor_component_x ) ) / 255.0 ) );
1097     }
1098
1099     /**
1100      * Helper method for calcColor methods.
1101      * 
1102      * 
1103      * @param value
1104      *            the value
1105      * @param larger
1106      *            the largest value
1107      * @param smaller
1108      *            the smallest value
1109      * @return a normalized value between larger and smaller
1110      */
1111     final private static double calculateColorFactor( final double value, final double larger, final double smaller ) {
1112         return ( 255.0 * ( value - smaller ) ) / ( larger - smaller );
1113     }
1114
1115     final private static String[] splitString( final String str ) {
1116         final String regex = "[\\s;,]+";
1117         return str.split( regex );
1118     }
1119
1120     public final static void outOfMemoryError( final OutOfMemoryError e ) {
1121         System.err.println();
1122         System.err.println( "Java memory allocation might be too small, try \"-Xmx2048m\" java command line option" );
1123         System.err.println();
1124         e.printStackTrace( System.err );
1125         System.err.println();
1126         System.exit( -1 );
1127     }
1128 }