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