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