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