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