in progress...
[jalview.git] / forester / java / src / org / forester / util / ForesterUtil.java
1 // $Id:
2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
4 //
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
7 // All rights reserved
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 //
23 // Contact: phylosoft @ gmail . com
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
25
26 package org.forester.util;
27
28 import java.awt.Color;
29 import java.io.BufferedReader;
30 import java.io.BufferedWriter;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.FileNotFoundException;
34 import java.io.FileOutputStream;
35 import java.io.FileReader;
36 import java.io.FileWriter;
37 import java.io.FilenameFilter;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.InputStreamReader;
41 import java.io.StringReader;
42 import java.io.Writer;
43 import java.math.BigDecimal;
44 import java.net.URL;
45 import java.net.URLConnection;
46 import java.security.KeyManagementException;
47 import java.security.NoSuchAlgorithmException;
48 import java.text.DateFormat;
49 import java.text.DecimalFormat;
50 import java.text.DecimalFormatSymbols;
51 import java.text.NumberFormat;
52 import java.text.ParseException;
53 import java.text.SimpleDateFormat;
54 import java.util.ArrayList;
55 import java.util.Collection;
56 import java.util.Date;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.Map.Entry;
60 import java.util.Set;
61 import java.util.SortedMap;
62 import java.util.SortedSet;
63 import java.util.TreeMap;
64 import java.util.TreeSet;
65 import java.util.regex.Matcher;
66 import java.util.regex.Pattern;
67
68 import org.forester.archaeopteryx.AptxConstants;
69 import org.forester.io.parsers.PhylogenyParser;
70 import org.forester.phylogeny.Phylogeny;
71 import org.forester.phylogeny.PhylogenyNode;
72 import org.forester.phylogeny.data.Distribution;
73 import org.forester.phylogeny.data.Sequence;
74 import org.forester.phylogeny.data.Taxonomy;
75 import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
76 import org.forester.protein.BasicProtein;
77 import org.forester.protein.Domain;
78 import org.forester.protein.Protein;
79 import org.forester.sequence.MolecularSequence;
80 import org.forester.sequence.MolecularSequence.TYPE;
81 import org.forester.surfacing.SurfacingUtil;
82
83 public final class ForesterUtil {
84
85     public final static String       FILE_SEPARATOR                   = System.getProperty( "file.separator" );
86     public static final NumberFormat FORMATTER_06;
87     public static final NumberFormat FORMATTER_3;
88     public static final NumberFormat FORMATTER_6;
89     public static final NumberFormat FORMATTER_9;
90     public final static String       JAVA_VENDOR                      = System.getProperty( "java.vendor" );
91     public final static String       JAVA_VERSION                     = System.getProperty( "java.version" );
92     public final static String       LINE_SEPARATOR                   = System.getProperty( "line.separator" );
93     public static final String       NCBI_GI                          = "http://www.ncbi.nlm.nih.gov/protein/gi:";
94     public static final String       NCBI_NUCCORE                     = "http://www.ncbi.nlm.nih.gov/nuccore/";
95     public static final String       NCBI_PROTEIN                     = "http://www.ncbi.nlm.nih.gov/protein/";
96     public static final BigDecimal   NULL_BD                          = new BigDecimal( 0 );
97     public final static String       OS_ARCH                          = System.getProperty( "os.arch" );
98     public final static String       OS_NAME                          = System.getProperty( "os.name" );
99     public final static String       OS_VERSION                       = System.getProperty( "os.version" );
100     public static final String       PDB                              = "http://www.pdb.org/pdb/explore/explore.do?pdbId=";
101     public final static String       UNIPROT_KB                       = "http://www.uniprot.org/uniprot/";
102     public final static double       ZERO_DIFF                        = 1.0E-12;
103     private static final Pattern     PARANTHESESABLE_NH_CHARS_PATTERN = Pattern.compile( "[(),;\\s:\\[\\]]" );
104     static {
105         final DecimalFormatSymbols dfs = new DecimalFormatSymbols();
106         dfs.setDecimalSeparator( '.' );
107         // dfs.setGroupingSeparator( ( char ) 0 );
108         FORMATTER_9 = new DecimalFormat( "#.#########", dfs );
109         FORMATTER_6 = new DecimalFormat( "#.######", dfs );
110         FORMATTER_06 = new DecimalFormat( "0.######", dfs );
111         FORMATTER_3 = new DecimalFormat( "#.###", dfs );
112     }
113
114     final public static void appendSeparatorIfNotEmpty( final StringBuffer sb, final char separator ) {
115         if ( sb.length() > 0 ) {
116             sb.append( separator );
117         }
118     }
119
120     final public static String removeFileExtension( final String file_name ) {
121         if ( file_name.indexOf( "." ) > 0 ) {
122             return file_name.substring( 0, file_name.lastIndexOf( "." ) );
123         }
124         return file_name;
125     }
126
127     /**
128      * This calculates a color. If value is equal to min the returned color is
129      * minColor, if value is equal to max the returned color is maxColor,
130      * otherwise a color 'proportional' to value is returned.
131      *
132      * @param value
133      *            the value
134      * @param min
135      *            the smallest value
136      * @param max
137      *            the largest value
138      * @param minColor
139      *            the color for min
140      * @param maxColor
141      *            the color for max
142      * @return a Color
143      */
144     final public static Color calcColor( double value,
145                                          final double min,
146                                          final double max,
147                                          final Color minColor,
148                                          final Color maxColor ) {
149         if ( value < min ) {
150             value = min;
151         }
152         if ( value > max ) {
153             value = max;
154         }
155         final double x = ForesterUtil.calculateColorFactor( value, max, min );
156         final int red = ForesterUtil.calculateColorComponent( minColor.getRed(), maxColor.getRed(), x );
157         final int green = ForesterUtil.calculateColorComponent( minColor.getGreen(), maxColor.getGreen(), x );
158         final int blue = ForesterUtil.calculateColorComponent( minColor.getBlue(), maxColor.getBlue(), x );
159         return new Color( red, green, blue );
160     }
161
162     /**
163      * This calculates a color. If value is equal to min the returned color is
164      * minColor, if value is equal to max the returned color is maxColor, if
165      * value is equal to mean the returned color is meanColor, otherwise a color
166      * 'proportional' to value is returned -- either between min-mean or
167      * mean-max
168      *
169      * @param value
170      *            the value
171      * @param min
172      *            the smallest value
173      * @param max
174      *            the largest value
175      * @param mean
176      *            the mean/median value
177      * @param minColor
178      *            the color for min
179      * @param maxColor
180      *            the color for max
181      * @param meanColor
182      *            the color for mean
183      * @return a Color
184      */
185     final public static Color calcColor( double value,
186                                          final double min,
187                                          final double max,
188                                          final double mean,
189                                          final Color minColor,
190                                          final Color maxColor,
191                                          final Color meanColor ) {
192         if ( value < min ) {
193             value = min;
194         }
195         if ( value > max ) {
196             value = max;
197         }
198         if ( value < mean ) {
199             final double x = ForesterUtil.calculateColorFactor( value, mean, min );
200             final int red = ForesterUtil.calculateColorComponent( minColor.getRed(), meanColor.getRed(), x );
201             final int green = ForesterUtil.calculateColorComponent( minColor.getGreen(), meanColor.getGreen(), x );
202             final int blue = ForesterUtil.calculateColorComponent( minColor.getBlue(), meanColor.getBlue(), x );
203             return new Color( red, green, blue );
204         }
205         else if ( value > mean ) {
206             final double x = ForesterUtil.calculateColorFactor( value, max, mean );
207             final int red = ForesterUtil.calculateColorComponent( meanColor.getRed(), maxColor.getRed(), x );
208             final int green = ForesterUtil.calculateColorComponent( meanColor.getGreen(), maxColor.getGreen(), x );
209             final int blue = ForesterUtil.calculateColorComponent( meanColor.getBlue(), maxColor.getBlue(), x );
210             return new Color( red, green, blue );
211         }
212         else {
213             return meanColor;
214         }
215     }
216
217     /**
218      * Helper method for calcColor methods.
219      *
220      * @param smallercolor_component_x
221      *            color component the smaller color
222      * @param largercolor_component_x
223      *            color component the larger color
224      * @param x
225      *            factor
226      * @return an int representing a color component
227      */
228     final private static int calculateColorComponent( final double smallercolor_component_x,
229                                                       final double largercolor_component_x,
230                                                       final double x ) {
231         return ( int ) ( smallercolor_component_x
232                 + ( ( x * ( largercolor_component_x - smallercolor_component_x ) ) / 255.0 ) );
233     }
234
235     /**
236      * Helper method for calcColor methods.
237      *
238      *
239      * @param value
240      *            the value
241      * @param larger
242      *            the largest value
243      * @param smaller
244      *            the smallest value
245      * @return a normalized value between larger and smaller
246      */
247     final private static double calculateColorFactor( final double value, final double larger, final double smaller ) {
248         return ( 255.0 * ( value - smaller ) ) / ( larger - smaller );
249     }
250
251     public static int calculateOverlap( final Domain domain, final List<Boolean> covered_positions ) {
252         int overlap_count = 0;
253         for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
254             if ( ( i < covered_positions.size() ) && ( covered_positions.get( i ) == true ) ) {
255                 ++overlap_count;
256             }
257         }
258         return overlap_count;
259     }
260
261     final public static String collapseWhiteSpace( final String s ) {
262         return s.replaceAll( "[\\s]+", " " );
263     }
264
265     final public static void collection2file( final File file, final Collection<?> data, final String separator )
266             throws IOException {
267         final Writer writer = new BufferedWriter( new FileWriter( file ) );
268         collection2writer( writer, data, separator );
269         writer.close();
270     }
271
272     final public static void collection2writer( final Writer writer, final Collection<?> data, final String separator )
273             throws IOException {
274         boolean first = true;
275         for( final Object object : data ) {
276             if ( !first ) {
277                 writer.write( separator );
278             }
279             else {
280                 first = false;
281             }
282             writer.write( object.toString() );
283         }
284     }
285
286     final public static String colorToHex( final Color color ) {
287         final String rgb = Integer.toHexString( color.getRGB() );
288         return rgb.substring( 2, rgb.length() );
289     }
290
291     synchronized public static void copyFile( final File in, final File out ) throws IOException {
292         final FileInputStream in_s = new FileInputStream( in );
293         final FileOutputStream out_s = new FileOutputStream( out );
294         try {
295             final byte[] buf = new byte[ 1024 ];
296             int i = 0;
297             while ( ( i = in_s.read( buf ) ) != -1 ) {
298                 out_s.write( buf, 0, i );
299             }
300         }
301         catch ( final IOException e ) {
302             throw e;
303         }
304         finally {
305             if ( in_s != null ) {
306                 in_s.close();
307             }
308             if ( out_s != null ) {
309                 out_s.close();
310             }
311         }
312     }
313
314     final public static int countChars( final String str, final char c ) {
315         int count = 0;
316         for( int i = 0; i < str.length(); ++i ) {
317             if ( str.charAt( i ) == c ) {
318                 ++count;
319             }
320         }
321         return count;
322     }
323
324     final public static BufferedWriter createBufferedWriter( final File file ) throws IOException {
325         if ( file.exists() ) {
326             throw new IOException( "[" + file + "] already exists" );
327         }
328         return new BufferedWriter( new FileWriter( file ) );
329     }
330
331     final public static BufferedWriter createBufferedWriter( final String name ) throws IOException {
332         return new BufferedWriter( new FileWriter( createFileForWriting( name ) ) );
333     }
334
335     final public static EasyWriter createEasyWriter( final File file ) throws IOException {
336         return new EasyWriter( createBufferedWriter( file ) );
337     }
338
339     final public static BufferedWriter createEasyWriter( final String name ) throws IOException {
340         return createEasyWriter( createFileForWriting( name ) );
341     }
342
343     final public static File createFileForWriting( final String name ) throws IOException {
344         final File file = new File( name );
345         if ( file.exists() ) {
346             throw new IOException( "[" + name + "] already exists" );
347         }
348         return file;
349     }
350
351     final public static void ensurePresenceOfDate( final PhylogenyNode node ) {
352         if ( !node.getNodeData().isHasDate() ) {
353             node.getNodeData().setDate( new org.forester.phylogeny.data.Date() );
354         }
355     }
356
357     final public static void ensurePresenceOfDistribution( final PhylogenyNode node ) {
358         if ( !node.getNodeData().isHasDistribution() ) {
359             node.getNodeData().setDistribution( new Distribution( "" ) );
360         }
361     }
362
363     public static void ensurePresenceOfSequence( final PhylogenyNode node ) {
364         if ( !node.getNodeData().isHasSequence() ) {
365             node.getNodeData().setSequence( new Sequence() );
366         }
367     }
368
369     public static void ensurePresenceOfTaxonomy( final PhylogenyNode node ) {
370         if ( !node.getNodeData().isHasTaxonomy() ) {
371             node.getNodeData().setTaxonomy( new Taxonomy() );
372         }
373     }
374
375     public static void fatalError( final String message ) {
376         System.err.println();
377         System.err.println( "error: " + message );
378         System.err.println();
379         System.exit( -1 );
380     }
381
382     public static void fatalError( final String prg_name, final String message ) {
383         System.err.println();
384         System.err.println( "[" + prg_name + "] > " + message );
385         System.err.println();
386         System.exit( -1 );
387     }
388
389     public static void fatalErrorIfFileNotReadable( final File file ) {
390         final String error = isReadableFile( file );
391         if ( !isEmpty( error ) ) {
392             System.err.println();
393             System.err.println( "error: " + error );
394             System.err.println();
395             System.exit( -1 );
396         }
397     }
398
399     public static void fatalErrorIfFileNotReadable( final String prg_name, final File file ) {
400         final String error = isReadableFile( file );
401         if ( !isEmpty( error ) ) {
402             System.err.println();
403             System.err.println( "[" + prg_name + "] > " + error );
404             System.err.println();
405             System.exit( -1 );
406         }
407     }
408
409     public static String[][] file22dArray( final File file ) throws IOException {
410         final List<String> list = new ArrayList<String>();
411         final BufferedReader in = new BufferedReader( new FileReader( file ) );
412         String str;
413         while ( ( str = in.readLine() ) != null ) {
414             str = str.trim();
415             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
416                 list.add( str );
417             }
418         }
419         in.close();
420         final String[][] ary = new String[ list.size() ][ 2 ];
421         final Pattern pa = Pattern.compile( "(\\S+)\\s+(\\S+)" );
422         int i = 0;
423         for( final String s : list ) {
424             final Matcher m = pa.matcher( s );
425             if ( m.matches() ) {
426                 ary[ i ][ 0 ] = m.group( 1 );
427                 ary[ i ][ 1 ] = m.group( 2 );
428                 ++i;
429             }
430             else {
431                 throw new IOException( "unexpcted format: " + s );
432             }
433         }
434         return ary;
435     }
436
437     public static String[] file2array( final File file ) throws IOException {
438         final List<String> list = file2list( file );
439         final String[] ary = new String[ list.size() ];
440         int i = 0;
441         for( final String s : list ) {
442             ary[ i++ ] = s;
443         }
444         return ary;
445     }
446
447     final public static List<String> file2list( final File file ) throws IOException {
448         final List<String> list = new ArrayList<String>();
449         final BufferedReader in = new BufferedReader( new FileReader( file ) );
450         String str;
451         while ( ( str = in.readLine() ) != null ) {
452             str = str.trim();
453             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
454                 for( final String s : splitString( str ) ) {
455                     list.add( s );
456                 }
457             }
458         }
459         in.close();
460         return list;
461     }
462
463     final public static SortedSet<String> file2set( final File file ) throws IOException {
464         final SortedSet<String> set = new TreeSet<String>();
465         final BufferedReader in = new BufferedReader( new FileReader( file ) );
466         String str;
467         while ( ( str = in.readLine() ) != null ) {
468             str = str.trim();
469             if ( ( str.length() > 0 ) && !str.startsWith( "#" ) ) {
470                 for( final String s : splitString( str ) ) {
471                     set.add( s );
472                 }
473             }
474         }
475         in.close();
476         return set;
477     }
478
479     final public static String getCurrentDateTime() {
480         final DateFormat format = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" );
481         return format.format( new Date() );
482     }
483
484     final public static String getFileSeparator() {
485         return ForesterUtil.FILE_SEPARATOR;
486     }
487
488     final public static String getFirstLine( final Object source ) throws FileNotFoundException, IOException {
489         BufferedReader reader = null;
490         if ( source instanceof File ) {
491             final File f = ( File ) source;
492             if ( !f.exists() ) {
493                 throw new IOException( "[" + f.getAbsolutePath() + "] does not exist" );
494             }
495             else if ( !f.isFile() ) {
496                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a file" );
497             }
498             else if ( !f.canRead() ) {
499                 throw new IOException( "[" + f.getAbsolutePath() + "] is not a readable" );
500             }
501             reader = new BufferedReader( new FileReader( f ) );
502         }
503         else if ( source instanceof InputStream ) {
504             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
505         }
506         else if ( source instanceof String ) {
507             reader = new BufferedReader( new StringReader( ( String ) source ) );
508         }
509         else if ( source instanceof StringBuffer ) {
510             reader = new BufferedReader( new StringReader( source.toString() ) );
511         }
512         else if ( source instanceof URL ) {
513             final URLConnection url_connection = ( ( URL ) source ).openConnection();
514             url_connection.setDefaultUseCaches( false );
515             reader = new BufferedReader( new InputStreamReader( url_connection.getInputStream() ) );
516         }
517         else {
518             throw new IllegalArgumentException( "dont know how to read [" + source.getClass() + "]" );
519         }
520         String line;
521         while ( ( line = reader.readLine() ) != null ) {
522             line = line.trim();
523             if ( !ForesterUtil.isEmpty( line ) ) {
524                 if ( reader != null ) {
525                     reader.close();
526                 }
527                 return line;
528             }
529         }
530         if ( reader != null ) {
531             reader.close();
532         }
533         return line;
534     }
535
536     final public static String getForesterLibraryInformation() {
537         return "forester " + ForesterConstants.FORESTER_VERSION + " (" + ForesterConstants.FORESTER_DATE + ")";
538     }
539
540     final public static String getLineSeparator() {
541         return ForesterUtil.LINE_SEPARATOR;
542     }
543
544     final public static MolecularSequence.TYPE guessMolecularSequenceType( final String mol_seq ) {
545         if ( mol_seq.contains( "L" ) || mol_seq.contains( "I" ) || mol_seq.contains( "E" ) || mol_seq.contains( "H" )
546                 || mol_seq.contains( "D" ) || mol_seq.contains( "Q" ) ) {
547             return TYPE.AA;
548         }
549         else {
550             if ( mol_seq.contains( "T" ) ) {
551                 return TYPE.DNA;
552             }
553             else if ( mol_seq.contains( "U" ) ) {
554                 return TYPE.RNA;
555             }
556         }
557         return null;
558     }
559
560     final public static void increaseCountingMap( final Map<String, Integer> counting_map, final String item_name ) {
561         if ( !counting_map.containsKey( item_name ) ) {
562             counting_map.put( item_name, 1 );
563         }
564         else {
565             counting_map.put( item_name, counting_map.get( item_name ) + 1 );
566         }
567     }
568
569     final public static boolean isEmpty( final List<?> l ) {
570         if ( ( l == null ) || l.isEmpty() ) {
571             return true;
572         }
573         for( final Object o : l ) {
574             if ( o != null ) {
575                 return false;
576             }
577         }
578         return true;
579     }
580
581     final public static boolean isEmpty( final Set<?> s ) {
582         if ( ( s == null ) || s.isEmpty() ) {
583             return true;
584         }
585         for( final Object o : s ) {
586             if ( o != null ) {
587                 return false;
588             }
589         }
590         return true;
591     }
592
593     final public static boolean isEmpty( final String s ) {
594         return ( ( s == null ) || ( s.length() < 1 ) );
595     }
596
597     final public static boolean isEmptyTrimmed( final String s ) {
598         if ( s == null ) {
599             return true;
600         }
601         return ( ( s.trim().length() < 1 ) );
602     }
603
604     /**
605      * Returns true is Domain domain falls in an uninterrupted stretch of
606      * covered positions.
607      *
608      * @param domain
609      * @param covered_positions
610      * @return
611      */
612     public static boolean isEngulfed( final Domain domain, final List<Boolean> covered_positions ) {
613         for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
614             if ( ( i >= covered_positions.size() ) || ( covered_positions.get( i ) != true ) ) {
615                 return false;
616             }
617         }
618         return true;
619     }
620
621     final public static boolean isEqual( final double a, final double b ) {
622         return ( ( Math.abs( a - b ) ) < ZERO_DIFF );
623     }
624
625     final public static boolean isEqual( final double a, final double b, final double tolerance ) {
626         return ( ( Math.abs( a - b ) ) < tolerance );
627     }
628
629     final public static boolean isEven( final int n ) {
630         return ( n % 2 ) == 0;
631     }
632
633     /**
634      * This determines whether String[] a and String[] b have at least one
635      * String in common (intersect). Returns false if at least one String[] is
636      * null or empty.
637      *
638      * @param a
639      *            a String[] b a String[]
640      * @return true if both a and b or not empty or null and contain at least
641      *         one element in common false otherwise
642      */
643     final public static boolean isIntersecting( final String[] a, final String[] b ) {
644         if ( ( a == null ) || ( b == null ) ) {
645             return false;
646         }
647         if ( ( a.length < 1 ) || ( b.length < 1 ) ) {
648             return false;
649         }
650         for( final String ai : a ) {
651             for( final String element : b ) {
652                 if ( ( ai != null ) && ( element != null ) && ai.equals( element ) ) {
653                     return true;
654                 }
655             }
656         }
657         return false;
658     }
659
660     final public static double isLargerOrEqualToZero( final double d ) {
661         if ( d > 0.0 ) {
662             return d;
663         }
664         else {
665             return 0.0;
666         }
667     }
668
669     public final static boolean isMac() {
670         try {
671             return OS_NAME.toLowerCase().startsWith( "mac" );
672         }
673         catch ( final Exception e ) {
674             ForesterUtil.printWarningMessage( AptxConstants.PRG_NAME, "minor error: " + e );
675             return false;
676         }
677     }
678
679     final public static boolean isNull( final BigDecimal s ) {
680         return ( ( s == null ) || ( s.compareTo( NULL_BD ) == 0 ) );
681     }
682
683     final public static String isReadableFile( final File f ) {
684         if ( !f.exists() ) {
685             return "file [" + f + "] does not exist";
686         }
687         if ( f.isDirectory() ) {
688             return "[" + f + "] is a directory";
689         }
690         if ( !f.isFile() ) {
691             return "[" + f + "] is not a file";
692         }
693         if ( !f.canRead() ) {
694             return "file [" + f + "] is not readable";
695         }
696         if ( f.length() < 1 ) {
697             return "file [" + f + "] is empty";
698         }
699         return null;
700     }
701
702     final public static String isReadableFile( final String s ) {
703         return isReadableFile( new File( s ) );
704     }
705
706     public final static boolean isWindows() {
707         try {
708             return OS_NAME.toLowerCase().indexOf( "win" ) > -1;
709         }
710         catch ( final Exception e ) {
711             ForesterUtil.printWarningMessage( AptxConstants.PRG_NAME, "minor error: " + e );
712             return false;
713         }
714     }
715
716     final public static String isWritableFile( final File f ) {
717         if ( f.isDirectory() ) {
718             return "[" + f + "] is a directory";
719         }
720         if ( f.exists() ) {
721             return "[" + f + "] already exists";
722         }
723         return null;
724     }
725     
726     final public static String isWritableFile( final String s ) {
727         return isWritableFile( new File( s ) );
728     }
729
730     /**
731      * Helper for method "stringToColor".
732      * <p>
733      * (Last modified: 12/20/03)
734      */
735     final public static int limitRangeForColor( int i ) {
736         if ( i > 255 ) {
737             i = 255;
738         }
739         else if ( i < 0 ) {
740             i = 0;
741         }
742         return i;
743     }
744
745     final public static SortedMap<Object, Integer> listToSortedCountsMap( final List<?> list ) {
746         final SortedMap<Object, Integer> map = new TreeMap<Object, Integer>();
747         for( final Object key : list ) {
748             if ( !map.containsKey( key ) ) {
749                 map.put( key, 1 );
750             }
751             else {
752                 map.put( key, map.get( key ) + 1 );
753             }
754         }
755         return map;
756     }
757
758     final public static void map2file( final File file,
759                                        final Map<?, ?> data,
760                                        final String entry_separator,
761                                        final String data_separator )
762             throws IOException {
763         final Writer writer = new BufferedWriter( new FileWriter( file ) );
764         map2writer( writer, data, entry_separator, data_separator );
765         writer.close();
766     }
767
768     final public static void map2writer( final Writer writer,
769                                          final Map<?, ?> data,
770                                          final String entry_separator,
771                                          final String data_separator )
772             throws IOException {
773         boolean first = true;
774         for( final Entry<?, ?> entry : data.entrySet() ) {
775             if ( !first ) {
776                 writer.write( data_separator );
777             }
778             else {
779                 first = false;
780             }
781             writer.write( entry.getKey().toString() );
782             writer.write( entry_separator );
783             writer.write( entry.getValue().toString() );
784         }
785     }
786
787     final public static StringBuffer mapToStringBuffer( final Map<Object, Object> map,
788                                                         final String key_value_separator ) {
789         final StringBuffer sb = new StringBuffer();
790         for( final Object key : map.keySet() ) {
791             sb.append( key.toString() );
792             sb.append( key_value_separator );
793             sb.append( map.get( key ).toString() );
794             sb.append( ForesterUtil.getLineSeparator() );
795         }
796         return sb;
797     }
798
799     final public static String normalizeString( final String s,
800                                                 final int length,
801                                                 final boolean left_pad,
802                                                 final char pad_char ) {
803         if ( s.length() > length ) {
804             return s.substring( 0, length );
805         }
806         else {
807             final StringBuffer pad = new StringBuffer( length - s.length() );
808             for( int i = 0; i < ( length - s.length() ); ++i ) {
809                 pad.append( pad_char );
810             }
811             if ( left_pad ) {
812                 return pad + s;
813             }
814             else {
815                 return s + pad;
816             }
817         }
818     }
819
820     public final static Color obtainColorDependingOnTaxonomyGroup( final String tax_group ) {
821         if ( !ForesterUtil.isEmpty( tax_group ) ) {
822             if ( tax_group.equals( TaxonomyGroups.DEUTEROSTOMIA ) ) {
823                 return TaxonomyColors.DEUTEROSTOMIA_COLOR;
824             }
825             else if ( tax_group.equals( TaxonomyGroups.PROTOSTOMIA ) ) {
826                 return TaxonomyColors.PROTOSTOMIA_COLOR;
827             }
828             else if ( tax_group.equals( TaxonomyGroups.CNIDARIA ) ) {
829                 return TaxonomyColors.CNIDARIA_COLOR;
830             }
831             else if ( tax_group.equals( TaxonomyGroups.PLACOZOA ) ) {
832                 return TaxonomyColors.PLACOZOA_COLOR;
833             }
834             else if ( tax_group.equals( TaxonomyGroups.CTENOPHORA ) ) {
835                 return TaxonomyColors.CTENOPHORA_COLOR;
836             }
837             else if ( tax_group.equals( TaxonomyGroups.PORIFERA ) ) {
838                 return TaxonomyColors.PORIFERA_COLOR;
839             }
840             else if ( tax_group.equals( TaxonomyGroups.CHOANOFLAGELLIDA ) ) {
841                 return TaxonomyColors.CHOANOFLAGELLIDA;
842             }
843             else if ( tax_group.equals( TaxonomyGroups.ICHTHYOPHONIDA_FILASTEREA ) ) {
844                 return TaxonomyColors.ICHTHYOSPOREA_AND_FILASTEREA;
845             }
846             else if ( tax_group.equals( TaxonomyGroups.DIKARYA ) ) {
847                 return TaxonomyColors.DIKARYA_COLOR;
848             }
849             else if ( tax_group.equalsIgnoreCase( TaxonomyGroups.FUNGI )
850                     || tax_group.equalsIgnoreCase( TaxonomyGroups.OTHER_FUNGI ) ) {
851                 return TaxonomyColors.OTHER_FUNGI_COLOR;
852             }
853             else if ( tax_group.equals( TaxonomyGroups.NUCLEARIIDAE_AND_FONTICULA_GROUP ) ) {
854                 return TaxonomyColors.NUCLEARIIDAE_AND_FONTICULA_GROUP_COLOR;
855             }
856             else if ( tax_group.equals( TaxonomyGroups.AMOEBOZOA ) ) {
857                 return TaxonomyColors.AMOEBOZOA_COLOR;
858             }
859             else if ( tax_group.equals( TaxonomyGroups.EMBRYOPHYTA ) ) {
860                 return TaxonomyColors.EMBRYOPHYTA_COLOR;
861             }
862             else if ( tax_group.equals( TaxonomyGroups.CHLOROPHYTA ) ) {
863                 return TaxonomyColors.CHLOROPHYTA_COLOR;
864             }
865             else if ( tax_group.equals( TaxonomyGroups.RHODOPHYTA ) ) {
866                 return TaxonomyColors.RHODOPHYTA_COLOR;
867             }
868             else if ( tax_group.equals( TaxonomyGroups.HACROBIA ) ) {
869                 return TaxonomyColors.HACROBIA_COLOR;
870             }
871             else if ( tax_group.equals( TaxonomyGroups.GLAUCOCYSTOPHYCEAE ) ) {
872                 return TaxonomyColors.GLAUCOPHYTA_COLOR;
873             }
874             else if ( tax_group.equals( TaxonomyGroups.STRAMENOPILES ) ) {
875                 return TaxonomyColors.STRAMENOPILES_COLOR;
876             }
877             else if ( tax_group.equals( TaxonomyGroups.ALVEOLATA ) ) {
878                 return TaxonomyColors.ALVEOLATA_COLOR;
879             }
880             else if ( tax_group.equals( TaxonomyGroups.RHIZARIA ) ) {
881                 return TaxonomyColors.RHIZARIA_COLOR;
882             }
883             else if ( tax_group.equals( TaxonomyGroups.EXCAVATA ) ) {
884                 return TaxonomyColors.EXCAVATA_COLOR;
885             }
886             else if ( tax_group.equals( TaxonomyGroups.APUSOZOA ) ) {
887                 return TaxonomyColors.APUSOZOA_COLOR;
888             }
889             else if ( tax_group.equals( TaxonomyGroups.ARCHAEA ) ) {
890                 return TaxonomyColors.ARCHAEA_COLOR;
891             }
892             else if ( tax_group.equals( TaxonomyGroups.BACTERIA ) ) {
893                 return TaxonomyColors.BACTERIA_COLOR;
894             }
895             else if ( tax_group.equals( TaxonomyGroups.VIRUSES ) ) {
896                 return TaxonomyColors.VIRUSES_COLOR;
897             }
898             else if ( tax_group.equals( TaxonomyGroups.ALPHAHERPESVIRINAE ) ) {
899                 return TaxonomyColors.ALPHAHERPESVIRINAE_COLOR;
900             }
901             else if ( tax_group.equals( TaxonomyGroups.BETAHERPESVIRINAE ) ) {
902                 return TaxonomyColors.BETAHERPESVIRINAE_COLOR;
903             }
904             else if ( tax_group.equals( TaxonomyGroups.GAMMAHERPESVIRINAE ) ) {
905                 return TaxonomyColors.GAMMAHERPESVIRINAE_COLOR;
906             }
907             else if ( tax_group.equals( TaxonomyGroups.OTHER ) ) {
908                 return TaxonomyColors.OTHER_COLOR;
909             }
910         }
911         return null;
912     }
913
914     public final static String obtainNormalizedTaxonomyGroup( final String tax ) {
915         if ( tax.equalsIgnoreCase( TaxonomyGroups.DEUTEROSTOMIA ) ) {
916             return TaxonomyGroups.DEUTEROSTOMIA;
917         }
918         else if ( tax.equalsIgnoreCase( TaxonomyGroups.PROTOSTOMIA ) ) {
919             return TaxonomyGroups.PROTOSTOMIA;
920         }
921         else if ( tax.equalsIgnoreCase( TaxonomyGroups.CNIDARIA ) ) {
922             return TaxonomyGroups.CNIDARIA;
923         }
924         else if ( tax.toLowerCase().startsWith( "trichoplax" ) || tax.equalsIgnoreCase( TaxonomyGroups.PLACOZOA ) ) {
925             return TaxonomyGroups.PLACOZOA;
926         }
927         else if ( tax.toLowerCase().startsWith( "mnemiopsis" ) || tax.equalsIgnoreCase( TaxonomyGroups.CTENOPHORA ) ) {
928             return TaxonomyGroups.CTENOPHORA;
929         }
930         else if ( tax.toLowerCase().startsWith( "amphimedon" ) || tax.equalsIgnoreCase( TaxonomyGroups.PORIFERA ) ) {
931             return TaxonomyGroups.PORIFERA;
932         }
933         else if ( tax.equalsIgnoreCase( "codonosigidae" ) || tax.equalsIgnoreCase( TaxonomyGroups.CHOANOFLAGELLIDA ) ) {
934             return TaxonomyGroups.CHOANOFLAGELLIDA;
935         }
936         else if ( tax.toLowerCase().startsWith( TaxonomyGroups.ICHTHYOPHONIDA_FILASTEREA )
937                 || tax.toLowerCase().startsWith( "ichthyophonida and filasterea" )
938                 || tax.toLowerCase().startsWith( "ichthyosporea & filasterea" )
939                 || tax.toLowerCase().startsWith( "ichthyosporea and filasterea" ) ) {
940             return TaxonomyGroups.ICHTHYOPHONIDA_FILASTEREA;
941         }
942         else if ( tax.equalsIgnoreCase( TaxonomyGroups.DIKARYA ) ) {
943             return TaxonomyGroups.DIKARYA;
944         }
945         else if ( tax.equalsIgnoreCase( TaxonomyGroups.FUNGI ) || tax.equalsIgnoreCase( TaxonomyGroups.OTHER_FUNGI ) ) {
946             return TaxonomyGroups.OTHER_FUNGI;
947         }
948         else if ( tax.toLowerCase().startsWith( "nucleariidae and fonticula" ) ) {
949             return TaxonomyGroups.NUCLEARIIDAE_AND_FONTICULA_GROUP;
950         }
951         else if ( tax.equalsIgnoreCase( TaxonomyGroups.AMOEBOZOA ) ) {
952             return TaxonomyGroups.AMOEBOZOA;
953         }
954         else if ( tax.equalsIgnoreCase( TaxonomyGroups.EMBRYOPHYTA ) ) {
955             return TaxonomyGroups.EMBRYOPHYTA;
956         }
957         else if ( tax.equalsIgnoreCase( TaxonomyGroups.CHLOROPHYTA ) ) {
958             return TaxonomyGroups.CHLOROPHYTA;
959         }
960         else if ( tax.equalsIgnoreCase( TaxonomyGroups.RHODOPHYTA ) ) {
961             return TaxonomyGroups.RHODOPHYTA;
962         }
963         else if ( tax.toLowerCase().startsWith( TaxonomyGroups.HACROBIA ) ) {
964             return TaxonomyGroups.HACROBIA;
965         }
966         else if ( tax.equalsIgnoreCase( TaxonomyGroups.GLAUCOCYSTOPHYCEAE ) || tax.equalsIgnoreCase( "glaucophyta" ) ) {
967             return TaxonomyGroups.GLAUCOCYSTOPHYCEAE;
968         }
969         else if ( tax.equalsIgnoreCase( TaxonomyGroups.STRAMENOPILES ) ) {
970             return TaxonomyGroups.STRAMENOPILES;
971         }
972         else if ( tax.equalsIgnoreCase( TaxonomyGroups.ALVEOLATA ) ) {
973             return TaxonomyGroups.ALVEOLATA;
974         }
975         else if ( tax.equalsIgnoreCase( TaxonomyGroups.RHIZARIA ) ) {
976             return TaxonomyGroups.RHIZARIA;
977         }
978         else if ( tax.equalsIgnoreCase( TaxonomyGroups.EXCAVATA ) ) {
979             return TaxonomyGroups.EXCAVATA;
980         }
981         else if ( tax.equalsIgnoreCase( TaxonomyGroups.APUSOZOA ) ) {
982             return TaxonomyGroups.APUSOZOA;
983         }
984         else if ( tax.equalsIgnoreCase( TaxonomyGroups.ARCHAEA ) ) {
985             return TaxonomyGroups.ARCHAEA;
986         }
987         else if ( tax.equalsIgnoreCase( TaxonomyGroups.BACTERIA ) ) {
988             return TaxonomyGroups.BACTERIA;
989         }
990         else if ( tax.equalsIgnoreCase( TaxonomyGroups.BACTERIA ) ) {
991             return TaxonomyGroups.BACTERIA;
992         }
993         else if ( tax.equalsIgnoreCase( TaxonomyGroups.VIRUSES ) ) {
994             return TaxonomyGroups.VIRUSES;
995         }
996         else if ( tax.equalsIgnoreCase( TaxonomyGroups.ALPHAHERPESVIRINAE ) ) {
997             return TaxonomyGroups.ALPHAHERPESVIRINAE;
998         }
999         else if ( tax.equalsIgnoreCase( TaxonomyGroups.BETAHERPESVIRINAE ) ) {
1000             return TaxonomyGroups.BETAHERPESVIRINAE;
1001         }
1002         else if ( tax.equalsIgnoreCase( TaxonomyGroups.GAMMAHERPESVIRINAE ) ) {
1003             return TaxonomyGroups.GAMMAHERPESVIRINAE;
1004         }
1005         return null;
1006     }
1007
1008     final public static BufferedReader obtainReader( final Object source ) throws IOException, FileNotFoundException {
1009         BufferedReader reader = null;
1010         if ( source instanceof File ) {
1011             final File f = ( File ) source;
1012             if ( !f.exists() ) {
1013                 throw new IOException( "\"" + f.getAbsolutePath() + "\" does not exist" );
1014             }
1015             else if ( !f.isFile() ) {
1016                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a file" );
1017             }
1018             else if ( !f.canRead() ) {
1019                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a readable" );
1020             }
1021             reader = new BufferedReader( new FileReader( f ) );
1022         }
1023         else if ( source instanceof InputStream ) {
1024             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
1025         }
1026         else if ( source instanceof String ) {
1027             reader = new BufferedReader( new StringReader( ( String ) source ) );
1028         }
1029         else if ( source instanceof StringBuffer ) {
1030             reader = new BufferedReader( new StringReader( source.toString() ) );
1031         }
1032         else {
1033             throw new IllegalArgumentException( "attempt to parse object of type [" + source.getClass()
1034                     + "] (can only parse objects of type File, InputStream, String, or StringBuffer)" );
1035         }
1036         return reader;
1037     }
1038
1039     public final static void outOfMemoryError( final OutOfMemoryError e ) {
1040         System.err.println();
1041         System.err.println( "Java memory allocation might be too small, try \"-Xmx2048m\" java command line option" );
1042         System.err.println();
1043         e.printStackTrace( System.err );
1044         System.err.println();
1045         System.exit( -1 );
1046     }
1047
1048     final public static StringBuffer pad( final double number,
1049                                           final int size,
1050                                           final char pad,
1051                                           final boolean left_pad ) {
1052         return pad( new StringBuffer( number + "" ), size, pad, left_pad );
1053     }
1054
1055     final public static StringBuffer pad( final String string,
1056                                           final int size,
1057                                           final char pad,
1058                                           final boolean left_pad ) {
1059         return pad( new StringBuffer( string ), size, pad, left_pad );
1060     }
1061
1062     final public static StringBuffer pad( final StringBuffer string,
1063                                           final int size,
1064                                           final char pad,
1065                                           final boolean left_pad ) {
1066         final StringBuffer padding = new StringBuffer();
1067         final int s = size - string.length();
1068         if ( s < 1 ) {
1069             return new StringBuffer( string.substring( 0, size ) );
1070         }
1071         for( int i = 0; i < s; ++i ) {
1072             padding.append( pad );
1073         }
1074         if ( left_pad ) {
1075             return padding.append( string );
1076         }
1077         else {
1078             return string.append( padding );
1079         }
1080     }
1081
1082     final public static double parseDouble( final String str ) throws ParseException {
1083         if ( ForesterUtil.isEmpty( str ) ) {
1084             return 0.0;
1085         }
1086         return Double.parseDouble( str );
1087     }
1088
1089     final public static int parseInt( final String str ) throws ParseException {
1090         if ( ForesterUtil.isEmpty( str ) ) {
1091             return 0;
1092         }
1093         return Integer.parseInt( str );
1094     }
1095
1096     final public static void printArray( final Object[] a ) {
1097         for( int i = 0; i < a.length; ++i ) {
1098             System.out.println( "[" + i + "]=" + a[ i ] );
1099         }
1100     }
1101
1102     final public static void printCountingMap( final Map<String, Integer> counting_map ) {
1103         for( final String key : counting_map.keySet() ) {
1104             System.out.println( key + ": " + counting_map.get( key ) );
1105         }
1106     }
1107
1108     final public static void printErrorMessage( final String prg_name, final String message ) {
1109         System.err.println( "[" + prg_name + "] > error: " + message );
1110     }
1111
1112     final public static void printProgramInformation( final String prg_name,
1113                                                       final String prg_version,
1114                                                       final String date ) {
1115         final int l = prg_name.length() + prg_version.length() + date.length() + 4;
1116         System.out.println();
1117         System.out.println( prg_name + " " + prg_version + " (" + date + ")" );
1118         for( int i = 0; i < l; ++i ) {
1119             System.out.print( "_" );
1120         }
1121         System.out.println();
1122     }
1123
1124     final public static void printProgramInformation( final String prg_name,
1125                                                       final String prg_version,
1126                                                       final String date,
1127                                                       final String email,
1128                                                       final String www ) {
1129         printProgramInformation( prg_name, null, prg_version, date, email, www, null );
1130     }
1131
1132     final public static void printProgramInformation( final String prg_name,
1133                                                       final String desc,
1134                                                       final String prg_version,
1135                                                       final String date,
1136                                                       final String email,
1137                                                       final String www,
1138                                                       final String based_on ) {
1139         String my_prg_name = new String( prg_name );
1140         if ( !ForesterUtil.isEmpty( desc ) ) {
1141             my_prg_name += ( " - " + desc );
1142         }
1143         final int l = my_prg_name.length() + prg_version.length() + date.length() + 4;
1144         System.out.println();
1145         System.out.println( my_prg_name + " " + prg_version + " (" + date + ")" );
1146         for( int i = 0; i < l; ++i ) {
1147             System.out.print( "_" );
1148         }
1149         System.out.println();
1150         System.out.println();
1151         System.out.println( "WWW     : " + www );
1152         System.out.println( "Contact : " + email );
1153         if ( !ForesterUtil.isEmpty( based_on ) ) {
1154             System.out.println( "Based on: " + based_on );
1155         }
1156         if ( !ForesterUtil.isEmpty( ForesterUtil.JAVA_VERSION ) && !ForesterUtil.isEmpty( ForesterUtil.JAVA_VENDOR ) ) {
1157             System.out.println();
1158             System.out
1159                     .println( "[running on Java " + ForesterUtil.JAVA_VERSION + " " + ForesterUtil.JAVA_VENDOR + "]" );
1160         }
1161         System.out.println();
1162     }
1163
1164     final public static void printWarningMessage( final String prg_name, final String message ) {
1165         System.out.println( "[" + prg_name + "] > warning: " + message );
1166     }
1167
1168     final public static void programMessage( final String prg_name, final String message ) {
1169         System.out.println( "[" + prg_name + "] > " + message );
1170     }
1171
1172     public static List<String> readUrl( final String url_str ) throws IOException {
1173         final URL url = new URL( url_str );
1174         final URLConnection urlc = url.openConnection();
1175         //urlc.setRequestProperty( "User-Agent", "" );
1176         final BufferedReader in = new BufferedReader( new InputStreamReader( urlc.getInputStream() ) );
1177         String line;
1178         final List<String> result = new ArrayList<String>();
1179         while ( ( line = in.readLine() ) != null ) {
1180             result.add( line );
1181         }
1182         in.close();
1183         return result;
1184     }
1185
1186     /**
1187      *
1188      * Example regarding engulfment: ------------0.1 ----------0.2 --0.3 =>
1189      * domain with 0.3 is ignored
1190      *
1191      * -----------0.1 ----------0.2 --0.3 => domain with 0.3 is ignored
1192      *
1193      *
1194      * ------------0.1 ----------0.3 --0.2 => domains with 0.3 and 0.2 are _not_
1195      * ignored
1196      *
1197      * @param max_allowed_overlap
1198      *            maximal allowed overlap (inclusive) to be still considered not
1199      *            overlapping (zero or negative value to allow any overlap)
1200      * @param remove_engulfed_domains
1201      *            to remove domains which are completely engulfed by coverage of
1202      *            domains with better support
1203      * @param protein
1204      * @return
1205      */
1206     public static Protein removeOverlappingDomains( final int max_allowed_overlap,
1207                                                     final boolean remove_engulfed_domains,
1208                                                     final Protein protein ) {
1209         final Protein pruned_protein = new BasicProtein( protein.getProteinId().getId(),
1210                                                          protein.getSpecies().getSpeciesId(),
1211                                                          protein.getLength() );
1212         final List<Domain> sorted = SurfacingUtil.sortDomainsWithAscendingConfidenceValues( protein );
1213         final List<Boolean> covered_positions = new ArrayList<Boolean>();
1214         for( final Domain domain : sorted ) {
1215             if ( ( ( max_allowed_overlap < 0 )
1216                     || ( ForesterUtil.calculateOverlap( domain, covered_positions ) <= max_allowed_overlap ) )
1217                     && ( !remove_engulfed_domains || !isEngulfed( domain, covered_positions ) ) ) {
1218                 final int covered_positions_size = covered_positions.size();
1219                 for( int i = covered_positions_size; i < domain.getFrom(); ++i ) {
1220                     covered_positions.add( false );
1221                 }
1222                 final int new_covered_positions_size = covered_positions.size();
1223                 for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
1224                     if ( i < new_covered_positions_size ) {
1225                         covered_positions.set( i, true );
1226                     }
1227                     else {
1228                         covered_positions.add( true );
1229                     }
1230                 }
1231                 pruned_protein.addProteinDomain( domain );
1232             }
1233         }
1234         return pruned_protein;
1235     }
1236
1237     final public static String removeSuffix( final String file_name ) {
1238         final int i = file_name.lastIndexOf( '.' );
1239         if ( i > 1 ) {
1240             return file_name.substring( 0, i );
1241         }
1242         return file_name;
1243     }
1244
1245     /**
1246      * Removes all white space from String s.
1247      *
1248      * @return String s with white space removed
1249      */
1250     final public static String removeWhiteSpace( String s ) {
1251         int i;
1252         for( i = 0; i <= ( s.length() - 1 ); i++ ) {
1253             if ( ( s.charAt( i ) == ' ' ) || ( s.charAt( i ) == '\t' ) || ( s.charAt( i ) == '\n' )
1254                     || ( s.charAt( i ) == '\r' ) ) {
1255                 s = s.substring( 0, i ) + s.substring( i + 1 );
1256                 i--;
1257             }
1258         }
1259         return s;
1260     }
1261
1262     final public static String replaceIllegalNhxCharacters( final String nhx ) {
1263         if ( nhx == null ) {
1264             return "";
1265         }
1266         return nhx.trim().replaceAll( "[\\[\\]']+", "_" );
1267     }
1268
1269     final public static double round( final double value, final int decimal_place ) {
1270         BigDecimal bd = new BigDecimal( value );
1271         bd = bd.setScale( decimal_place, BigDecimal.ROUND_HALF_UP );
1272         return bd.doubleValue();
1273     }
1274
1275     /**
1276      * Rounds d to an int.
1277      */
1278     final public static int roundToInt( final double d ) {
1279         return ( int ) ( d + 0.5 );
1280     }
1281
1282     final public static int roundToInt( final float f ) {
1283         return ( int ) ( f + 0.5f );
1284     }
1285
1286     final public static short roundToShort( final double d ) {
1287         return ( short ) ( d + 0.5 );
1288     }
1289
1290     final public static String sanitizeString( final String s ) {
1291         if ( s == null ) {
1292             return "";
1293         }
1294         else {
1295             return s.trim();
1296         }
1297     }
1298
1299     public final static StringBuilder santitizeStringForNH( String data ) {
1300         data = data.replaceAll( "\\s+", " " ).trim();
1301         final StringBuilder sb = new StringBuilder();
1302         if ( data.length() > 0 ) {
1303             final boolean single_pars = data.indexOf( '\'' ) > -1;
1304             final boolean double_pars = data.indexOf( '"' ) > -1;
1305             if ( single_pars && double_pars ) {
1306                 data = data.replace( '\'', '`' );
1307                 sb.append( '\'' );
1308                 sb.append( data );
1309                 sb.append( '\'' );
1310             }
1311             else if ( single_pars ) {
1312                 sb.append( '"' );
1313                 sb.append( data );
1314                 sb.append( '"' );
1315             }
1316             else if ( PARANTHESESABLE_NH_CHARS_PATTERN.matcher( data ).find() ) {
1317                 sb.append( '\'' );
1318                 sb.append( data );
1319                 sb.append( '\'' );
1320             }
1321             else {
1322                 sb.append( data );
1323             }
1324         }
1325         return sb;
1326     }
1327
1328     public static boolean seqIsLikelyToBeAa( final String s ) {
1329         final String seq = s.toLowerCase();
1330         if ( ( seq.indexOf( 'r' ) > -1 ) || ( seq.indexOf( 'd' ) > -1 ) || ( seq.indexOf( 'e' ) > -1 )
1331                 || ( seq.indexOf( 'q' ) > -1 ) || ( seq.indexOf( 'h' ) > -1 ) || ( seq.indexOf( 'k' ) > -1 )
1332                 || ( seq.indexOf( 'w' ) > -1 ) || ( seq.indexOf( 's' ) > -1 ) || ( seq.indexOf( 'm' ) > -1 )
1333                 || ( seq.indexOf( 'p' ) > -1 ) || ( seq.indexOf( 'v' ) > -1 ) ) {
1334             return true;
1335         }
1336         return false;
1337     }
1338
1339     final private static String[] splitString( final String str ) {
1340         final String regex = "[\\s;,]+";
1341         return str.split( regex );
1342     }
1343
1344     final public static String stringArrayToString( final String[] a ) {
1345         return stringArrayToString( a, ", " );
1346     }
1347
1348     final public static String stringArrayToString( final String[] a, final String separator ) {
1349         final StringBuilder sb = new StringBuilder();
1350         if ( ( a != null ) && ( a.length > 0 ) ) {
1351             for( int i = 0; i < ( a.length - 1 ); ++i ) {
1352                 sb.append( a[ i ] + separator );
1353             }
1354             sb.append( a[ a.length - 1 ] );
1355         }
1356         return sb.toString();
1357     }
1358
1359     final public static String[] stringListToArray( final List<String> list ) {
1360         if ( list != null ) {
1361             final String[] str = new String[ list.size() ];
1362             int i = 0;
1363             for( final String l : list ) {
1364                 str[ i++ ] = l;
1365             }
1366             return str;
1367         }
1368         return null;
1369     }
1370
1371     final public static String stringListToString( final List<String> l, final String separator ) {
1372         final StringBuilder sb = new StringBuilder();
1373         if ( ( l != null ) && ( l.size() > 0 ) ) {
1374             for( int i = 0; i < ( l.size() - 1 ); ++i ) {
1375                 sb.append( l.get( i ) + separator );
1376             }
1377             sb.append( l.get( l.size() - 1 ) );
1378         }
1379         return sb.toString();
1380     }
1381
1382     final public static String[] stringSetToArray( final Set<String> strings ) {
1383         final String[] str_array = new String[ strings.size() ];
1384         int i = 0;
1385         for( final String e : strings ) {
1386             str_array[ i++ ] = e;
1387         }
1388         return str_array;
1389     }
1390
1391     final public static void unexpectedFatalError( final Error e ) {
1392         System.err.println();
1393         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
1394         e.printStackTrace( System.err );
1395         System.err.println();
1396         System.exit( -1 );
1397     }
1398
1399     final public static void unexpectedFatalError( final Exception e ) {
1400         System.err.println();
1401         System.err.println( "unexpected exception: should not have occured! Please contact program author(s)." );
1402         e.printStackTrace( System.err );
1403         System.err.println();
1404         System.exit( -1 );
1405     }
1406
1407     final public static void unexpectedFatalError( final String message ) {
1408         System.err.println();
1409         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
1410         System.err.println( message );
1411         System.err.println();
1412         System.exit( -1 );
1413     }
1414
1415     final public static void unexpectedFatalError( final String prg_name, final Exception e ) {
1416         System.err.println();
1417         System.err.println( "[" + prg_name
1418                 + "] > unexpected error; should not have occured! Please contact program author(s)." );
1419         e.printStackTrace( System.err );
1420         System.err.println();
1421         System.exit( -1 );
1422     }
1423
1424     final public static void unexpectedFatalError( final String prg_name, final String message ) {
1425         System.err.println();
1426         System.err.println( "[" + prg_name
1427                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1428         System.err.println( message );
1429         System.err.println();
1430         System.exit( -1 );
1431     }
1432
1433     final public static void unexpectedFatalError( final String prg_name, final String message, final Exception e ) {
1434         System.err.println();
1435         System.err.println( "[" + prg_name
1436                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1437         System.err.println( message );
1438         e.printStackTrace( System.err );
1439         System.err.println();
1440         System.exit( -1 );
1441     }
1442
1443     public final static void updateProgress( final double progress_percentage ) {
1444         final int width = 50;
1445         System.out.print( "\r[" );
1446         int i = 0;
1447         for( ; i <= ForesterUtil.roundToInt( progress_percentage * width ); i++ ) {
1448             System.out.print( "." );
1449         }
1450         for( ; i < width; i++ ) {
1451             System.out.print( " " );
1452         }
1453         System.out.print( "]" );
1454     }
1455
1456     public final static void updateProgress( final int i, final DecimalFormat f ) {
1457         System.out.print( "\r[" + f.format( i ) + "]" );
1458     }
1459
1460     public final static String wordWrap( final String str, final int width ) {
1461         final StringBuilder sb = new StringBuilder( str );
1462         int start = 0;
1463         int ls = -1;
1464         int i = 0;
1465         while ( i < sb.length() ) {
1466             if ( sb.charAt( i ) == ' ' ) {
1467                 ls = i;
1468             }
1469             if ( sb.charAt( i ) == '\n' ) {
1470                 ls = -1;
1471                 start = i + 1;
1472             }
1473             if ( i > ( ( start + width ) - 1 ) ) {
1474                 if ( ls != -1 ) {
1475                     sb.setCharAt( ls, '\n' );
1476                     start = ls + 1;
1477                     ls = -1;
1478                 }
1479                 else {
1480                     sb.insert( i, '\n' );
1481                     start = i + 1;
1482                 }
1483             }
1484             i++;
1485         }
1486         return sb.toString();
1487     }
1488
1489     public final static Phylogeny[] readPhylogeniesFromUrl( final URL url, final PhylogenyParser parser )
1490             throws NoSuchAlgorithmException, IOException, KeyManagementException {
1491         if ( url == null ) {
1492             throw new IllegalArgumentException( "URL to read from must not be null" );
1493         }
1494         else if ( parser == null ) {
1495             throw new IllegalArgumentException( "parser to use to read from URL must not be null" );
1496         }
1497         final URLConnection con;
1498         if ( url.toString().startsWith( "https:" ) ) {
1499             con = TrustManager.makeHttpsURLConnection( url );
1500         }
1501         else if ( url.toString().startsWith( "http:" ) ) {
1502             con = url.openConnection();
1503         }
1504         else {
1505             throw new IllegalArgumentException( "Cannot deal with URL: " + url );
1506         }
1507         if ( con == null ) {
1508             throw new IOException( "could not create connection from " + url );
1509         }
1510         con.setDefaultUseCaches( false );
1511         final InputStream is = con.getInputStream();
1512         if ( is == null ) {
1513             throw new IOException( "could not create input stream from " + url );
1514         }
1515         final Phylogeny[] trees = ParserBasedPhylogenyFactory.getInstance().create( is, parser );
1516         try {
1517             is.close();
1518         }
1519         catch ( final Exception e ) {
1520             // ignore  
1521         }
1522         return trees;
1523     }
1524
1525     public final static File getMatchingFile( final File dir, final String prefix, final String suffix )
1526             throws IOException {
1527         if ( !dir.exists() ) {
1528             throw new IOException( "[" + dir + "] does not exist" );
1529         }
1530         if ( !dir.isDirectory() ) {
1531             throw new IOException( "[" + dir + "] is not a directory" );
1532         }
1533         if ( dir.listFiles().length == 0 ) {
1534             throw new IOException( "[" + dir + "] is empty" );
1535         }
1536         final File files[] = dir.listFiles( new FilenameFilter() {
1537
1538             @Override
1539             public boolean accept( final File dir, final String name ) {
1540                 return ( name.endsWith( suffix ) );
1541             }
1542         } );
1543         if ( files.length == 0 ) {
1544             throw new IOException( "no files ending with \"" + suffix + "\" found in [" + dir + "]" );
1545         }
1546         String my_prefix = prefix;
1547         boolean done = false;
1548         boolean more_than_one = false;
1549         File the_one = null;
1550         do {
1551             int matches = 0;
1552             for( File file : files ) {
1553                 if ( file.getName().startsWith( my_prefix ) ) {
1554                     matches++;
1555                     if ( matches > 1 ) {
1556                         the_one = null;
1557                         break;
1558                     }
1559                     the_one = file;
1560                 }
1561             }
1562             if ( matches > 1 ) {
1563                 more_than_one = true;
1564                 done = true;
1565             }
1566             if ( matches == 1 ) {
1567                 done = true;
1568             }
1569             else {
1570                 if ( my_prefix.length() <= 1 ) {
1571                     throw new IOException( "no file matching \"" + removeFileExtension( prefix )
1572                             + "\" and ending with \"" + suffix + "\" found in [" + dir + "]" );
1573                 }
1574                 my_prefix = my_prefix.substring( 0, my_prefix.length() - 1 );
1575             }
1576         } while ( !done );
1577         if ( more_than_one ) {
1578             throw new IOException( "multiple files matching \"" + removeFileExtension( prefix )
1579                     + "\" and ending with \"" + suffix + "\" found in [" + dir + "]" );
1580         }
1581         else if ( the_one != null ) {
1582         }
1583         else {
1584             throw new IOException( "no file matching \"" + removeFileExtension( prefix ) + "\" and ending with \""
1585                     + suffix + "\" found in [" + dir + "]" );
1586         }
1587         return the_one;
1588     }
1589
1590     public final static String greatestCommonPrefix( final String a, final String b ) {
1591         final int min_length = Math.min( a.length(), b.length() );
1592         for( int i = 0; i < min_length; ++i ) {
1593             if ( a.charAt( i ) != b.charAt( i ) ) {
1594                 return a.substring( 0, i );
1595             }
1596         }
1597         return a.substring( 0, min_length );
1598     }
1599
1600     public final static String greatestCommonPrefix( final String a, final String b, final String separator ) {
1601         if ( ForesterUtil.isEmpty( separator ) ) {
1602             throw new IllegalArgumentException( "separator must not be null or empty" );
1603         }
1604         final String[] as = a.split( Pattern.quote( separator ) );
1605         final String[] bs = b.split( Pattern.quote( separator ) );
1606         final int min_length = Math.min( as.length, bs.length );
1607         for( int i = 0; i < min_length; ++i ) {
1608             if ( !( as[ i ].equals( bs[ i ] ) ) ) {
1609                 StringBuilder sb = new StringBuilder();
1610                 boolean first = true;
1611                 for( int j = 0; j < i; ++j ) {
1612                     if ( first ) {
1613                         first = false;
1614                     }
1615                     else {
1616                         sb.append( separator );
1617                     }
1618                     sb.append( as[ j ] );
1619                 }
1620                 return sb.toString();
1621             }
1622         }
1623         StringBuilder sb = new StringBuilder();
1624         boolean first = true;
1625         for( int j = 0; j < min_length; ++j ) {
1626             if ( first ) {
1627                 first = false;
1628             }
1629             else {
1630                 sb.append( separator );
1631             }
1632             sb.append( as[ j ] );
1633         }
1634         return sb.toString();
1635     }
1636
1637     public final static String greatestCommonPrefix( final List<String> strings ) {
1638         if ( strings == null ) {
1639             throw new IllegalArgumentException( "list of strings is null" );
1640         }
1641         if ( strings.isEmpty() ) {
1642             throw new IllegalArgumentException( "list of strings is empty" );
1643         }
1644         String common = strings.get( 0 );
1645         for( int i = 1; i < strings.size(); ++i ) {
1646             common = greatestCommonPrefix( common, strings.get( i ) );
1647         }
1648         return common;
1649     }
1650
1651     public final static String greatestCommonPrefix( final List<String> strings, final String separator ) {
1652         if ( ForesterUtil.isEmpty( separator ) ) {
1653             return greatestCommonPrefix( strings );
1654         }
1655         if ( strings == null ) {
1656             throw new IllegalArgumentException( "list of strings is null" );
1657         }
1658         if ( strings.isEmpty() ) {
1659             throw new IllegalArgumentException( "list of strings is empty" );
1660         }
1661         String common = strings.get( 0 );
1662         for( int i = 1; i < strings.size(); ++i ) {
1663             common = greatestCommonPrefix( common, strings.get( i ), separator );
1664         }
1665         return common;
1666     }
1667
1668     private ForesterUtil() {
1669     }
1670
1671     public static List<String> spliIntoPrefixes( final String prefix, final String separator ) {
1672         final String[] a = prefix.split( Pattern.quote( separator ) );
1673         final List<String> l = new ArrayList<String>();
1674         for( int i = 0; i < a.length; ++i ) {
1675             final StringBuilder sb = new StringBuilder();
1676             for( int j = 0; j <= i; ++j ) {
1677                 sb.append( a[ j ] );
1678                 if ( j < i ) {
1679                     sb.append( separator );
1680                 }
1681             }
1682             //  System.out.println( sb.toString() );
1683             l.add( sb.toString() );
1684         }
1685         return l;
1686     }
1687
1688     //
1689     public static boolean isLooksLikeFasta( final File file ) throws IOException {
1690         final String first_line = ForesterUtil.getFirstLine( file ).trim().toLowerCase();
1691         return ( ( !isEmptyTrimmed( first_line ) && first_line.trim().startsWith( ">" ) ) );
1692     }
1693 }