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: 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.List;
54 import java.util.Map;
55 import java.util.Map.Entry;
56 import java.util.Set;
57 import java.util.SortedMap;
58 import java.util.SortedSet;
59 import java.util.TreeMap;
60 import java.util.TreeSet;
61 import java.util.regex.Matcher;
62 import java.util.regex.Pattern;
63
64 import org.forester.archaeopteryx.Constants;
65 import org.forester.phylogeny.PhylogenyNode;
66 import org.forester.phylogeny.data.Distribution;
67 import org.forester.phylogeny.data.Sequence;
68 import org.forester.phylogeny.data.Taxonomy;
69 import org.forester.protein.BasicProtein;
70 import org.forester.protein.Domain;
71 import org.forester.protein.Protein;
72 import org.forester.surfacing.SurfacingUtil;
73
74 public final class ForesterUtil {
75
76     public final static String       FILE_SEPARATOR                   = System.getProperty( "file.separator" );
77     public static final NumberFormat FORMATTER_06;
78     public static final NumberFormat FORMATTER_3;
79     public static final NumberFormat FORMATTER_6;
80     public static final NumberFormat FORMATTER_9;
81     public final static String       JAVA_VENDOR                      = System.getProperty( "java.vendor" );
82     public final static String       JAVA_VERSION                     = System.getProperty( "java.version" );
83     public final static String       LINE_SEPARATOR                   = System.getProperty( "line.separator" );
84     public static final String       NCBI_GI                          = "http://www.ncbi.nlm.nih.gov/protein/gi:";
85     public static final String       NCBI_NUCCORE                     = "http://www.ncbi.nlm.nih.gov/nuccore/";
86     public static final String       NCBI_PROTEIN                     = "http://www.ncbi.nlm.nih.gov/protein/";
87     public static final BigDecimal   NULL_BD                          = new BigDecimal( 0 );
88     public final static String       OS_ARCH                          = System.getProperty( "os.arch" );
89     public final static String       OS_NAME                          = System.getProperty( "os.name" );
90     public final static String       OS_VERSION                       = System.getProperty( "os.version" );
91     public static final String       PDB                              = "http://www.pdb.org/pdb/explore/explore.do?pdbId=";
92     public final static String       UNIPROT_KB                       = "http://www.uniprot.org/uniprot/";
93     public final static double       ZERO_DIFF                        = 1.0E-9;
94     private static final Pattern     PARANTHESESABLE_NH_CHARS_PATTERN = Pattern.compile( "[(),;\\s:\\[\\]]" );
95     static {
96         final DecimalFormatSymbols dfs = new DecimalFormatSymbols();
97         dfs.setDecimalSeparator( '.' );
98         // dfs.setGroupingSeparator( ( char ) 0 );
99         FORMATTER_9 = new DecimalFormat( "#.#########", dfs );
100         FORMATTER_6 = new DecimalFormat( "#.######", dfs );
101         FORMATTER_06 = new DecimalFormat( "0.######", dfs );
102         FORMATTER_3 = new DecimalFormat( "#.###", dfs );
103     }
104
105     private ForesterUtil() {
106     }
107
108     final public static void appendSeparatorIfNotEmpty( final StringBuffer sb, final char separator ) {
109         if ( sb.length() > 0 ) {
110             sb.append( separator );
111         }
112     }
113
114     /**
115      * This calculates a color. If value is equal to min the returned color is
116      * minColor, if value is equal to max the returned color is maxColor,
117      * otherwise a color 'proportional' to value is returned.
118      * 
119      * @param value
120      *            the value 
121      * @param min
122      *            the smallest value 
123      * @param max
124      *            the largest value 
125      * @param minColor
126      *            the color for min
127      * @param maxColor
128      *            the color for max
129      * @return a Color
130      */
131     final public static Color calcColor( double value,
132                                          final double min,
133                                          final double max,
134                                          final Color minColor,
135                                          final Color maxColor ) {
136         if ( value < min ) {
137             value = min;
138         }
139         if ( value > max ) {
140             value = max;
141         }
142         final double x = ForesterUtil.calculateColorFactor( value, max, min );
143         final int red = ForesterUtil.calculateColorComponent( minColor.getRed(), maxColor.getRed(), x );
144         final int green = ForesterUtil.calculateColorComponent( minColor.getGreen(), maxColor.getGreen(), x );
145         final int blue = ForesterUtil.calculateColorComponent( minColor.getBlue(), maxColor.getBlue(), x );
146         return new Color( red, green, blue );
147     }
148
149     /**
150      * This calculates a color. If value is equal to min the returned color is
151      * minColor, if value is equal to max the returned color is maxColor, if
152      * value is equal to mean the returned color is meanColor, otherwise a color
153      * 'proportional' to value is returned -- either between min-mean or
154      * mean-max
155      * 
156      * @param value
157      *            the value
158      * @param min
159      *            the smallest value
160      * @param max
161      *            the largest value 
162      * @param mean
163      *            the mean/median value 
164      * @param minColor
165      *            the color for min
166      * @param maxColor
167      *            the color for max
168      * @param meanColor
169      *            the color for mean
170      * @return a Color
171      */
172     final public static Color calcColor( double value,
173                                          final double min,
174                                          final double max,
175                                          final double mean,
176                                          final Color minColor,
177                                          final Color maxColor,
178                                          final Color meanColor ) {
179         if ( value < min ) {
180             value = min;
181         }
182         if ( value > max ) {
183             value = max;
184         }
185         if ( value < mean ) {
186             final double x = ForesterUtil.calculateColorFactor( value, mean, min );
187             final int red = ForesterUtil.calculateColorComponent( minColor.getRed(), meanColor.getRed(), x );
188             final int green = ForesterUtil.calculateColorComponent( minColor.getGreen(), meanColor.getGreen(), x );
189             final int blue = ForesterUtil.calculateColorComponent( minColor.getBlue(), meanColor.getBlue(), x );
190             return new Color( red, green, blue );
191         }
192         else if ( value > mean ) {
193             final double x = ForesterUtil.calculateColorFactor( value, max, mean );
194             final int red = ForesterUtil.calculateColorComponent( meanColor.getRed(), maxColor.getRed(), x );
195             final int green = ForesterUtil.calculateColorComponent( meanColor.getGreen(), maxColor.getGreen(), x );
196             final int blue = ForesterUtil.calculateColorComponent( meanColor.getBlue(), maxColor.getBlue(), x );
197             return new Color( red, green, blue );
198         }
199         else {
200             return meanColor;
201         }
202     }
203
204     public static int calculateOverlap( final Domain domain, final List<Boolean> covered_positions ) {
205         int overlap_count = 0;
206         for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
207             if ( ( i < covered_positions.size() ) && ( covered_positions.get( i ) == true ) ) {
208                 ++overlap_count;
209             }
210         }
211         return overlap_count;
212     }
213
214     final public static String collapseWhiteSpace( final String s ) {
215         return s.replaceAll( "[\\s]+", " " );
216     }
217
218     final public static void collection2file( final File file, final Collection<?> data, final String separator )
219             throws IOException {
220         final Writer writer = new BufferedWriter( new FileWriter( file ) );
221         collection2writer( writer, data, separator );
222         writer.close();
223     }
224
225     final public static void collection2writer( final Writer writer, final Collection<?> data, final String separator )
226             throws IOException {
227         boolean first = true;
228         for( final Object object : data ) {
229             if ( !first ) {
230                 writer.write( separator );
231             }
232             else {
233                 first = false;
234             }
235             writer.write( object.toString() );
236         }
237     }
238
239     final public static String colorToHex( final Color color ) {
240         final String rgb = Integer.toHexString( color.getRGB() );
241         return rgb.substring( 2, rgb.length() );
242     }
243
244     synchronized public static void copyFile( final File in, final File out ) throws IOException {
245         final FileInputStream in_s = new FileInputStream( in );
246         final FileOutputStream out_s = new FileOutputStream( out );
247         try {
248             final byte[] buf = new byte[ 1024 ];
249             int i = 0;
250             while ( ( i = in_s.read( buf ) ) != -1 ) {
251                 out_s.write( buf, 0, i );
252             }
253         }
254         catch ( final IOException e ) {
255             throw e;
256         }
257         finally {
258             if ( in_s != null ) {
259                 in_s.close();
260             }
261             if ( out_s != null ) {
262                 out_s.close();
263             }
264         }
265     }
266
267     final public static int countChars( final String str, final char c ) {
268         int count = 0;
269         for( int i = 0; i < str.length(); ++i ) {
270             if ( str.charAt( i ) == c ) {
271                 ++count;
272             }
273         }
274         return count;
275     }
276
277     final public static BufferedWriter createBufferedWriter( final File file ) throws IOException {
278         if ( file.exists() ) {
279             throw new IOException( "[" + file + "] already exists" );
280         }
281         return new BufferedWriter( new FileWriter( file ) );
282     }
283
284     final public static BufferedWriter createBufferedWriter( final String name ) throws IOException {
285         return new BufferedWriter( new FileWriter( createFileForWriting( name ) ) );
286     }
287
288     final public static EasyWriter createEasyWriter( final File file ) throws IOException {
289         return new EasyWriter( createBufferedWriter( file ) );
290     }
291
292     final public static BufferedWriter createEasyWriter( final String name ) throws IOException {
293         return createEasyWriter( createFileForWriting( name ) );
294     }
295
296     final public static File createFileForWriting( final String name ) throws IOException {
297         final File file = new File( name );
298         if ( file.exists() ) {
299             throw new IOException( "[" + name + "] already exists" );
300         }
301         return file;
302     }
303
304     final public static void ensurePresenceOfDate( final PhylogenyNode node ) {
305         if ( !node.getNodeData().isHasDate() ) {
306             node.getNodeData().setDate( new org.forester.phylogeny.data.Date() );
307         }
308     }
309
310     final public static void ensurePresenceOfDistribution( final PhylogenyNode node ) {
311         if ( !node.getNodeData().isHasDistribution() ) {
312             node.getNodeData().setDistribution( new Distribution( "" ) );
313         }
314     }
315
316     public static void ensurePresenceOfSequence( final PhylogenyNode node ) {
317         if ( !node.getNodeData().isHasSequence() ) {
318             node.getNodeData().setSequence( new Sequence() );
319         }
320     }
321
322     public static void ensurePresenceOfTaxonomy( final PhylogenyNode node ) {
323         if ( !node.getNodeData().isHasTaxonomy() ) {
324             node.getNodeData().setTaxonomy( new Taxonomy() );
325         }
326     }
327
328     public static void fatalError( final String message ) {
329         System.err.println();
330         System.err.println( "error: " + message );
331         System.err.println();
332         System.exit( -1 );
333     }
334
335     public static void fatalError( final String prg_name, final String message ) {
336         System.err.println();
337         System.err.println( "[" + prg_name + "] > " + message );
338         System.err.println();
339         System.exit( -1 );
340     }
341
342     public static void fatalErrorIfFileNotReadable( final File file ) {
343         final String error = isReadableFile( file );
344         if ( !isEmpty( error ) ) {
345             System.err.println();
346             System.err.println( "error: " + error );
347             System.err.println();
348             System.exit( -1 );
349         }
350     }
351
352     public static void fatalErrorIfFileNotReadable( final String prg_name, final File file ) {
353         final String error = isReadableFile( file );
354         if ( !isEmpty( error ) ) {
355             System.err.println();
356             System.err.println( "[" + prg_name + "] > " + error );
357             System.err.println();
358             System.exit( -1 );
359         }
360     }
361
362     public static String[][] file22dArray( final File file ) throws IOException {
363         final List<String> list = new ArrayList<String>();
364         final BufferedReader in = new BufferedReader( new FileReader( file ) );
365         String str;
366         while ( ( str = in.readLine() ) != null ) {
367             str = str.trim();
368             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
369                 list.add( str );
370             }
371         }
372         in.close();
373         final String[][] ary = new String[ list.size() ][ 2 ];
374         final Pattern pa = Pattern.compile( "(\\S+)\\s+(\\S+)" );
375         int i = 0;
376         for( final String s : list ) {
377             final Matcher m = pa.matcher( s );
378             if ( m.matches() ) {
379                 ary[ i ][ 0 ] = m.group( 1 );
380                 ary[ i ][ 1 ] = m.group( 2 );
381                 ++i;
382             }
383             else {
384                 throw new IOException( "unexpcted format: " + s );
385             }
386         }
387         return ary;
388     }
389
390     public static String[] file2array( final File file ) throws IOException {
391         final List<String> list = file2list( file );
392         final String[] ary = new String[ list.size() ];
393         int i = 0;
394         for( final String s : list ) {
395             ary[ i++ ] = s;
396         }
397         return ary;
398     }
399
400     final public static List<String> file2list( final File file ) throws IOException {
401         final List<String> list = new ArrayList<String>();
402         final BufferedReader in = new BufferedReader( new FileReader( file ) );
403         String str;
404         while ( ( str = in.readLine() ) != null ) {
405             str = str.trim();
406             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
407                 for( final String s : splitString( str ) ) {
408                     list.add( s );
409                 }
410             }
411         }
412         in.close();
413         return list;
414     }
415
416     final public static SortedSet<String> file2set( final File file ) throws IOException {
417         final SortedSet<String> set = new TreeSet<String>();
418         final BufferedReader in = new BufferedReader( new FileReader( file ) );
419         String str;
420         while ( ( str = in.readLine() ) != null ) {
421             str = str.trim();
422             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
423                 for( final String s : splitString( str ) ) {
424                     set.add( s );
425                 }
426             }
427         }
428         in.close();
429         return set;
430     }
431
432     final public static String getCurrentDateTime() {
433         final DateFormat format = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" );
434         return format.format( new Date() );
435     }
436
437     final public static String getFileSeparator() {
438         return ForesterUtil.FILE_SEPARATOR;
439     }
440
441     final public static String getFirstLine( final Object source ) throws FileNotFoundException, IOException {
442         BufferedReader reader = null;
443         if ( source instanceof File ) {
444             final File f = ( File ) source;
445             if ( !f.exists() ) {
446                 throw new IOException( "[" + f.getAbsolutePath() + "] does not exist" );
447             }
448             else if ( !f.isFile() ) {
449                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a file" );
450             }
451             else if ( !f.canRead() ) {
452                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a readable" );
453             }
454             reader = new BufferedReader( new FileReader( f ) );
455         }
456         else if ( source instanceof InputStream ) {
457             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
458         }
459         else if ( source instanceof String ) {
460             reader = new BufferedReader( new StringReader( ( String ) source ) );
461         }
462         else if ( source instanceof StringBuffer ) {
463             reader = new BufferedReader( new StringReader( source.toString() ) );
464         }
465         else if ( source instanceof URL ) {
466             reader = new BufferedReader( new InputStreamReader( ( ( URL ) source ).openStream() ) );
467         }
468         else {
469             throw new IllegalArgumentException( "dont know how to read [" + source.getClass() + "]" );
470         }
471         String line;
472         while ( ( line = reader.readLine() ) != null ) {
473             line = line.trim();
474             if ( !ForesterUtil.isEmpty( line ) ) {
475                 if ( reader != null ) {
476                     reader.close();
477                 }
478                 return line;
479             }
480         }
481         if ( reader != null ) {
482             reader.close();
483         }
484         return line;
485     }
486
487     final public static String getForesterLibraryInformation() {
488         return "forester " + ForesterConstants.FORESTER_VERSION + " (" + ForesterConstants.FORESTER_DATE + ")";
489     }
490
491     final public static String getLineSeparator() {
492         return ForesterUtil.LINE_SEPARATOR;
493     }
494
495     final public static void increaseCountingMap( final Map<String, Integer> counting_map, final String item_name ) {
496         if ( !counting_map.containsKey( item_name ) ) {
497             counting_map.put( item_name, 1 );
498         }
499         else {
500             counting_map.put( item_name, counting_map.get( item_name ) + 1 );
501         }
502     }
503
504     final public static boolean isEmpty( final List<?> l ) {
505         if ( ( l == null ) || l.isEmpty() ) {
506             return true;
507         }
508         for( final Object o : l ) {
509             if ( o != null ) {
510                 return false;
511             }
512         }
513         return true;
514     }
515
516     final public static boolean isEmpty( final Set<?> s ) {
517         if ( ( s == null ) || s.isEmpty() ) {
518             return true;
519         }
520         for( final Object o : s ) {
521             if ( o != null ) {
522                 return false;
523             }
524         }
525         return true;
526     }
527
528     final public static boolean isEmpty( final String s ) {
529         return ( ( s == null ) || ( s.length() < 1 ) );
530     }
531
532     /**
533      * Returns true is Domain domain falls in an uninterrupted stretch of
534      * covered positions.
535      * 
536      * @param domain
537      * @param covered_positions
538      * @return
539      */
540     public static boolean isEngulfed( final Domain domain, final List<Boolean> covered_positions ) {
541         for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
542             if ( ( i >= covered_positions.size() ) || ( covered_positions.get( i ) != true ) ) {
543                 return false;
544             }
545         }
546         return true;
547     }
548
549     final public static boolean isEqual( final double a, final double b ) {
550         return ( ( Math.abs( a - b ) ) < ZERO_DIFF );
551     }
552
553     final public static boolean isEven( final int n ) {
554         return ( n % 2 ) == 0;
555     }
556
557     /**
558      * This determines whether String[] a and String[] b have at least one
559      * String in common (intersect). Returns false if at least one String[] is
560      * null or empty.
561      * 
562      * @param a
563      *            a String[] b a String[]
564      * @return true if both a and b or not empty or null and contain at least
565      *         one element in common false otherwise
566      */
567     final public static boolean isIntersecting( final String[] a, final String[] b ) {
568         if ( ( a == null ) || ( b == null ) ) {
569             return false;
570         }
571         if ( ( a.length < 1 ) || ( b.length < 1 ) ) {
572             return false;
573         }
574         for( final String ai : a ) {
575             for( final String element : b ) {
576                 if ( ( ai != null ) && ( element != null ) && ai.equals( element ) ) {
577                     return true;
578                 }
579             }
580         }
581         return false;
582     }
583
584     final public static double isLargerOrEqualToZero( final double d ) {
585         if ( d > 0.0 ) {
586             return d;
587         }
588         else {
589             return 0.0;
590         }
591     }
592
593     public final static boolean isMac() {
594         try {
595             return OS_NAME.toLowerCase().startsWith( "mac" );
596         }
597         catch ( final Exception e ) {
598             ForesterUtil.printWarningMessage( Constants.PRG_NAME, "minor error: " + e );
599             return false;
600         }
601     }
602
603     final public static boolean isNull( final BigDecimal s ) {
604         return ( ( s == null ) || ( s.compareTo( NULL_BD ) == 0 ) );
605     }
606
607     final public static String isReadableFile( final File f ) {
608         if ( !f.exists() ) {
609             return "file [" + f + "] does not exist";
610         }
611         if ( f.isDirectory() ) {
612             return "[" + f + "] is a directory";
613         }
614         if ( !f.isFile() ) {
615             return "[" + f + "] is not a file";
616         }
617         if ( !f.canRead() ) {
618             return "file [" + f + "] is not readable";
619         }
620         if ( f.length() < 1 ) {
621             return "file [" + f + "] is empty";
622         }
623         return null;
624     }
625
626     final public static String isReadableFile( final String s ) {
627         return isReadableFile( new File( s ) );
628     }
629
630     public final static boolean isWindows() {
631         try {
632             return OS_NAME.toLowerCase().indexOf( "win" ) > -1;
633         }
634         catch ( final Exception e ) {
635             ForesterUtil.printWarningMessage( Constants.PRG_NAME, "minor error: " + e );
636             return false;
637         }
638     }
639
640     final public static String isWritableFile( final File f ) {
641         if ( f.isDirectory() ) {
642             return "[" + f + "] is a directory";
643         }
644         if ( f.exists() ) {
645             return "[" + f + "] already exists";
646         }
647         return null;
648     }
649
650     /**
651      * Helper for method "stringToColor".
652      * <p>
653      * (Last modified: 12/20/03)
654      */
655     final public static int limitRangeForColor( int i ) {
656         if ( i > 255 ) {
657             i = 255;
658         }
659         else if ( i < 0 ) {
660             i = 0;
661         }
662         return i;
663     }
664
665     final public static SortedMap<Object, Integer> listToSortedCountsMap( final List<?> list ) {
666         final SortedMap<Object, Integer> map = new TreeMap<Object, Integer>();
667         for( final Object key : list ) {
668             if ( !map.containsKey( key ) ) {
669                 map.put( key, 1 );
670             }
671             else {
672                 map.put( key, map.get( key ) + 1 );
673             }
674         }
675         return map;
676     }
677
678     final public static void map2file( final File file,
679                                        final Map<?, ?> data,
680                                        final String entry_separator,
681                                        final String data_separator ) throws IOException {
682         final Writer writer = new BufferedWriter( new FileWriter( file ) );
683         map2writer( writer, data, entry_separator, data_separator );
684         writer.close();
685     }
686
687     final public static void map2writer( final Writer writer,
688                                          final Map<?, ?> data,
689                                          final String entry_separator,
690                                          final String data_separator ) throws IOException {
691         boolean first = true;
692         for( final Entry<?, ?> entry : data.entrySet() ) {
693             if ( !first ) {
694                 writer.write( data_separator );
695             }
696             else {
697                 first = false;
698             }
699             writer.write( entry.getKey().toString() );
700             writer.write( entry_separator );
701             writer.write( entry.getValue().toString() );
702         }
703     }
704
705     final public static StringBuffer mapToStringBuffer( final Map<Object, Object> map, final String key_value_separator ) {
706         final StringBuffer sb = new StringBuffer();
707         for( final Object key : map.keySet() ) {
708             sb.append( key.toString() );
709             sb.append( key_value_separator );
710             sb.append( map.get( key ).toString() );
711             sb.append( ForesterUtil.getLineSeparator() );
712         }
713         return sb;
714     }
715
716     final public static String normalizeString( final String s,
717                                                 final int length,
718                                                 final boolean left_pad,
719                                                 final char pad_char ) {
720         if ( s.length() > length ) {
721             return s.substring( 0, length );
722         }
723         else {
724             final StringBuffer pad = new StringBuffer( length - s.length() );
725             for( int i = 0; i < ( length - s.length() ); ++i ) {
726                 pad.append( pad_char );
727             }
728             if ( left_pad ) {
729                 return pad + s;
730             }
731             else {
732                 return s + pad;
733             }
734         }
735     }
736
737     public final static Color obtainColorDependingOnTaxonomyGroup( final String tax_group ) {
738         if ( !ForesterUtil.isEmpty( tax_group ) ) {
739             if ( tax_group.equals( TaxonomyGroups.DEUTEROSTOMIA ) ) {
740                 return TaxonomyColors.DEUTEROSTOMIA_COLOR;
741             }
742             else if ( tax_group.equals( TaxonomyGroups.PROTOSTOMIA ) ) {
743                 return TaxonomyColors.PROTOSTOMIA_COLOR;
744             }
745             else if ( tax_group.equals( TaxonomyGroups.CNIDARIA ) ) {
746                 return TaxonomyColors.CNIDARIA_COLOR;
747             }
748             else if ( tax_group.equals( TaxonomyGroups.PLACOZOA ) ) {
749                 return TaxonomyColors.PLACOZOA_COLOR;
750             }
751             else if ( tax_group.equals( TaxonomyGroups.CTENOPHORA ) ) {
752                 return TaxonomyColors.CTENOPHORA_COLOR;
753             }
754             else if ( tax_group.equals( TaxonomyGroups.PORIFERA ) ) {
755                 return TaxonomyColors.PORIFERA_COLOR;
756             }
757             else if ( tax_group.equals( TaxonomyGroups.CHOANOFLAGELLIDA ) ) {
758                 return TaxonomyColors.CHOANOFLAGELLIDA;
759             }
760             else if ( tax_group.equals( TaxonomyGroups.ICHTHYOPHONIDA_FILASTEREA ) ) {
761                 return TaxonomyColors.ICHTHYOSPOREA_AND_FILASTEREA;
762             }
763             else if ( tax_group.equals( TaxonomyGroups.DIKARYA ) ) {
764                 return TaxonomyColors.DIKARYA_COLOR;
765             }
766             else if ( tax_group.equalsIgnoreCase( TaxonomyGroups.FUNGI )
767                     || tax_group.equalsIgnoreCase( TaxonomyGroups.OTHER_FUNGI ) ) {
768                 return TaxonomyColors.OTHER_FUNGI_COLOR;
769             }
770             else if ( tax_group.equals( TaxonomyGroups.NUCLEARIIDAE_AND_FONTICULA_GROUP ) ) {
771                 return TaxonomyColors.NUCLEARIIDAE_AND_FONTICULA_GROUP_COLOR;
772             }
773             else if ( tax_group.equals( TaxonomyGroups.AMOEBOZOA ) ) {
774                 return TaxonomyColors.AMOEBOZOA_COLOR;
775             }
776             else if ( tax_group.equals( TaxonomyGroups.EMBRYOPHYTA ) ) {
777                 return TaxonomyColors.EMBRYOPHYTA_COLOR;
778             }
779             else if ( tax_group.equals( TaxonomyGroups.CHLOROPHYTA ) ) {
780                 return TaxonomyColors.CHLOROPHYTA_COLOR;
781             }
782             else if ( tax_group.equals( TaxonomyGroups.RHODOPHYTA ) ) {
783                 return TaxonomyColors.RHODOPHYTA_COLOR;
784             }
785             else if ( tax_group.equals( TaxonomyGroups.HACROBIA ) ) {
786                 return TaxonomyColors.HACROBIA_COLOR;
787             }
788             else if ( tax_group.equals( TaxonomyGroups.GLAUCOCYSTOPHYCEAE ) ) {
789                 return TaxonomyColors.GLAUCOPHYTA_COLOR;
790             }
791             else if ( tax_group.equals( TaxonomyGroups.STRAMENOPILES ) ) {
792                 return TaxonomyColors.STRAMENOPILES_COLOR;
793             }
794             else if ( tax_group.equals( TaxonomyGroups.ALVEOLATA ) ) {
795                 return TaxonomyColors.ALVEOLATA_COLOR;
796             }
797             else if ( tax_group.equals( TaxonomyGroups.RHIZARIA ) ) {
798                 return TaxonomyColors.RHIZARIA_COLOR;
799             }
800             else if ( tax_group.equals( TaxonomyGroups.EXCAVATA ) ) {
801                 return TaxonomyColors.EXCAVATA_COLOR;
802             }
803             else if ( tax_group.equals( TaxonomyGroups.APUSOZOA ) ) {
804                 return TaxonomyColors.APUSOZOA_COLOR;
805             }
806             else if ( tax_group.equals( TaxonomyGroups.ARCHAEA ) ) {
807                 return TaxonomyColors.ARCHAEA_COLOR;
808             }
809             else if ( tax_group.equals( TaxonomyGroups.BACTERIA ) ) {
810                 return TaxonomyColors.BACTERIA_COLOR;
811             }
812         }
813         return null;
814     }
815
816     public final static String obtainNormalizedTaxonomyGroup( final String tax ) {
817         if ( tax.equalsIgnoreCase( TaxonomyGroups.DEUTEROSTOMIA ) ) {
818             return TaxonomyGroups.DEUTEROSTOMIA;
819         }
820         else if ( tax.equalsIgnoreCase( TaxonomyGroups.PROTOSTOMIA ) ) {
821             return TaxonomyGroups.PROTOSTOMIA;
822         }
823         else if ( tax.equalsIgnoreCase( TaxonomyGroups.CNIDARIA ) ) {
824             return TaxonomyGroups.CNIDARIA;
825         }
826         else if ( tax.toLowerCase().startsWith( "trichoplax" ) || tax.equalsIgnoreCase( TaxonomyGroups.PLACOZOA ) ) {
827             return TaxonomyGroups.PLACOZOA;
828         }
829         else if ( tax.toLowerCase().startsWith( "mnemiopsis" ) || tax.equalsIgnoreCase( TaxonomyGroups.CTENOPHORA ) ) {
830             return TaxonomyGroups.CTENOPHORA;
831         }
832         else if ( tax.toLowerCase().startsWith( "amphimedon" ) || tax.equalsIgnoreCase( TaxonomyGroups.PORIFERA ) ) {
833             return TaxonomyGroups.PORIFERA;
834         }
835         else if ( tax.equalsIgnoreCase( "codonosigidae" ) || tax.equalsIgnoreCase( TaxonomyGroups.CHOANOFLAGELLIDA ) ) {
836             return TaxonomyGroups.CHOANOFLAGELLIDA;
837         }
838         else if ( tax.toLowerCase().startsWith( TaxonomyGroups.ICHTHYOPHONIDA_FILASTEREA )
839                 || tax.toLowerCase().startsWith( "ichthyophonida and filasterea" )
840                 || tax.toLowerCase().startsWith( "ichthyosporea & filasterea" )
841                 || tax.toLowerCase().startsWith( "ichthyosporea and filasterea" ) ) {
842             return TaxonomyGroups.ICHTHYOPHONIDA_FILASTEREA;
843         }
844         else if ( tax.equalsIgnoreCase( TaxonomyGroups.DIKARYA ) ) {
845             return TaxonomyGroups.DIKARYA;
846         }
847         else if ( tax.equalsIgnoreCase( TaxonomyGroups.FUNGI ) || tax.equalsIgnoreCase( TaxonomyGroups.OTHER_FUNGI ) ) {
848             return TaxonomyGroups.OTHER_FUNGI;
849         }
850         else if ( tax.toLowerCase().startsWith( "nucleariidae and fonticula" ) ) {
851             return TaxonomyGroups.NUCLEARIIDAE_AND_FONTICULA_GROUP;
852         }
853         else if ( tax.equalsIgnoreCase( TaxonomyGroups.AMOEBOZOA ) ) {
854             return TaxonomyGroups.AMOEBOZOA;
855         }
856         else if ( tax.equalsIgnoreCase( TaxonomyGroups.EMBRYOPHYTA ) ) {
857             return TaxonomyGroups.EMBRYOPHYTA;
858         }
859         else if ( tax.equalsIgnoreCase( TaxonomyGroups.CHLOROPHYTA ) ) {
860             return TaxonomyGroups.CHLOROPHYTA;
861         }
862         else if ( tax.equalsIgnoreCase( TaxonomyGroups.RHODOPHYTA ) ) {
863             return TaxonomyGroups.RHODOPHYTA;
864         }
865         else if ( tax.toLowerCase().startsWith( TaxonomyGroups.HACROBIA ) ) {
866             return TaxonomyGroups.HACROBIA;
867         }
868         else if ( tax.equalsIgnoreCase( TaxonomyGroups.GLAUCOCYSTOPHYCEAE ) || tax.equalsIgnoreCase( "glaucophyta" ) ) {
869             return TaxonomyGroups.GLAUCOCYSTOPHYCEAE;
870         }
871         else if ( tax.equalsIgnoreCase( TaxonomyGroups.STRAMENOPILES ) ) {
872             return TaxonomyGroups.STRAMENOPILES;
873         }
874         else if ( tax.equalsIgnoreCase( TaxonomyGroups.ALVEOLATA ) ) {
875             return TaxonomyGroups.ALVEOLATA;
876         }
877         else if ( tax.equalsIgnoreCase( TaxonomyGroups.RHIZARIA ) ) {
878             return TaxonomyGroups.RHIZARIA;
879         }
880         else if ( tax.equalsIgnoreCase( TaxonomyGroups.EXCAVATA ) ) {
881             return TaxonomyGroups.EXCAVATA;
882         }
883         else if ( tax.equalsIgnoreCase( TaxonomyGroups.APUSOZOA ) ) {
884             return TaxonomyGroups.APUSOZOA;
885         }
886         else if ( tax.equalsIgnoreCase( TaxonomyGroups.ARCHAEA ) ) {
887             return TaxonomyGroups.ARCHAEA;
888         }
889         else if ( tax.equalsIgnoreCase( TaxonomyGroups.BACTERIA ) ) {
890             return TaxonomyGroups.BACTERIA;
891         }
892         return null;
893     }
894
895     final public static BufferedReader obtainReader( final Object source ) throws IOException, FileNotFoundException {
896         BufferedReader reader = null;
897         if ( source instanceof File ) {
898             final File f = ( File ) source;
899             if ( !f.exists() ) {
900                 throw new IOException( "\"" + f.getAbsolutePath() + "\" does not exist" );
901             }
902             else if ( !f.isFile() ) {
903                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a file" );
904             }
905             else if ( !f.canRead() ) {
906                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a readable" );
907             }
908             reader = new BufferedReader( new FileReader( f ) );
909         }
910         else if ( source instanceof InputStream ) {
911             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
912         }
913         else if ( source instanceof String ) {
914             reader = new BufferedReader( new StringReader( ( String ) source ) );
915         }
916         else if ( source instanceof StringBuffer ) {
917             reader = new BufferedReader( new StringReader( source.toString() ) );
918         }
919         else {
920             throw new IllegalArgumentException( "attempt to parse object of type [" + source.getClass()
921                     + "] (can only parse objects of type File, InputStream, String, or StringBuffer)" );
922         }
923         return reader;
924     }
925
926     public final static void outOfMemoryError( final OutOfMemoryError e ) {
927         System.err.println();
928         System.err.println( "Java memory allocation might be too small, try \"-Xmx2048m\" java command line option" );
929         System.err.println();
930         e.printStackTrace( System.err );
931         System.err.println();
932         System.exit( -1 );
933     }
934
935     final public static StringBuffer pad( final double number, final int size, final char pad, final boolean left_pad ) {
936         return pad( new StringBuffer( number + "" ), size, pad, left_pad );
937     }
938
939     final public static StringBuffer pad( final String string, final int size, final char pad, final boolean left_pad ) {
940         return pad( new StringBuffer( string ), size, pad, left_pad );
941     }
942
943     final public static StringBuffer pad( final StringBuffer string,
944                                           final int size,
945                                           final char pad,
946                                           final boolean left_pad ) {
947         final StringBuffer padding = new StringBuffer();
948         final int s = size - string.length();
949         if ( s < 1 ) {
950             return new StringBuffer( string.substring( 0, size ) );
951         }
952         for( int i = 0; i < s; ++i ) {
953             padding.append( pad );
954         }
955         if ( left_pad ) {
956             return padding.append( string );
957         }
958         else {
959             return string.append( padding );
960         }
961     }
962
963     final public static double parseDouble( final String str ) throws ParseException {
964         if ( ForesterUtil.isEmpty( str ) ) {
965             return 0.0;
966         }
967         return Double.parseDouble( str );
968     }
969
970     final public static int parseInt( final String str ) throws ParseException {
971         if ( ForesterUtil.isEmpty( str ) ) {
972             return 0;
973         }
974         return Integer.parseInt( str );
975     }
976
977     final public static void printArray( final Object[] a ) {
978         for( int i = 0; i < a.length; ++i ) {
979             System.out.println( "[" + i + "]=" + a[ i ] );
980         }
981     }
982
983     final public static void printCountingMap( final Map<String, Integer> counting_map ) {
984         for( final String key : counting_map.keySet() ) {
985             System.out.println( key + ": " + counting_map.get( key ) );
986         }
987     }
988
989     final public static void printErrorMessage( final String prg_name, final String message ) {
990         System.err.println( "[" + prg_name + "] > error: " + message );
991     }
992
993     final public static void printProgramInformation( final String prg_name, final String prg_version, final String date ) {
994         final int l = prg_name.length() + prg_version.length() + date.length() + 4;
995         System.out.println();
996         System.out.println( prg_name + " " + prg_version + " (" + date + ")" );
997         for( int i = 0; i < l; ++i ) {
998             System.out.print( "_" );
999         }
1000         System.out.println();
1001     }
1002
1003     final public static void printProgramInformation( final String prg_name,
1004                                                       final String prg_version,
1005                                                       final String date,
1006                                                       final String email,
1007                                                       final String www ) {
1008         printProgramInformation( prg_name, null, prg_version, date, email, www, null );
1009     }
1010
1011     final public static void printProgramInformation( final String prg_name,
1012                                                       final String desc,
1013                                                       final String prg_version,
1014                                                       final String date,
1015                                                       final String email,
1016                                                       final String www,
1017                                                       final String based_on ) {
1018         String my_prg_name = new String( prg_name );
1019         if ( !ForesterUtil.isEmpty( desc ) ) {
1020             my_prg_name += ( " - " + desc );
1021         }
1022         final int l = my_prg_name.length() + prg_version.length() + date.length() + 4;
1023         System.out.println();
1024         System.out.println( my_prg_name + " " + prg_version + " (" + date + ")" );
1025         for( int i = 0; i < l; ++i ) {
1026             System.out.print( "_" );
1027         }
1028         System.out.println();
1029         System.out.println();
1030         System.out.println( "WWW     : " + www );
1031         System.out.println( "Contact : " + email );
1032         if ( !ForesterUtil.isEmpty( based_on ) ) {
1033             System.out.println( "Based on: " + based_on );
1034         }
1035         if ( !ForesterUtil.isEmpty( ForesterUtil.JAVA_VERSION ) && !ForesterUtil.isEmpty( ForesterUtil.JAVA_VENDOR ) ) {
1036             System.out.println();
1037             System.out.println( "[running on Java " + ForesterUtil.JAVA_VERSION + " " + ForesterUtil.JAVA_VENDOR + "]" );
1038         }
1039         System.out.println();
1040     }
1041
1042     final public static void printWarningMessage( final String prg_name, final String message ) {
1043         System.out.println( "[" + prg_name + "] > warning: " + message );
1044     }
1045
1046     final public static void programMessage( final String prg_name, final String message ) {
1047         System.out.println( "[" + prg_name + "] > " + message );
1048     }
1049
1050     /**
1051      * 
1052      * Example regarding engulfment: ------------0.1 ----------0.2 --0.3 =>
1053      * domain with 0.3 is ignored
1054      * 
1055      * -----------0.1 ----------0.2 --0.3 => domain with 0.3 is ignored
1056      * 
1057      * 
1058      * ------------0.1 ----------0.3 --0.2 => domains with 0.3 and 0.2 are _not_
1059      * ignored
1060      * 
1061      * @param max_allowed_overlap
1062      *            maximal allowed overlap (inclusive) to be still considered not
1063      *            overlapping (zero or negative value to allow any overlap)
1064      * @param remove_engulfed_domains
1065      *            to remove domains which are completely engulfed by coverage of
1066      *            domains with better support
1067      * @param protein
1068      * @return
1069      */
1070     public static Protein removeOverlappingDomains( final int max_allowed_overlap,
1071                                                     final boolean remove_engulfed_domains,
1072                                                     final Protein protein ) {
1073         final Protein pruned_protein = new BasicProtein( protein.getProteinId().getId(), protein.getSpecies()
1074                 .getSpeciesId(), protein.getLength() );
1075         final List<Domain> sorted = SurfacingUtil.sortDomainsWithAscendingConfidenceValues( protein );
1076         final List<Boolean> covered_positions = new ArrayList<Boolean>();
1077         for( final Domain domain : sorted ) {
1078             if ( ( ( max_allowed_overlap < 0 ) || ( ForesterUtil.calculateOverlap( domain, covered_positions ) <= max_allowed_overlap ) )
1079                     && ( !remove_engulfed_domains || !isEngulfed( domain, covered_positions ) ) ) {
1080                 final int covered_positions_size = covered_positions.size();
1081                 for( int i = covered_positions_size; i < domain.getFrom(); ++i ) {
1082                     covered_positions.add( false );
1083                 }
1084                 final int new_covered_positions_size = covered_positions.size();
1085                 for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
1086                     if ( i < new_covered_positions_size ) {
1087                         covered_positions.set( i, true );
1088                     }
1089                     else {
1090                         covered_positions.add( true );
1091                     }
1092                 }
1093                 pruned_protein.addProteinDomain( domain );
1094             }
1095         }
1096         return pruned_protein;
1097     }
1098
1099     final public static String removeSuffix( final String file_name ) {
1100         final int i = file_name.lastIndexOf( '.' );
1101         if ( i > 1 ) {
1102             return file_name.substring( 0, i );
1103         }
1104         return file_name;
1105     }
1106
1107     /**
1108      * Removes all white space from String s.
1109      * 
1110      * @return String s with white space removed
1111      */
1112     final public static String removeWhiteSpace( String s ) {
1113         int i;
1114         for( i = 0; i <= ( s.length() - 1 ); i++ ) {
1115             if ( ( s.charAt( i ) == ' ' ) || ( s.charAt( i ) == '\t' ) || ( s.charAt( i ) == '\n' )
1116                     || ( s.charAt( i ) == '\r' ) ) {
1117                 s = s.substring( 0, i ) + s.substring( i + 1 );
1118                 i--;
1119             }
1120         }
1121         return s;
1122     }
1123
1124     final public static String replaceIllegalNhxCharacters( final String nhx ) {
1125         if ( nhx == null ) {
1126             return "";
1127         }
1128         return nhx.trim().replaceAll( "[\\[\\]']+", "_" );
1129     }
1130
1131     final public static double round( final double value, final int decimal_place ) {
1132         BigDecimal bd = new BigDecimal( value );
1133         bd = bd.setScale( decimal_place, BigDecimal.ROUND_HALF_UP );
1134         return bd.doubleValue();
1135     }
1136
1137     /**
1138      * Rounds d to an int.
1139      */
1140     final public static int roundToInt( final double d ) {
1141         return ( int ) ( d + 0.5 );
1142     }
1143
1144     final public static int roundToInt( final float f ) {
1145         return ( int ) ( f + 0.5f );
1146     }
1147
1148     final public static short roundToShort( final double d ) {
1149         return ( short ) ( d + 0.5 );
1150     }
1151
1152     final public static String sanitizeString( final String s ) {
1153         if ( s == null ) {
1154             return "";
1155         }
1156         else {
1157             return s.trim();
1158         }
1159     }
1160
1161     public final static StringBuilder santitizeStringForNH( String data ) {
1162         data = data.replaceAll( "\\s+", " " ).trim();
1163         final StringBuilder sb = new StringBuilder();
1164         if ( data.length() > 0 ) {
1165             final boolean single_pars = data.indexOf( '\'' ) > -1;
1166             final boolean double_pars = data.indexOf( '"' ) > -1;
1167             if ( single_pars && double_pars ) {
1168                 data = data.replace( '\'', '`' );
1169                 sb.append( '\'' );
1170                 sb.append( data );
1171                 sb.append( '\'' );
1172             }
1173             else if ( single_pars ) {
1174                 sb.append( '"' );
1175                 sb.append( data );
1176                 sb.append( '"' );
1177             }
1178             else if ( PARANTHESESABLE_NH_CHARS_PATTERN.matcher( data ).find() ) {
1179                 sb.append( '\'' );
1180                 sb.append( data );
1181                 sb.append( '\'' );
1182             }
1183             else {
1184                 sb.append( data );
1185             }
1186         }
1187         return sb;
1188     }
1189
1190     public static boolean seqIsLikelyToBeAa( final String s ) {
1191         final String seq = s.toLowerCase();
1192         if ( ( seq.indexOf( 'r' ) > -1 ) || ( seq.indexOf( 'd' ) > -1 ) || ( seq.indexOf( 'e' ) > -1 )
1193                 || ( seq.indexOf( 'q' ) > -1 ) || ( seq.indexOf( 'h' ) > -1 ) || ( seq.indexOf( 'k' ) > -1 )
1194                 || ( seq.indexOf( 'w' ) > -1 ) || ( seq.indexOf( 's' ) > -1 ) || ( seq.indexOf( 'm' ) > -1 )
1195                 || ( seq.indexOf( 'p' ) > -1 ) || ( seq.indexOf( 'v' ) > -1 ) ) {
1196             return true;
1197         }
1198         return false;
1199     }
1200
1201     final public static String stringArrayToString( final String[] a ) {
1202         return stringArrayToString( a, ", " );
1203     }
1204
1205     final public static String stringArrayToString( final String[] a, final String separator ) {
1206         final StringBuilder sb = new StringBuilder();
1207         if ( ( a != null ) && ( a.length > 0 ) ) {
1208             for( int i = 0; i < ( a.length - 1 ); ++i ) {
1209                 sb.append( a[ i ] + separator );
1210             }
1211             sb.append( a[ a.length - 1 ] );
1212         }
1213         return sb.toString();
1214     }
1215
1216     final public static String[] stringListToArray( final List<String> list ) {
1217         if ( list != null ) {
1218             final String[] str = new String[ list.size() ];
1219             int i = 0;
1220             for( final String l : list ) {
1221                 str[ i++ ] = l;
1222             }
1223             return str;
1224         }
1225         return null;
1226     }
1227
1228     final public static String stringListToString( final List<String> l, final String separator ) {
1229         final StringBuilder sb = new StringBuilder();
1230         if ( ( l != null ) && ( l.size() > 0 ) ) {
1231             for( int i = 0; i < ( l.size() - 1 ); ++i ) {
1232                 sb.append( l.get( i ) + separator );
1233             }
1234             sb.append( l.get( l.size() - 1 ) );
1235         }
1236         return sb.toString();
1237     }
1238
1239     final public static String[] stringSetToArray( final Set<String> strings ) {
1240         final String[] str_array = new String[ strings.size() ];
1241         int i = 0;
1242         for( final String e : strings ) {
1243             str_array[ i++ ] = e;
1244         }
1245         return str_array;
1246     }
1247
1248     final public static void unexpectedFatalError( final Error e ) {
1249         System.err.println();
1250         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
1251         e.printStackTrace( System.err );
1252         System.err.println();
1253         System.exit( -1 );
1254     }
1255
1256     final public static void unexpectedFatalError( final Exception e ) {
1257         System.err.println();
1258         System.err.println( "unexpected exception: should not have occured! Please contact program author(s)." );
1259         e.printStackTrace( System.err );
1260         System.err.println();
1261         System.exit( -1 );
1262     }
1263
1264     final public static void unexpectedFatalError( final String message ) {
1265         System.err.println();
1266         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
1267         System.err.println( message );
1268         System.err.println();
1269         System.exit( -1 );
1270     }
1271
1272     final public static void unexpectedFatalError( final String prg_name, final Exception e ) {
1273         System.err.println();
1274         System.err.println( "[" + prg_name
1275                 + "] > unexpected error; should not have occured! Please contact program author(s)." );
1276         e.printStackTrace( System.err );
1277         System.err.println();
1278         System.exit( -1 );
1279     }
1280
1281     final public static void unexpectedFatalError( final String prg_name, final String message ) {
1282         System.err.println();
1283         System.err.println( "[" + prg_name
1284                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1285         System.err.println( message );
1286         System.err.println();
1287         System.exit( -1 );
1288     }
1289
1290     final public static void unexpectedFatalError( final String prg_name, final String message, final Exception e ) {
1291         System.err.println();
1292         System.err.println( "[" + prg_name
1293                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1294         System.err.println( message );
1295         e.printStackTrace( System.err );
1296         System.err.println();
1297         System.exit( -1 );
1298     }
1299
1300     public final static void updateProgress( final double progress_percentage ) {
1301         final int width = 50;
1302         System.out.print( "\r[" );
1303         int i = 0;
1304         for( ; i <= ForesterUtil.roundToInt( progress_percentage * width ); i++ ) {
1305             System.out.print( "." );
1306         }
1307         for( ; i < width; i++ ) {
1308             System.out.print( " " );
1309         }
1310         System.out.print( "]" );
1311     }
1312
1313     public final static void updateProgress( final int i, final DecimalFormat f ) {
1314         System.out.print( "\r[" + f.format( i ) + "]" );
1315     }
1316
1317     public final static String wordWrap( final String str, final int width ) {
1318         final StringBuilder sb = new StringBuilder( str );
1319         int start = 0;
1320         int ls = -1;
1321         int i = 0;
1322         while ( i < sb.length() ) {
1323             if ( sb.charAt( i ) == ' ' ) {
1324                 ls = i;
1325             }
1326             if ( sb.charAt( i ) == '\n' ) {
1327                 ls = -1;
1328                 start = i + 1;
1329             }
1330             if ( i > ( ( start + width ) - 1 ) ) {
1331                 if ( ls != -1 ) {
1332                     sb.setCharAt( ls, '\n' );
1333                     start = ls + 1;
1334                     ls = -1;
1335                 }
1336                 else {
1337                     sb.insert( i, '\n' );
1338                     start = i + 1;
1339                 }
1340             }
1341             i++;
1342         }
1343         return sb.toString();
1344     }
1345
1346     /**
1347      * Helper method for calcColor methods.
1348      * 
1349      * @param smallercolor_component_x
1350      *            color component the smaller color
1351      * @param largercolor_component_x
1352      *            color component the larger color
1353      * @param x
1354      *            factor
1355      * @return an int representing a color component
1356      */
1357     final private static int calculateColorComponent( final double smallercolor_component_x,
1358                                                       final double largercolor_component_x,
1359                                                       final double x ) {
1360         return ( int ) ( smallercolor_component_x + ( ( x * ( largercolor_component_x - smallercolor_component_x ) ) / 255.0 ) );
1361     }
1362
1363     /**
1364      * Helper method for calcColor methods.
1365      * 
1366      * 
1367      * @param value
1368      *            the value
1369      * @param larger
1370      *            the largest value
1371      * @param smaller
1372      *            the smallest value
1373      * @return a normalized value between larger and smaller
1374      */
1375     final private static double calculateColorFactor( final double value, final double larger, final double smaller ) {
1376         return ( 255.0 * ( value - smaller ) ) / ( larger - smaller );
1377     }
1378
1379     final private static String[] splitString( final String str ) {
1380         final String regex = "[\\s;,]+";
1381         return str.split( regex );
1382     }
1383 }