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