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