dddbf28842b2130123b506aad00f924a2e3ed962
[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     /**
727      * Helper for method "stringToColor".
728      * <p>
729      * (Last modified: 12/20/03)
730      */
731     final public static int limitRangeForColor( int i ) {
732         if ( i > 255 ) {
733             i = 255;
734         }
735         else if ( i < 0 ) {
736             i = 0;
737         }
738         return i;
739     }
740
741     final public static SortedMap<Object, Integer> listToSortedCountsMap( final List<?> list ) {
742         final SortedMap<Object, Integer> map = new TreeMap<Object, Integer>();
743         for( final Object key : list ) {
744             if ( !map.containsKey( key ) ) {
745                 map.put( key, 1 );
746             }
747             else {
748                 map.put( key, map.get( key ) + 1 );
749             }
750         }
751         return map;
752     }
753
754     final public static void map2file( final File file,
755                                        final Map<?, ?> data,
756                                        final String entry_separator,
757                                        final String data_separator )
758             throws IOException {
759         final Writer writer = new BufferedWriter( new FileWriter( file ) );
760         map2writer( writer, data, entry_separator, data_separator );
761         writer.close();
762     }
763
764     final public static void map2writer( final Writer writer,
765                                          final Map<?, ?> data,
766                                          final String entry_separator,
767                                          final String data_separator )
768             throws IOException {
769         boolean first = true;
770         for( final Entry<?, ?> entry : data.entrySet() ) {
771             if ( !first ) {
772                 writer.write( data_separator );
773             }
774             else {
775                 first = false;
776             }
777             writer.write( entry.getKey().toString() );
778             writer.write( entry_separator );
779             writer.write( entry.getValue().toString() );
780         }
781     }
782
783     final public static StringBuffer mapToStringBuffer( final Map<Object, Object> map,
784                                                         final String key_value_separator ) {
785         final StringBuffer sb = new StringBuffer();
786         for( final Object key : map.keySet() ) {
787             sb.append( key.toString() );
788             sb.append( key_value_separator );
789             sb.append( map.get( key ).toString() );
790             sb.append( ForesterUtil.getLineSeparator() );
791         }
792         return sb;
793     }
794
795     final public static String normalizeString( final String s,
796                                                 final int length,
797                                                 final boolean left_pad,
798                                                 final char pad_char ) {
799         if ( s.length() > length ) {
800             return s.substring( 0, length );
801         }
802         else {
803             final StringBuffer pad = new StringBuffer( length - s.length() );
804             for( int i = 0; i < ( length - s.length() ); ++i ) {
805                 pad.append( pad_char );
806             }
807             if ( left_pad ) {
808                 return pad + s;
809             }
810             else {
811                 return s + pad;
812             }
813         }
814     }
815
816     public final static Color obtainColorDependingOnTaxonomyGroup( final String tax_group ) {
817         if ( !ForesterUtil.isEmpty( tax_group ) ) {
818             if ( tax_group.equals( TaxonomyGroups.DEUTEROSTOMIA ) ) {
819                 return TaxonomyColors.DEUTEROSTOMIA_COLOR;
820             }
821             else if ( tax_group.equals( TaxonomyGroups.PROTOSTOMIA ) ) {
822                 return TaxonomyColors.PROTOSTOMIA_COLOR;
823             }
824             else if ( tax_group.equals( TaxonomyGroups.CNIDARIA ) ) {
825                 return TaxonomyColors.CNIDARIA_COLOR;
826             }
827             else if ( tax_group.equals( TaxonomyGroups.PLACOZOA ) ) {
828                 return TaxonomyColors.PLACOZOA_COLOR;
829             }
830             else if ( tax_group.equals( TaxonomyGroups.CTENOPHORA ) ) {
831                 return TaxonomyColors.CTENOPHORA_COLOR;
832             }
833             else if ( tax_group.equals( TaxonomyGroups.PORIFERA ) ) {
834                 return TaxonomyColors.PORIFERA_COLOR;
835             }
836             else if ( tax_group.equals( TaxonomyGroups.CHOANOFLAGELLIDA ) ) {
837                 return TaxonomyColors.CHOANOFLAGELLIDA;
838             }
839             else if ( tax_group.equals( TaxonomyGroups.ICHTHYOPHONIDA_FILASTEREA ) ) {
840                 return TaxonomyColors.ICHTHYOSPOREA_AND_FILASTEREA;
841             }
842             else if ( tax_group.equals( TaxonomyGroups.DIKARYA ) ) {
843                 return TaxonomyColors.DIKARYA_COLOR;
844             }
845             else if ( tax_group.equalsIgnoreCase( TaxonomyGroups.FUNGI )
846                     || tax_group.equalsIgnoreCase( TaxonomyGroups.OTHER_FUNGI ) ) {
847                 return TaxonomyColors.OTHER_FUNGI_COLOR;
848             }
849             else if ( tax_group.equals( TaxonomyGroups.NUCLEARIIDAE_AND_FONTICULA_GROUP ) ) {
850                 return TaxonomyColors.NUCLEARIIDAE_AND_FONTICULA_GROUP_COLOR;
851             }
852             else if ( tax_group.equals( TaxonomyGroups.AMOEBOZOA ) ) {
853                 return TaxonomyColors.AMOEBOZOA_COLOR;
854             }
855             else if ( tax_group.equals( TaxonomyGroups.EMBRYOPHYTA ) ) {
856                 return TaxonomyColors.EMBRYOPHYTA_COLOR;
857             }
858             else if ( tax_group.equals( TaxonomyGroups.CHLOROPHYTA ) ) {
859                 return TaxonomyColors.CHLOROPHYTA_COLOR;
860             }
861             else if ( tax_group.equals( TaxonomyGroups.RHODOPHYTA ) ) {
862                 return TaxonomyColors.RHODOPHYTA_COLOR;
863             }
864             else if ( tax_group.equals( TaxonomyGroups.HACROBIA ) ) {
865                 return TaxonomyColors.HACROBIA_COLOR;
866             }
867             else if ( tax_group.equals( TaxonomyGroups.GLAUCOCYSTOPHYCEAE ) ) {
868                 return TaxonomyColors.GLAUCOPHYTA_COLOR;
869             }
870             else if ( tax_group.equals( TaxonomyGroups.STRAMENOPILES ) ) {
871                 return TaxonomyColors.STRAMENOPILES_COLOR;
872             }
873             else if ( tax_group.equals( TaxonomyGroups.ALVEOLATA ) ) {
874                 return TaxonomyColors.ALVEOLATA_COLOR;
875             }
876             else if ( tax_group.equals( TaxonomyGroups.RHIZARIA ) ) {
877                 return TaxonomyColors.RHIZARIA_COLOR;
878             }
879             else if ( tax_group.equals( TaxonomyGroups.EXCAVATA ) ) {
880                 return TaxonomyColors.EXCAVATA_COLOR;
881             }
882             else if ( tax_group.equals( TaxonomyGroups.APUSOZOA ) ) {
883                 return TaxonomyColors.APUSOZOA_COLOR;
884             }
885             else if ( tax_group.equals( TaxonomyGroups.ARCHAEA ) ) {
886                 return TaxonomyColors.ARCHAEA_COLOR;
887             }
888             else if ( tax_group.equals( TaxonomyGroups.BACTERIA ) ) {
889                 return TaxonomyColors.BACTERIA_COLOR;
890             }
891             else if ( tax_group.equals( TaxonomyGroups.VIRUSES ) ) {
892                 return TaxonomyColors.VIRUSES_COLOR;
893             }
894             else if ( tax_group.equals( TaxonomyGroups.ALPHAHERPESVIRINAE ) ) {
895                 return TaxonomyColors.ALPHAHERPESVIRINAE_COLOR;
896             }
897             else if ( tax_group.equals( TaxonomyGroups.BETAHERPESVIRINAE ) ) {
898                 return TaxonomyColors.BETAHERPESVIRINAE_COLOR;
899             }
900             else if ( tax_group.equals( TaxonomyGroups.GAMMAHERPESVIRINAE ) ) {
901                 return TaxonomyColors.GAMMAHERPESVIRINAE_COLOR;
902             }
903             else if ( tax_group.equals( TaxonomyGroups.OTHER ) ) {
904                 return TaxonomyColors.OTHER_COLOR;
905             }
906         }
907         return null;
908     }
909
910     public final static String obtainNormalizedTaxonomyGroup( final String tax ) {
911         if ( tax.equalsIgnoreCase( TaxonomyGroups.DEUTEROSTOMIA ) ) {
912             return TaxonomyGroups.DEUTEROSTOMIA;
913         }
914         else if ( tax.equalsIgnoreCase( TaxonomyGroups.PROTOSTOMIA ) ) {
915             return TaxonomyGroups.PROTOSTOMIA;
916         }
917         else if ( tax.equalsIgnoreCase( TaxonomyGroups.CNIDARIA ) ) {
918             return TaxonomyGroups.CNIDARIA;
919         }
920         else if ( tax.toLowerCase().startsWith( "trichoplax" ) || tax.equalsIgnoreCase( TaxonomyGroups.PLACOZOA ) ) {
921             return TaxonomyGroups.PLACOZOA;
922         }
923         else if ( tax.toLowerCase().startsWith( "mnemiopsis" ) || tax.equalsIgnoreCase( TaxonomyGroups.CTENOPHORA ) ) {
924             return TaxonomyGroups.CTENOPHORA;
925         }
926         else if ( tax.toLowerCase().startsWith( "amphimedon" ) || tax.equalsIgnoreCase( TaxonomyGroups.PORIFERA ) ) {
927             return TaxonomyGroups.PORIFERA;
928         }
929         else if ( tax.equalsIgnoreCase( "codonosigidae" ) || tax.equalsIgnoreCase( TaxonomyGroups.CHOANOFLAGELLIDA ) ) {
930             return TaxonomyGroups.CHOANOFLAGELLIDA;
931         }
932         else if ( tax.toLowerCase().startsWith( TaxonomyGroups.ICHTHYOPHONIDA_FILASTEREA )
933                 || tax.toLowerCase().startsWith( "ichthyophonida and filasterea" )
934                 || tax.toLowerCase().startsWith( "ichthyosporea & filasterea" )
935                 || tax.toLowerCase().startsWith( "ichthyosporea and filasterea" ) ) {
936             return TaxonomyGroups.ICHTHYOPHONIDA_FILASTEREA;
937         }
938         else if ( tax.equalsIgnoreCase( TaxonomyGroups.DIKARYA ) ) {
939             return TaxonomyGroups.DIKARYA;
940         }
941         else if ( tax.equalsIgnoreCase( TaxonomyGroups.FUNGI ) || tax.equalsIgnoreCase( TaxonomyGroups.OTHER_FUNGI ) ) {
942             return TaxonomyGroups.OTHER_FUNGI;
943         }
944         else if ( tax.toLowerCase().startsWith( "nucleariidae and fonticula" ) ) {
945             return TaxonomyGroups.NUCLEARIIDAE_AND_FONTICULA_GROUP;
946         }
947         else if ( tax.equalsIgnoreCase( TaxonomyGroups.AMOEBOZOA ) ) {
948             return TaxonomyGroups.AMOEBOZOA;
949         }
950         else if ( tax.equalsIgnoreCase( TaxonomyGroups.EMBRYOPHYTA ) ) {
951             return TaxonomyGroups.EMBRYOPHYTA;
952         }
953         else if ( tax.equalsIgnoreCase( TaxonomyGroups.CHLOROPHYTA ) ) {
954             return TaxonomyGroups.CHLOROPHYTA;
955         }
956         else if ( tax.equalsIgnoreCase( TaxonomyGroups.RHODOPHYTA ) ) {
957             return TaxonomyGroups.RHODOPHYTA;
958         }
959         else if ( tax.toLowerCase().startsWith( TaxonomyGroups.HACROBIA ) ) {
960             return TaxonomyGroups.HACROBIA;
961         }
962         else if ( tax.equalsIgnoreCase( TaxonomyGroups.GLAUCOCYSTOPHYCEAE ) || tax.equalsIgnoreCase( "glaucophyta" ) ) {
963             return TaxonomyGroups.GLAUCOCYSTOPHYCEAE;
964         }
965         else if ( tax.equalsIgnoreCase( TaxonomyGroups.STRAMENOPILES ) ) {
966             return TaxonomyGroups.STRAMENOPILES;
967         }
968         else if ( tax.equalsIgnoreCase( TaxonomyGroups.ALVEOLATA ) ) {
969             return TaxonomyGroups.ALVEOLATA;
970         }
971         else if ( tax.equalsIgnoreCase( TaxonomyGroups.RHIZARIA ) ) {
972             return TaxonomyGroups.RHIZARIA;
973         }
974         else if ( tax.equalsIgnoreCase( TaxonomyGroups.EXCAVATA ) ) {
975             return TaxonomyGroups.EXCAVATA;
976         }
977         else if ( tax.equalsIgnoreCase( TaxonomyGroups.APUSOZOA ) ) {
978             return TaxonomyGroups.APUSOZOA;
979         }
980         else if ( tax.equalsIgnoreCase( TaxonomyGroups.ARCHAEA ) ) {
981             return TaxonomyGroups.ARCHAEA;
982         }
983         else if ( tax.equalsIgnoreCase( TaxonomyGroups.BACTERIA ) ) {
984             return TaxonomyGroups.BACTERIA;
985         }
986         else if ( tax.equalsIgnoreCase( TaxonomyGroups.BACTERIA ) ) {
987             return TaxonomyGroups.BACTERIA;
988         }
989         else if ( tax.equalsIgnoreCase( TaxonomyGroups.VIRUSES ) ) {
990             return TaxonomyGroups.VIRUSES;
991         }
992         else if ( tax.equalsIgnoreCase( TaxonomyGroups.ALPHAHERPESVIRINAE ) ) {
993             return TaxonomyGroups.ALPHAHERPESVIRINAE;
994         }
995         else if ( tax.equalsIgnoreCase( TaxonomyGroups.BETAHERPESVIRINAE ) ) {
996             return TaxonomyGroups.BETAHERPESVIRINAE;
997         }
998         else if ( tax.equalsIgnoreCase( TaxonomyGroups.GAMMAHERPESVIRINAE ) ) {
999             return TaxonomyGroups.GAMMAHERPESVIRINAE;
1000         }
1001         return null;
1002     }
1003
1004     final public static BufferedReader obtainReader( final Object source ) throws IOException, FileNotFoundException {
1005         BufferedReader reader = null;
1006         if ( source instanceof File ) {
1007             final File f = ( File ) source;
1008             if ( !f.exists() ) {
1009                 throw new IOException( "\"" + f.getAbsolutePath() + "\" does not exist" );
1010             }
1011             else if ( !f.isFile() ) {
1012                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a file" );
1013             }
1014             else if ( !f.canRead() ) {
1015                 throw new IOException( "\"" + f.getAbsolutePath() + "\" is not a readable" );
1016             }
1017             reader = new BufferedReader( new FileReader( f ) );
1018         }
1019         else if ( source instanceof InputStream ) {
1020             reader = new BufferedReader( new InputStreamReader( ( InputStream ) source ) );
1021         }
1022         else if ( source instanceof String ) {
1023             reader = new BufferedReader( new StringReader( ( String ) source ) );
1024         }
1025         else if ( source instanceof StringBuffer ) {
1026             reader = new BufferedReader( new StringReader( source.toString() ) );
1027         }
1028         else {
1029             throw new IllegalArgumentException( "attempt to parse object of type [" + source.getClass()
1030                     + "] (can only parse objects of type File, InputStream, String, or StringBuffer)" );
1031         }
1032         return reader;
1033     }
1034
1035     public final static void outOfMemoryError( final OutOfMemoryError e ) {
1036         System.err.println();
1037         System.err.println( "Java memory allocation might be too small, try \"-Xmx2048m\" java command line option" );
1038         System.err.println();
1039         e.printStackTrace( System.err );
1040         System.err.println();
1041         System.exit( -1 );
1042     }
1043
1044     final public static StringBuffer pad( final double number,
1045                                           final int size,
1046                                           final char pad,
1047                                           final boolean left_pad ) {
1048         return pad( new StringBuffer( number + "" ), size, pad, left_pad );
1049     }
1050
1051     final public static StringBuffer pad( final String string,
1052                                           final int size,
1053                                           final char pad,
1054                                           final boolean left_pad ) {
1055         return pad( new StringBuffer( string ), size, pad, left_pad );
1056     }
1057
1058     final public static StringBuffer pad( final StringBuffer string,
1059                                           final int size,
1060                                           final char pad,
1061                                           final boolean left_pad ) {
1062         final StringBuffer padding = new StringBuffer();
1063         final int s = size - string.length();
1064         if ( s < 1 ) {
1065             return new StringBuffer( string.substring( 0, size ) );
1066         }
1067         for( int i = 0; i < s; ++i ) {
1068             padding.append( pad );
1069         }
1070         if ( left_pad ) {
1071             return padding.append( string );
1072         }
1073         else {
1074             return string.append( padding );
1075         }
1076     }
1077
1078     final public static double parseDouble( final String str ) throws ParseException {
1079         if ( ForesterUtil.isEmpty( str ) ) {
1080             return 0.0;
1081         }
1082         return Double.parseDouble( str );
1083     }
1084
1085     final public static int parseInt( final String str ) throws ParseException {
1086         if ( ForesterUtil.isEmpty( str ) ) {
1087             return 0;
1088         }
1089         return Integer.parseInt( str );
1090     }
1091
1092     final public static void printArray( final Object[] a ) {
1093         for( int i = 0; i < a.length; ++i ) {
1094             System.out.println( "[" + i + "]=" + a[ i ] );
1095         }
1096     }
1097
1098     final public static void printCountingMap( final Map<String, Integer> counting_map ) {
1099         for( final String key : counting_map.keySet() ) {
1100             System.out.println( key + ": " + counting_map.get( key ) );
1101         }
1102     }
1103
1104     final public static void printErrorMessage( final String prg_name, final String message ) {
1105         System.err.println( "[" + prg_name + "] > error: " + message );
1106     }
1107
1108     final public static void printProgramInformation( final String prg_name,
1109                                                       final String prg_version,
1110                                                       final String date ) {
1111         final int l = prg_name.length() + prg_version.length() + date.length() + 4;
1112         System.out.println();
1113         System.out.println( prg_name + " " + prg_version + " (" + date + ")" );
1114         for( int i = 0; i < l; ++i ) {
1115             System.out.print( "_" );
1116         }
1117         System.out.println();
1118     }
1119
1120     final public static void printProgramInformation( final String prg_name,
1121                                                       final String prg_version,
1122                                                       final String date,
1123                                                       final String email,
1124                                                       final String www ) {
1125         printProgramInformation( prg_name, null, prg_version, date, email, www, null );
1126     }
1127
1128     final public static void printProgramInformation( final String prg_name,
1129                                                       final String desc,
1130                                                       final String prg_version,
1131                                                       final String date,
1132                                                       final String email,
1133                                                       final String www,
1134                                                       final String based_on ) {
1135         String my_prg_name = new String( prg_name );
1136         if ( !ForesterUtil.isEmpty( desc ) ) {
1137             my_prg_name += ( " - " + desc );
1138         }
1139         final int l = my_prg_name.length() + prg_version.length() + date.length() + 4;
1140         System.out.println();
1141         System.out.println( my_prg_name + " " + prg_version + " (" + date + ")" );
1142         for( int i = 0; i < l; ++i ) {
1143             System.out.print( "_" );
1144         }
1145         System.out.println();
1146         System.out.println();
1147         System.out.println( "WWW     : " + www );
1148         System.out.println( "Contact : " + email );
1149         if ( !ForesterUtil.isEmpty( based_on ) ) {
1150             System.out.println( "Based on: " + based_on );
1151         }
1152         if ( !ForesterUtil.isEmpty( ForesterUtil.JAVA_VERSION ) && !ForesterUtil.isEmpty( ForesterUtil.JAVA_VENDOR ) ) {
1153             System.out.println();
1154             System.out
1155                     .println( "[running on Java " + ForesterUtil.JAVA_VERSION + " " + ForesterUtil.JAVA_VENDOR + "]" );
1156         }
1157         System.out.println();
1158     }
1159
1160     final public static void printWarningMessage( final String prg_name, final String message ) {
1161         System.out.println( "[" + prg_name + "] > warning: " + message );
1162     }
1163
1164     final public static void programMessage( final String prg_name, final String message ) {
1165         System.out.println( "[" + prg_name + "] > " + message );
1166     }
1167
1168     public static List<String> readUrl( final String url_str ) throws IOException {
1169         final URL url = new URL( url_str );
1170         final URLConnection urlc = url.openConnection();
1171         //urlc.setRequestProperty( "User-Agent", "" );
1172         final BufferedReader in = new BufferedReader( new InputStreamReader( urlc.getInputStream() ) );
1173         String line;
1174         final List<String> result = new ArrayList<String>();
1175         while ( ( line = in.readLine() ) != null ) {
1176             result.add( line );
1177         }
1178         in.close();
1179         return result;
1180     }
1181
1182     /**
1183      *
1184      * Example regarding engulfment: ------------0.1 ----------0.2 --0.3 =>
1185      * domain with 0.3 is ignored
1186      *
1187      * -----------0.1 ----------0.2 --0.3 => domain with 0.3 is ignored
1188      *
1189      *
1190      * ------------0.1 ----------0.3 --0.2 => domains with 0.3 and 0.2 are _not_
1191      * ignored
1192      *
1193      * @param max_allowed_overlap
1194      *            maximal allowed overlap (inclusive) to be still considered not
1195      *            overlapping (zero or negative value to allow any overlap)
1196      * @param remove_engulfed_domains
1197      *            to remove domains which are completely engulfed by coverage of
1198      *            domains with better support
1199      * @param protein
1200      * @return
1201      */
1202     public static Protein removeOverlappingDomains( final int max_allowed_overlap,
1203                                                     final boolean remove_engulfed_domains,
1204                                                     final Protein protein ) {
1205         final Protein pruned_protein = new BasicProtein( protein.getProteinId().getId(),
1206                                                          protein.getSpecies().getSpeciesId(),
1207                                                          protein.getLength() );
1208         final List<Domain> sorted = SurfacingUtil.sortDomainsWithAscendingConfidenceValues( protein );
1209         final List<Boolean> covered_positions = new ArrayList<Boolean>();
1210         for( final Domain domain : sorted ) {
1211             if ( ( ( max_allowed_overlap < 0 )
1212                     || ( ForesterUtil.calculateOverlap( domain, covered_positions ) <= max_allowed_overlap ) )
1213                     && ( !remove_engulfed_domains || !isEngulfed( domain, covered_positions ) ) ) {
1214                 final int covered_positions_size = covered_positions.size();
1215                 for( int i = covered_positions_size; i < domain.getFrom(); ++i ) {
1216                     covered_positions.add( false );
1217                 }
1218                 final int new_covered_positions_size = covered_positions.size();
1219                 for( int i = domain.getFrom(); i <= domain.getTo(); ++i ) {
1220                     if ( i < new_covered_positions_size ) {
1221                         covered_positions.set( i, true );
1222                     }
1223                     else {
1224                         covered_positions.add( true );
1225                     }
1226                 }
1227                 pruned_protein.addProteinDomain( domain );
1228             }
1229         }
1230         return pruned_protein;
1231     }
1232
1233     final public static String removeSuffix( final String file_name ) {
1234         final int i = file_name.lastIndexOf( '.' );
1235         if ( i > 1 ) {
1236             return file_name.substring( 0, i );
1237         }
1238         return file_name;
1239     }
1240
1241     /**
1242      * Removes all white space from String s.
1243      *
1244      * @return String s with white space removed
1245      */
1246     final public static String removeWhiteSpace( String s ) {
1247         int i;
1248         for( i = 0; i <= ( s.length() - 1 ); i++ ) {
1249             if ( ( s.charAt( i ) == ' ' ) || ( s.charAt( i ) == '\t' ) || ( s.charAt( i ) == '\n' )
1250                     || ( s.charAt( i ) == '\r' ) ) {
1251                 s = s.substring( 0, i ) + s.substring( i + 1 );
1252                 i--;
1253             }
1254         }
1255         return s;
1256     }
1257
1258     final public static String replaceIllegalNhxCharacters( final String nhx ) {
1259         if ( nhx == null ) {
1260             return "";
1261         }
1262         return nhx.trim().replaceAll( "[\\[\\]']+", "_" );
1263     }
1264
1265     final public static double round( final double value, final int decimal_place ) {
1266         BigDecimal bd = new BigDecimal( value );
1267         bd = bd.setScale( decimal_place, BigDecimal.ROUND_HALF_UP );
1268         return bd.doubleValue();
1269     }
1270
1271     /**
1272      * Rounds d to an int.
1273      */
1274     final public static int roundToInt( final double d ) {
1275         return ( int ) ( d + 0.5 );
1276     }
1277
1278     final public static int roundToInt( final float f ) {
1279         return ( int ) ( f + 0.5f );
1280     }
1281
1282     final public static short roundToShort( final double d ) {
1283         return ( short ) ( d + 0.5 );
1284     }
1285
1286     final public static String sanitizeString( final String s ) {
1287         if ( s == null ) {
1288             return "";
1289         }
1290         else {
1291             return s.trim();
1292         }
1293     }
1294
1295     public final static StringBuilder santitizeStringForNH( String data ) {
1296         data = data.replaceAll( "\\s+", " " ).trim();
1297         final StringBuilder sb = new StringBuilder();
1298         if ( data.length() > 0 ) {
1299             final boolean single_pars = data.indexOf( '\'' ) > -1;
1300             final boolean double_pars = data.indexOf( '"' ) > -1;
1301             if ( single_pars && double_pars ) {
1302                 data = data.replace( '\'', '`' );
1303                 sb.append( '\'' );
1304                 sb.append( data );
1305                 sb.append( '\'' );
1306             }
1307             else if ( single_pars ) {
1308                 sb.append( '"' );
1309                 sb.append( data );
1310                 sb.append( '"' );
1311             }
1312             else if ( PARANTHESESABLE_NH_CHARS_PATTERN.matcher( data ).find() ) {
1313                 sb.append( '\'' );
1314                 sb.append( data );
1315                 sb.append( '\'' );
1316             }
1317             else {
1318                 sb.append( data );
1319             }
1320         }
1321         return sb;
1322     }
1323
1324     public static boolean seqIsLikelyToBeAa( final String s ) {
1325         final String seq = s.toLowerCase();
1326         if ( ( seq.indexOf( 'r' ) > -1 ) || ( seq.indexOf( 'd' ) > -1 ) || ( seq.indexOf( 'e' ) > -1 )
1327                 || ( seq.indexOf( 'q' ) > -1 ) || ( seq.indexOf( 'h' ) > -1 ) || ( seq.indexOf( 'k' ) > -1 )
1328                 || ( seq.indexOf( 'w' ) > -1 ) || ( seq.indexOf( 's' ) > -1 ) || ( seq.indexOf( 'm' ) > -1 )
1329                 || ( seq.indexOf( 'p' ) > -1 ) || ( seq.indexOf( 'v' ) > -1 ) ) {
1330             return true;
1331         }
1332         return false;
1333     }
1334
1335     final private static String[] splitString( final String str ) {
1336         final String regex = "[\\s;,]+";
1337         return str.split( regex );
1338     }
1339
1340     final public static String stringArrayToString( final String[] a ) {
1341         return stringArrayToString( a, ", " );
1342     }
1343
1344     final public static String stringArrayToString( final String[] a, final String separator ) {
1345         final StringBuilder sb = new StringBuilder();
1346         if ( ( a != null ) && ( a.length > 0 ) ) {
1347             for( int i = 0; i < ( a.length - 1 ); ++i ) {
1348                 sb.append( a[ i ] + separator );
1349             }
1350             sb.append( a[ a.length - 1 ] );
1351         }
1352         return sb.toString();
1353     }
1354
1355     final public static String[] stringListToArray( final List<String> list ) {
1356         if ( list != null ) {
1357             final String[] str = new String[ list.size() ];
1358             int i = 0;
1359             for( final String l : list ) {
1360                 str[ i++ ] = l;
1361             }
1362             return str;
1363         }
1364         return null;
1365     }
1366
1367     final public static String stringListToString( final List<String> l, final String separator ) {
1368         final StringBuilder sb = new StringBuilder();
1369         if ( ( l != null ) && ( l.size() > 0 ) ) {
1370             for( int i = 0; i < ( l.size() - 1 ); ++i ) {
1371                 sb.append( l.get( i ) + separator );
1372             }
1373             sb.append( l.get( l.size() - 1 ) );
1374         }
1375         return sb.toString();
1376     }
1377
1378     final public static String[] stringSetToArray( final Set<String> strings ) {
1379         final String[] str_array = new String[ strings.size() ];
1380         int i = 0;
1381         for( final String e : strings ) {
1382             str_array[ i++ ] = e;
1383         }
1384         return str_array;
1385     }
1386
1387     final public static void unexpectedFatalError( final Error e ) {
1388         System.err.println();
1389         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
1390         e.printStackTrace( System.err );
1391         System.err.println();
1392         System.exit( -1 );
1393     }
1394
1395     final public static void unexpectedFatalError( final Exception e ) {
1396         System.err.println();
1397         System.err.println( "unexpected exception: should not have occured! Please contact program author(s)." );
1398         e.printStackTrace( System.err );
1399         System.err.println();
1400         System.exit( -1 );
1401     }
1402
1403     final public static void unexpectedFatalError( final String message ) {
1404         System.err.println();
1405         System.err.println( "unexpected error: should not have occured! Please contact program author(s)." );
1406         System.err.println( message );
1407         System.err.println();
1408         System.exit( -1 );
1409     }
1410
1411     final public static void unexpectedFatalError( final String prg_name, final Exception e ) {
1412         System.err.println();
1413         System.err.println( "[" + prg_name
1414                 + "] > unexpected error; should not have occured! Please contact program author(s)." );
1415         e.printStackTrace( System.err );
1416         System.err.println();
1417         System.exit( -1 );
1418     }
1419
1420     final public static void unexpectedFatalError( final String prg_name, final String message ) {
1421         System.err.println();
1422         System.err.println( "[" + prg_name
1423                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1424         System.err.println( message );
1425         System.err.println();
1426         System.exit( -1 );
1427     }
1428
1429     final public static void unexpectedFatalError( final String prg_name, final String message, final Exception e ) {
1430         System.err.println();
1431         System.err.println( "[" + prg_name
1432                 + "] > unexpected error: should not have occured! Please contact program author(s)." );
1433         System.err.println( message );
1434         e.printStackTrace( System.err );
1435         System.err.println();
1436         System.exit( -1 );
1437     }
1438
1439     public final static void updateProgress( final double progress_percentage ) {
1440         final int width = 50;
1441         System.out.print( "\r[" );
1442         int i = 0;
1443         for( ; i <= ForesterUtil.roundToInt( progress_percentage * width ); i++ ) {
1444             System.out.print( "." );
1445         }
1446         for( ; i < width; i++ ) {
1447             System.out.print( " " );
1448         }
1449         System.out.print( "]" );
1450     }
1451
1452     public final static void updateProgress( final int i, final DecimalFormat f ) {
1453         System.out.print( "\r[" + f.format( i ) + "]" );
1454     }
1455
1456     public final static String wordWrap( final String str, final int width ) {
1457         final StringBuilder sb = new StringBuilder( str );
1458         int start = 0;
1459         int ls = -1;
1460         int i = 0;
1461         while ( i < sb.length() ) {
1462             if ( sb.charAt( i ) == ' ' ) {
1463                 ls = i;
1464             }
1465             if ( sb.charAt( i ) == '\n' ) {
1466                 ls = -1;
1467                 start = i + 1;
1468             }
1469             if ( i > ( ( start + width ) - 1 ) ) {
1470                 if ( ls != -1 ) {
1471                     sb.setCharAt( ls, '\n' );
1472                     start = ls + 1;
1473                     ls = -1;
1474                 }
1475                 else {
1476                     sb.insert( i, '\n' );
1477                     start = i + 1;
1478                 }
1479             }
1480             i++;
1481         }
1482         return sb.toString();
1483     }
1484
1485     public final static Phylogeny[] readPhylogeniesFromUrl( final URL url, final PhylogenyParser parser )
1486             throws NoSuchAlgorithmException, IOException, KeyManagementException {
1487         if ( url == null ) {
1488             throw new IllegalArgumentException( "URL to read from must not be null" );
1489         }
1490         else if ( parser == null ) {
1491             throw new IllegalArgumentException( "parser to use to read from URL must not be null" );
1492         }
1493         final URLConnection con;
1494         if ( url.toString().startsWith( "https:" ) ) {
1495             con = TrustManager.makeHttpsURLConnection( url );
1496         }
1497         else if ( url.toString().startsWith( "http:" ) ) {
1498             con = url.openConnection();
1499         }
1500         else {
1501             throw new IllegalArgumentException( "Cannot deal with URL: " + url );
1502         }
1503         if ( con == null ) {
1504             throw new IOException( "could not create connection from " + url );
1505         }
1506         con.setDefaultUseCaches( false );
1507         final InputStream is = con.getInputStream();
1508         if ( is == null ) {
1509             throw new IOException( "could not create input stream from " + url );
1510         }
1511         final Phylogeny[] trees = ParserBasedPhylogenyFactory.getInstance().create( is, parser );
1512         try {
1513             is.close();
1514         }
1515         catch ( final Exception e ) {
1516             // ignore  
1517         }
1518         return trees;
1519     }
1520
1521     public final static File getMatchingFile( final File dir, final String prefix, final String suffix )
1522             throws IOException {
1523         if ( !dir.exists() ) {
1524             throw new IOException( "[" + dir + "] does not exist" );
1525         }
1526         if ( !dir.isDirectory() ) {
1527             throw new IOException( "[" + dir + "] is not a directory" );
1528         }
1529         if ( dir.listFiles().length == 0 ) {
1530             throw new IOException( "[" + dir + "] is empty" );
1531         }
1532         final File files[] = dir.listFiles( new FilenameFilter() {
1533
1534             @Override
1535             public boolean accept( final File dir, final String name ) {
1536                 return ( name.endsWith( suffix ) );
1537             }
1538         } );
1539         if ( files.length == 0 ) {
1540             throw new IOException( "no files ending with \"" + suffix + "\" found in [" + dir + "]" );
1541         }
1542         String my_prefix = prefix;
1543         boolean done = false;
1544         boolean more_than_one = false;
1545         File the_one = null;
1546         do {
1547             int matches = 0;
1548             for( File file : files ) {
1549                 if ( file.getName().startsWith( my_prefix ) ) {
1550                     matches++;
1551                     if ( matches > 1 ) {
1552                         the_one = null;
1553                         break;
1554                     }
1555                     the_one = file;
1556                 }
1557             }
1558             if ( matches > 1 ) {
1559                 more_than_one = true;
1560                 done = true;
1561             }
1562             if ( matches == 1 ) {
1563                 done = true;
1564             }
1565             else {
1566                 if ( my_prefix.length() <= 1 ) {
1567                     throw new IOException( "no file matching \"" + removeFileExtension( prefix )
1568                             + "\" and ending with \"" + suffix + "\" found in [" + dir + "]" );
1569                 }
1570                 my_prefix = my_prefix.substring( 0, my_prefix.length() - 1 );
1571             }
1572         } while ( !done );
1573         if ( more_than_one ) {
1574             throw new IOException( "multiple files matching \"" + removeFileExtension( prefix )
1575                     + "\" and ending with \"" + suffix + "\" found in [" + dir + "]" );
1576         }
1577         else if ( the_one != null ) {
1578         }
1579         else {
1580             throw new IOException( "no file matching \"" + removeFileExtension( prefix ) + "\" and ending with \""
1581                     + suffix + "\" found in [" + dir + "]" );
1582         }
1583         return the_one;
1584     }
1585
1586     public final static String greatestCommonPrefix( final String a, final String b ) {
1587         final int min_length = Math.min( a.length(), b.length() );
1588         for( int i = 0; i < min_length; ++i ) {
1589             if ( a.charAt( i ) != b.charAt( i ) ) {
1590                 return a.substring( 0, i );
1591             }
1592         }
1593         return a.substring( 0, min_length );
1594     }
1595
1596     public final static String greatestCommonPrefix( final String a, final String b, final String separator ) {
1597         if ( ForesterUtil.isEmpty( separator ) ) {
1598             throw new IllegalArgumentException( "separator must not be null or empty" );
1599         }
1600         final String[] as = a.split( Pattern.quote( separator ) );
1601         final String[] bs = b.split( Pattern.quote( separator ) );
1602         final int min_length = Math.min( as.length, bs.length );
1603         for( int i = 0; i < min_length; ++i ) {
1604             if ( !( as[ i ].equals( bs[ i ] ) ) ) {
1605                 StringBuilder sb = new StringBuilder();
1606                 boolean first = true;
1607                 for( int j = 0; j < i; ++j ) {
1608                     if ( first ) {
1609                         first = false;
1610                     }
1611                     else {
1612                         sb.append( separator );
1613                     }
1614                     sb.append( as[ j ] );
1615                 }
1616                 return sb.toString();
1617             }
1618         }
1619         StringBuilder sb = new StringBuilder();
1620         boolean first = true;
1621         for( int j = 0; j < min_length; ++j ) {
1622             if ( first ) {
1623                 first = false;
1624             }
1625             else {
1626                 sb.append( separator );
1627             }
1628             sb.append( as[ j ] );
1629         }
1630         return sb.toString();
1631     }
1632
1633     public final static String greatestCommonPrefix( final List<String> strings ) {
1634         if ( strings == null ) {
1635             throw new IllegalArgumentException( "list of strings is null" );
1636         }
1637         if ( strings.isEmpty() ) {
1638             throw new IllegalArgumentException( "list of strings is empty" );
1639         }
1640         String common = strings.get( 0 );
1641         for( int i = 1; i < strings.size(); ++i ) {
1642             common = greatestCommonPrefix( common, strings.get( i ) );
1643         }
1644         return common;
1645     }
1646
1647     public final static String greatestCommonPrefix( final List<String> strings, final String separator ) {
1648         if ( ForesterUtil.isEmpty( separator ) ) {
1649             return greatestCommonPrefix( strings );
1650         }
1651         if ( strings == null ) {
1652             throw new IllegalArgumentException( "list of strings is null" );
1653         }
1654         if ( strings.isEmpty() ) {
1655             throw new IllegalArgumentException( "list of strings is empty" );
1656         }
1657         String common = strings.get( 0 );
1658         for( int i = 1; i < strings.size(); ++i ) {
1659             common = greatestCommonPrefix( common, strings.get( i ), separator );
1660         }
1661         return common;
1662     }
1663
1664     private ForesterUtil() {
1665     }
1666
1667     public static List<String> spliIntoPrefixes( final String prefix, final String separator ) {
1668         final String[] a = prefix.split( Pattern.quote( separator ) );
1669         final List<String> l = new ArrayList<String>();
1670         for( int i = 0; i < a.length; ++i ) {
1671             final StringBuilder sb = new StringBuilder();
1672             for( int j = 0; j <= i; ++j ) {
1673                 sb.append( a[ j ] );
1674                 if ( j < i ) {
1675                     sb.append( separator );
1676                 }
1677             }
1678             //  System.out.println( sb.toString() );
1679             l.add( sb.toString() );
1680         }
1681         return l;
1682     }
1683
1684     //
1685     public static boolean isLooksLikeFasta( final File file ) throws IOException {
1686         final String first_line = ForesterUtil.getFirstLine( file ).trim().toLowerCase();
1687         return ( ( !isEmptyTrimmed( first_line ) && first_line.trim().startsWith( ">" ) ) );
1688     }
1689 }