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